How I found a bug in Intel Skylake processors (2017)
gallium.inria.fr
gallium.inria.fr
I wrote a Swift iOS app once, and came across an issue with one of the collection classes.
Of course, nobody thinks that the Swift libs will be wrong as a first guess. So I worked through a number of hypotheses about my own code, slowly stripping out pieces that I thought might contain an error. And then combinations. I also tried reducing the number of entries just to simplify the logs. This worked, but of course you are not going to think that there's a library bug affecting collections with size > 16, and it wasn't actually a theory until I randomly decided to reduce the n. I also discovered that it worked just fine on release but not debug, so I thought maybe I have some race condition.
More and more stripping down occurred, until I eventually gave up using my own project and just started a new one just to see about the collection class. I did it for the sake of being thorough, rather than actually thinking the lib had a bug in its debug implementation. But lo and behold, when I managed to make it reproducible and put it on SO, someone from Apple acknowledged that they could also see it, and they fixed it.
Naturally if I'd gone direct to testing the lib I'd have saved a huge amount of time, but I guess that's the tradeoff from the most sensible heuristic: test your own code first, the bug is there.
Also known as "select is not broken" (see for instance https://blog.codinghorror.com/the-first-rule-of-programming-...).
This is highly dependent on which version of Swift you started with! When Swift introduced the new substring API I hit a bug where certain UTF-8 character sequences caused an index out of bounds error internally. Unfortunately we learned this in production when an entire organization couldn't launch our app due to a string they were feeding through it.
That is how your trust in the standard libs is forever broken. Library and compiler bugs were quite common in the Swift 1-3 days.
I've also found that depending on my employer, the open source codebases we use often don't actually hold up to the standard of quality that we hold our own code to. But we don't check it because all libraries are assumed to work.
Then one day I discovered APARs were a thing.
https://www.ibm.com/support/pages/open-apars-ibm-products-av...
(turns out that IBM do get decimals right if you're running on z/Architecture, where the code diverts to some hardware-accelerated fast path; just not on x86-64 machines used by paupers like my project)
It wasn’t just a visual thing - the calculation itself was changed by the toggling briefly to scientific mode and back again.
I no longer fully trust calculators.
https://lists.debian.org/debian-devel/2017/06/msg00308.html
Ahrefs writeup
https://tech.ahrefs.com/skylake-bug-a-detective-story-ab1ad2...
The Intel spec update still labels SKL150 as No Fix but there is a microcode update available. Dunno exactly what to make of that distinction.
https://www.intel.com/content/www/us/en/processors/core/desk...
Can an x86 program detect whether this update has been applied? Can a Linux process set a DONT_HYPERTHREAD_ME_BRO bit?
Of course, disabling the LSD has some costs: CPUs use more power and some loops are slower (though some are faster). These updates are usually applied silently without user consent, so you might quite surprised to find out that after a reboot your computation kernel suddenly draws more power or has slowed down or sped up.
> Can an x86 program detect whether this update has been applied? Can a Linux process set a DONT_HYPERTHREAD_ME_BRO bit?
Yes. One way would be to check the microcode version (available in /proc/cpuinfo on Linux, among other places), since the version that introduced this fix is known.
Another way would be to run a small loop known to fit in the LSD and then check a performance counter event which counts uops delivered from the LSD, like lsd.uops. This counter is always zero when the LSD is disabled (or realistically you could just run any substantial code and check the counter since you always have some non-neglible portion of the uops coming from the LSD). This is how I check it from the command line in practice.
Finally, if you don't have easy access to the counters, you could create a loop that has a significant performance difference depending on whether it is coming from the LSD or not. For example, a loop that crosses a 32-byte boundary will run 2 or more cycles when using the decoder or uop cache, but could run in 1 cycle in the LSD. Timing such a loop would give you a strong indication about whether the LSD is enabled.
---
* Specifically, the cache used is not a dedicated one, but rather the IDQ (decoded instruction queue) is reused. This queue holds uops and is normally fed by the decoders or the uop cache on one end, and which feeds the allocation/rename engine on the other. In LSD mode, this queue stops being a queue and is instead used as a kind of cache with the loop operations "locked down" in the queue and just repeatedly replayed.
(There are also hundreds of errata like this one in every CPU generation. They're usually not easy to exploit, since they cause system instability rather than disclosing secret material or allowing unintended code execution.)
It's not really a flaw, more like a consequence of how memory cells are laid out. I mean most people want lots of bits in their DRAM. Maximizing this parameter necessitates that some will be in close proximity.
Colloquially, it's basically a change in voltage in one place can indirectly cause a change in voltage in another place via capacitive coupling. Capacitance increases proportional to the inverse of the separating distance so only in recent years have things shrunk to the size that makes it an issue.
Since having less bits in DRAM is basically not an option most mitigation techniques that I know of remove the possibility of hammering: possibilities include the OS, memory system controller, or DRAM controller changes.
[1] https://users.ece.cmu.edu/~yoonguk/papers/kim-isca14.pdf
They should also have logic to refresh adjacent rows if some number of consecutive accesses to a small group of rows is detected. This is rare in normal workloads, because those accesses normally come from cache. It's lame of chipmakers to not fix this. The fix would requires the DRAM controller (integrated into modern CPUs) to know more about the internals of DRAMs than they currently do.
The programming in question here is ucode instead of application code, but it’s programming nonetheless.
(This is not a complaint; I found the post interesting.)
I found a bug in Intel Skylake processors - https://news.ycombinator.com/item?id=14686277 - July 2017 (99 comments)
This was the bane of my existence when I worked on testing Windows years ago. New SDETs almost invariably fell into the trap of assuming any automation error was a "test bug" instead of a bug in OS code, even if the OS code in question was written last week.
I think Intel should regression-test its CPUs using the decades of demoscene productions out there, especially those in the extreme-size-optimisation categories; testing with almost exclusively "mainstream" compiler output is IMHO a bad idea and a step down the path to "warranty void if VLC is used" (https://news.ycombinator.com/item?id=7205759 )
https://github.com/xoreaxeaxeax/sandsifter https://github.com/google/fuzzing/blob/master/docs/silifuzz.... https://www.phoronix.com/scan.php?page=news_item&px=Google-S...
And even if I did, I wouldn’t have the expertise to even figure it out.
:-)