sRGB ≠ 256
June 4, 2020 3:48 PM   Subscribe

How this wallpaper kills your (Android) phone SLYT
One number in one pixel is enough to send your phone into this spiral of doom.

TLDW
When converting the Pro Photo color space to the sRGB color space Google's default color engine rounds 54.213, 182.376, 17.5446 to 55, 183, 18 which adds up to 256, outside the 255 limit.
posted by zinon (61 comments total) 11 users marked this as a favorite
 
I had heard something about a wallpaper crashing phones but I thought it had some malicious code embedded in it. Kind of neat that it is just a number being rounded up.

Does this kill the phone for good, are you able to reboot in some kind of "safe mode" to fix things, or do you have to do a factory reset?
posted by any portmanteau in a storm at 4:07 PM on June 4, 2020


When converting the Pro Photo color space to the sRGB color space Google's default color engine rounds 54.213, 182.376, 17.5446 to 55, 183, 18 which adds up to 256, outside the 255 limit.

Wow. Bounds error and off by one errors combine to one super fuckup.
posted by Your Childhood Pet Rock at 4:20 PM on June 4, 2020 [7 favorites]


Why would they store an 8-bit color value in anything larger than a byte? Adding two bytes/chars in C does an implicit truncation (if there is overflow), so at worst you should just get back some other color in the RGB space. Is this a Java bug?
posted by They sucked his brains out! at 4:22 PM on June 4, 2020 [2 favorites]


I believe modern CPUs work most efficiently at machine word size (32- or 64-bit), to the point that working with 8-bit numbers is slower than storing them in machine words and then dealing with the excess bits when packing them into their ultimate destination. Presumably it's this final stage where, rather than sensibly clamping the number into the 0...255 range, it throws an exception if it's out of range.
posted by acb at 4:29 PM on June 4, 2020 [3 favorites]


Presumably it's this final stage where, rather than sensibly clamping the number into the 0...255 range, it throws an exception if it's out of range.

Yep. The crash is an out of bounds error because it's accessing the 257th element in a 256 element array (arrays start at 0 dammit) putting together the histogram.
posted by Your Childhood Pet Rock at 4:32 PM on June 4, 2020 [3 favorites]




Metafilter: arrays start at 0 dammit
posted by Greg_Ace at 4:36 PM on June 4, 2020 [26 favorites]


Metafilter: arrays start at 0 dammit

I'm a weak agnostic but even I know that god intended it that way and I will die on this hill.
posted by Your Childhood Pet Rock at 4:37 PM on June 4, 2020 [32 favorites]


Not arguing, just acknowledging the sheer lexicological beauty and inherent humor of the phrase.
posted by Greg_Ace at 4:40 PM on June 4, 2020 [1 favorite]


Metafilter: just acknowledging the-- oh, forget it.
posted by Greg_Ace at 4:41 PM on June 4, 2020 [21 favorites]


dealing with the excess bits when packing them into their ultimate destination

Bit shifts throw away the bits that fall off the end (depending on endedness). Though it does sound like a bad type choice somewhere in Android, if they are using an array of 8-byte ints instead of just a byte (or union of them for color). Seems like a waste of memory.
posted by They sucked his brains out! at 4:43 PM on June 4, 2020


From the code Your Childhood Pet Rock linked it to looks like the error doesn't even occur when displaying the colour image, it's when calculating a grayscale version of the image for some fancy transition/deactivation effect. It amazes me how much people like to nerd out about colour-spaces and image quality and the like, as if anyone is going to notice or care about whether it's "proper grayscale" for some split second transition. So many bugs in my experience are like this, it's something completely superfluous that ends up bringing down the whole thing crashing down.
posted by L.P. Hatecraft at 4:45 PM on June 4, 2020 [14 favorites]


I'm curious how they identified that particular bit.
posted by Greg_Ace at 4:45 PM on June 4, 2020


it's when calculating a grayscale version of the image for some fancy transition/deactivation effect.

Running between color spaces usually involves a transition to XYZ at some point which usually means you need to calculate the luminance (Y being the luminance value) which is just the greyscale value of the pixel.
posted by Your Childhood Pet Rock at 4:51 PM on June 4, 2020 [4 favorites]


I was taught to round anything less than .5 down , not up. Is this common now or is it an Android thing?
posted by tommasz at 4:55 PM on June 4, 2020 [4 favorites]


Coulda been worse, but not dumber.
posted by j_curiouser at 5:40 PM on June 4, 2020


You can't do the 5 and up rule. 1.5 + 1.5 = 3 round(1.5) = 2, round(1.5) = 2. Therefore 1.5+1.5 = 4. The rule (in HS at least) was you have to keep track of how many times you've rounded the .5 up and balance it with the number of times you rounded the .5 down. round'(1.5) = 1, round'(1.5) = 2, 1.5+1.5 =3.
posted by zengargoyle at 5:52 PM on June 4, 2020 [4 favorites]


They should have just floor() instead of ceil() to avoid passing the edge of the space. (assuming (0,0,0) is in space)
posted by zengargoyle at 5:55 PM on June 4, 2020 [2 favorites]


The rule (in HS at least) was you have to keep track of how many times you've rounded the .5 up and balance it with the number of times you rounded the .5 down.

If you're going to devote an extra bit to improving the accuracy of your rounding, you'd be much better off just rounding things to the nearest half-integer.
posted by aws17576 at 6:12 PM on June 4, 2020 [5 favorites]


What Happens When Maths Goes Wrong? - with Matt Parker.

If you Google up 'matt parker humble pi' and check the videos, he's done several talks (all mostly a different selection of chapters) from his book Humble Pi: When Math Goes Wrong in the Real World, Parker, Matt - Amazon.com which is all about these sorts of errors. They are numerous and everywhere and can cause catastrophe (but Matt chooses his examples on non-life-loss examples).
posted by zengargoyle at 6:15 PM on June 4, 2020 [7 favorites]


And there goes my make mathsmonday a thing thing
posted by zengargoyle at 6:17 PM on June 4, 2020 [1 favorite]


And there goes my make mathsmonday a thing thing

...he summed up.
posted by Greg_Ace at 6:21 PM on June 4, 2020 [8 favorites]


They should have just floor() instead of ceil() to avoid passing the edge of the space. (assuming (0,0,0) is in space)

It wasn’t 0,0,0. It was accessing i[256] of an array that only went to i[255]. They needed ceil() as a bounds check.
posted by Your Childhood Pet Rock at 6:55 PM on June 4, 2020 [1 favorite]


I had heard something about a wallpaper crashing phones but I thought it had some malicious code embedded in it. Kind of neat that it is just a number being rounded up.

Much of what you would consider "some malicious code" starts off with some sort of out of bounds problem just like this one. The trick is start off with a system that just runs whatever is in memory outside of the data structure you mean to deal with, then you put your "bad stuff" in that "outside" place, and then you purposefully ask for and execute the non-existent element, which is really your "bad stuff".
posted by sideshow at 7:09 PM on June 4, 2020 [4 favorites]


It takes a human effort larger than that used to construct the pyramids to make a functional OS that doesn't crash all the time. But Skynet is taking over any day now in the popular media.
posted by benzenedream at 7:11 PM on June 4, 2020 [1 favorite]


Java has no unsigned byte type, which leads to using signed 16-bit values so you can store 0..255. But then your calculations can result in -32,768..32,767, and if you're using that to index into an array of 256 values you'd better be very careful.
posted by (parenthetic me) at 7:23 PM on June 4, 2020


The Terminator is going to go get Sarah Conner eventually, but right now he’s got to install these 4 updates.
posted by Huffy Puffy at 7:32 PM on June 4, 2020 [11 favorites]


Metafilter: arrays start at 0 dammit


“Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration.”

— Stan Kelly-Bootle

posted by suetanvil at 7:39 PM on June 4, 2020 [17 favorites]


Quite why we still use languages without robust runtime bounds-checking, I'll never know
posted by scruss at 7:45 PM on June 4, 2020 [2 favorites]


It is robust runtime bounds-checking. That's why it threw an IndexOutOfBoundsException and terminated the process because said exception was unhandled instead of silently using corrupt data.
posted by Your Childhood Pet Rock at 8:12 PM on June 4, 2020 [7 favorites]


Yes, the issue is more that they didn't bother to catch runtime exceptions, so it went out to the system to handle ungracefully (never really understood why the designers of Java thought it'd be a good idea to allow programmers to ignore runtime exceptions - if you're going to have them, make people think about them, even if they just catch them all and do nothing).
posted by clicking the 'Post Comment' button at 8:15 PM on June 4, 2020 [1 favorite]


never really understood why the designers of Java thought it'd be a good idea to allow programmers to ignore runtime exceptions - if you're going to have them, make people think about them, even if they just catch them all and do nothing

Because then programmers will stuff everything in a single try/catch block and Java will quietly do something with things in an unknown state, errors be damned. At least when it throws an exception and terminates the programmer can be made aware of it without having to have a contingency plan for every little thing.

It’s just terminating to the system didn’t really work in this case because the system is locked up tighter than a fish’s asshole.
posted by Your Childhood Pet Rock at 8:22 PM on June 4, 2020 [1 favorite]


“Either this wallpaper goes, or I do.”
posted by Segundus at 8:26 PM on June 4, 2020 [40 favorites]


Java has no unsigned byte type

Ah, language failure meets design failure.
posted by They sucked his brains out! at 8:54 PM on June 4, 2020 [3 favorites]


Can't believe I'm the first to come here and say:

1 + 1 = 3, for large values of 1.
posted by neuron at 9:39 PM on June 4, 2020 [6 favorites]


I spent part of my day learning new programming things about something I'm supposedly an expert at which was causing problems and making me look like an ass, so I guess I should make this photo wallpaper on my phone so I can lose all my puppy photos as punishment.

Also, when the video showed there was something called "Adobe RGB Space" I thought "aha". Imagine my surprise it wasn't the cause of the problem--that must be a first for the geniuses at Adobe, programming masters whose lovely Creative Cloud launches about 20 processes which eat a consistent 1 - 2% of your CPU, all day, every day...
posted by maxwelton at 10:47 PM on June 4, 2020 [1 favorite]


L.P. Hatecraft: It amazes me how much people like to nerd out about colour-spaces and image quality and the like, as if anyone is going to notice or care about whether it's "proper grayscale" for some split second transition.

Oh god. Our company is in the middle of prepping for a kids cartoon in Rec. 2020 (but which gamma will we use for that gamut? you ask, and how many nits should the review monitors use?), and I routinely find myself coughing into my sleeve [cough]thekidsdon'tcare[/cough].
posted by clawsoon at 11:37 PM on June 4, 2020 [3 favorites]


“Either this wallpaper goes, or I do.”

I have to say, I'm frankly in awe of this comment/reference.
posted by Ivan Fyodorovich at 12:00 AM on June 5, 2020 [8 favorites]


I'm skeptical of the idea that it's just the RGB value of [255, 255, 243] that causes this problem. There are a LOT of pixels in a LOT of images out there, and you're telling me there are NONE with that color value that anyone has ever tried to set as their phone wallpaper?
posted by The Tensor at 12:19 AM on June 5, 2020 [2 favorites]


I used to build color space converters in silicon ... handling the back end of MPEG decoding - these sorts of out-of-gamut artifacts coming out of MPEG decoders were quite common - I once spent a frustrating 3 months attempting to build stuff to render a short clip of a woman dancing in a sparkly silvery dress - that dress had enough high frequency information that it compressed poorly and produced lots of these crazy color-space artifacts
posted by mbo at 5:46 AM on June 5, 2020 [2 favorites]


I'm skeptical of the idea that it's just the RGB value of [255, 255, 243] that causes this problem. There are a LOT of pixels in a LOT of images out there, and you're telling me there are NONE with that color value that anyone has ever tried to set as their phone wallpaper?

Without access to the source code, but I share your skepticism. I suspect there's some clever algorithm the google library uses that optimizes the color conversion, and there's an edge case triggered by this picture. It's still a "simple" off-by-one error, but as I said before on this site, there are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
posted by DreamerFi at 6:06 AM on June 5, 2020 [7 favorites]


I'm skeptical of the idea that it's just the RGB value of [255, 255, 243] that causes this problem. There are a LOT of pixels in a LOT of images out there, and you're telling me there are NONE with that color value that anyone has ever tried to set as their phone wallpaper?

It's not the RGB value that's the problem. It's the RGB value when going through a color space conversion. When you convert an image to another color space in most cases you first normalize the image to the XYZ color space which involves computing the luminance of each pixel. If the sRGB display is displaying an sRGB piece of imagery (which will happen 99% of the time) then it doesn't go through color conversion and doesn't hit the bug. Maybe gamma correction and that's it.

The bug is because that RGB value in particular trips up the luminance conversion function which then returns an invalid value for an array access. So the edge case is that it requires both the RGB value and also for the image to go through color conversion which immediately cuts down the bug's chance of happening to almost nil. Then you also have to do it as the background to brick the phone because a required process to keep the system running (i.e. the shell) will terminate with an IndexOutOfBoundsException.

Voila. Bricked phone.

I suspect there's some clever algorithm the google library uses that optimizes the color conversion, and there's an edge case triggered by this picture.

No. It's literally dumb rounding in a matrix function.
This is due to the fact, that the internal matrix calculation always
rounds up, resulting in maximum values of
- r: 255 * 0.2126 = 54.213 => 55
- g: 255 * 0.7152 = 182.376 => 183
- b: 255 * 0.0722 = 18.411 => 19
=> r + b + g = 257
The fix was to calculate each of the color values with their matching luminance components then add them.
posted by Your Childhood Pet Rock at 6:22 AM on June 5, 2020 [2 favorites]


there are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.

Well played.
posted by scrump at 6:25 AM on June 5, 2020 [4 favorites]


I wanna know which pixel it is.
posted by FirstMateKate at 8:30 AM on June 5, 2020 [1 favorite]


Does this kill the phone for good, are you able to reboot in some kind of "safe mode" to fix things, or do you have to do a factory reset?

"....I applied it to my Galaxy S20 Ultra. Big mistake. [clip of people laughing] Gone. Finito. Galaxy S20 Ultra, in one fell swoop, nuked. I couldn't get past my lock screen, and even Safe Mode wouldn't let me recover it. All data on that phone that I didn't back up, is gone."
posted by solotoro at 8:47 AM on June 5, 2020 [2 favorites]


i kinda love RGB values as a sneaky way of transmitting information. I was taught last year in my intro to CS class how to embed encrypted messages into images and it was super neat. Apparently Russian intel ops was actually doing that in 4chan img posts.
posted by lazaruslong at 9:26 AM on June 5, 2020 [1 favorite]


steganography! that's what it was called.
posted by lazaruslong at 9:27 AM on June 5, 2020 [4 favorites]


All this colour space talk is way outside my wheelhouse. I regularly use pictures I've taken as wallpaper on my Android device. Images are edited with XnView and/or MS Photos and uploaded via USB. Is this something that a) can effect my phone/images and b) even vaguely likely if technically possible?
posted by Mitheral at 9:29 AM on June 5, 2020


I regularly use pictures I've taken as wallpaper on my Android device. Images are edited with XnView and/or MS Photos and uploaded via USB. Is this something that a) can effect my phone/images and b) even vaguely likely if technically possible?

Most probably not. Most Android phones are set to sRGB by default and that's probably what your editor is going to be saving the photos in. You won't hit the conversion routines that get triggered by it.
posted by Your Childhood Pet Rock at 9:59 AM on June 5, 2020 [1 favorite]


As someone who just recently started tinkering with palette generating code from one or more colors, intended to calculate all the correct relative luminosities of background vs text as well as figure out the usable contrast and highlight values... ummm, homerdisappearsintothebushes.gif? Really interesting post, though, thanks!
posted by Godspeed.You!Black.Emperor.Penguin at 11:34 AM on June 5, 2020


I'm kinda curious if a consumer has any recourse whatsoever when their $1,000 rectangle suddenly dies via an action which, by all accounts, is supported. Because this is hellworld, I'm guessing not.
posted by maxwelton at 11:35 AM on June 5, 2020 [1 favorite]


OK, so if it's really rounding up every time (WHY?!??), then this overflow should be happening for any pixel values in the ranges:

250-253, 255, 250-255
254, 254, 250-255
254, 255, 237-255
255, 254, 250-255
255, 255, 236-255

That's 76 distinct combinations of R, G, B (all of which are close to white, BTW, rather than the pinkish color shown for that pixel in the video). So why isn't it happening all the time?
posted by The Tensor at 12:26 PM on June 5, 2020 [1 favorite]


suetanvil, thanks for referencing Stan Kelly-Bootle.
posted by lhauser at 7:44 PM on June 5, 2020


I have discovered a truly remarkable explanation of this issue which this post is too small to contain.

My initial gloss is:
When converting the Pro Photo color space to the sRGB color space Google's default color engine

It's a specific bug that comes into play only when the initial image is is 'Pro Photo' format that comes into play when converting to 'sRGB' for display on the device.

You would not hit this bug in the (Oh, we can convert Pro Photo into JPG/PNG/sRGB etc.) if your images were not Pro Photo format in the first place and neeced converting. It seems at my first glance to be a specific problem that can occur when displaying Pro Photo (what the hell even is that) format images and that little bit of code to handle Pro Photo image conversion to a displayable thing is the bit that goes BOOM!

The rest won't fit in the margin.
posted by zengargoyle at 8:01 PM on June 5, 2020 [2 favorites]


Remember that the color space used for jpeg (and mpeg) is YUV, the Y and the UV are compressed separately - in different versions of YUV Y is variously 0-255 or 16-255. There a bunch of possible YUV values that don't map to valid RGB values - they cause the math to wrap around - since the compression/decompression process which is essentially:

RGB->YUV->compression->decompression->YUV->RGB

loses some information at every step that final step can push values that are >255 or < 0, good decoders have to handle all these issues.

BTW - one of the problems with using YUV is that the Y is gamma corrected - it has far more dynamic range for bright (saturated) colors - that means that there are not many possible values that encode dark colors so lots of quantization error occurs for them (and after compression even more is lost). It's changed the way that people have produced movies - check out the original Blade Runner on DVD (MPEG2) those dark, noiry scenes with smoke drifting they pixelate horribly because of this - since then movie people (who depended on DVD sales) have (mostly) stopped making movies that don't do well on digital video.

This is akin to why people stopped wearing stripes/checks/houndstooth jackets when they went out of fashion because people on color TV couldn't wear them because of limitations in the way that color is represented in NTSC video
posted by mbo at 10:37 PM on June 5, 2020 [1 favorite]


I think you have that backwards: gamma encoding dedicates more values to dark colors than to bright ones. The underlying problem is that an 8-bit luma (Y) is simply too small (256 possible grayscale values is just not that many); in linear 8-bit the darks would look even worse.
posted by Pyry at 11:54 PM on June 5, 2020 [1 favorite]


I'm kind of relieved that the presenter said he couldn't re-create it deliberately using his own tools. Because if he had been able to, then I probably would have spent way too much time making right-wing meme background images that contained the poisoned pixel, and uploading them to wallpaper sites.

I mean, theoretically...
posted by rum-soaked space hobo at 4:41 AM on June 6, 2020


Behold! The mighty pixel! Just when you think you're too small to make a difference in the world, along comes a story like this...
posted by WalkerWestridge at 10:58 AM on June 7, 2020 [2 favorites]


I have no way to verify this because it's way outside of my experience, but a few people on Reddit have claimed that the image must have an uncommon color profile to make this happen. I think not every image has a color profile in its metadata, and not every color profile produces this bug. Some have claimed the profile is probably broken to produce this effect, other seem to think it's valid but the profile creates a very-unusual edge case. Either way that would explain why people aren't accidentally creating Android-destroying wallpapers left and right.

Threads where I've seen it discussed:

https://www.reddit.com/r/Android/comments/gtsoxc/apparently_a_certain_wallpaper_is_causing_samsung/

https://www.reddit.com/r/Android/comments/gwcwk0/update_new_explanation_google_response_this/
posted by Tehhund at 1:18 PM on June 7, 2020


Pyry: I think you have that backwards: gamma encoding dedicates more values to dark colors than to bright ones.

Depends on which gamma encoding direction you're talking about, doesn't it?
posted by clawsoon at 6:38 PM on June 8, 2020


Metafilter: arrays start at 0 dammit

That's the deal-breaker with Lua (and Lua-based platforms like PICO-8) for me. Their arrays start at 1, like Microsoft BASIC on a VIC-20 or something. What kind of Fisher-Price kindergarten bullshit is that?
posted by acb at 4:29 AM on June 10, 2020


« Older What Is an Anti-Racist Reading List For?   |   Amsterdam 4K Newer »


This thread has been archived and is closed to new comments