Thumbhash crashes swift reference implementation

Describe the issue:

Some thumbhashes generated by datocms cause both the expo-image and reference (github.com/evanw/thumbhash) Swift decoder to crash. It also appears to fail to render an image on java/android implementation. The web implementation is ok, due to a quirk of the JS language.

Can you provide a link to the item, model, or project in question?

The hash that breaks is CwgGH4Z3q3cgd2SkW3mHqVh3R8YJZYs= generated from https://www.datocms-assets.com/107161/1699353334-adults-manage-emotions.png

Do you have any sample code you can provide?

Run this fork of the reference example iOS project here: https://github.com/Royce/thumbhash/tree/main/examples/ios/Example.xcodeproj – I have hard coded the problematic thumbhash if you want to see it crash.

This is the line that crashes: swift/ThumbHash.swift#L287

  let decodeChannel = { (nx: Int, ny: Int, scale: Float32) -> [Float32] in
    var ac: [Float32] = []
    for cy in 0 ..< ny {
      var cx = cy > 0 ? 0 : 1
      while cx * ny < nx * (ny - cy) {
>>>     let iac = (hash[ac_start + (ac_index >> 1)] >> ((ac_index & 1) << 2)) & 15;
        var fac = Float32(iac)
        fac = (fac / 7.5 - 1) * scale
        ac.append(fac)
        ac_index += 1
        cx += 1
      }
    }
    return ac
  }

Specifically, hash[ac_start + (ac_index >> 1)] is hash[23] is an out of bounds error.

The javascript implementation is ok, but only because javascript is weird

In the javascript implementation (js/thumbhash.js#L128) the code hash[ac_start + (ac_index >> 1)] is undefined and (hash[ac_start + (ac_index >> 1)] >> ((ac_index++ & 1) << 2) is undefined >> 4 is 0 >> 4 – so the missing data from hash is treated as 0

  let decodeChannel = (nx, ny, scale) => {
    let ac = []
    for (let cy = 0; cy < ny; cy++)
      for (let cx = cy ? 0 : 1; cx * ny < nx * (ny - cy); cx++)
        ac.push((((hash[ac_start + (ac_index >> 1)] >> ((ac_index++ & 1) << 2)) & 15) / 7.5 - 1) * scale)
    return ac
  }

Workaround and possible solution

The problem hash is:
CwgGH4Z3q3cgd2SkW3mHqVh3R8YJZYs= β†’ 0b 08 06 1f 86 77 ab 77 20 77 64 a4 5b 79 87 a9 58 77 47 c6 09 65 8b

Changing this to the following avoids the issue:
CwgGH4Z3q3cgd2SkW3mHqVh3R8YJZYsA β†’ 0b 08 06 1f 86 77 ab 77 20 77 64 a4 5b 79 87 a9 58 77 47 c6 09 65 8b 00 < note the extra 00

It’s worth noting that if I take this image (/107161/1699353334-adults-manage-emotions.png) and generate a thumbhash using the demo website (evanw.github.io/thumbhash) I get the following very similar hash that explicitly also encodes the final 00.

CwgGH4Z3qncgd2SkW3mHqVh3R8YJZYsA => 0B 08 06 1F 86 77 AA 77 20 77 64 A4 5B 79 87 A9 58 77 47 C6 09 65 8B 00

2 Likes

Hi @royce,

Welcome to the Dato forums and thank you very much for this detailed report! Your analysis is very helpful :slight_smile:

I will report it to the devs immediately and let you know once we have a resolution.

Thank you!

Thank you, @royce! We have just released an update to resolve this bug. In your project, there were only two incorrect thumbhashes, and we have fixed them.

/107161/1698281279-clection-manage-emotions.png
/107161/1699353334-adults-manage-emotions.png

2 Likes