P
Pavel Zemtsov
pzemtsov.github.io · Personal blog · on HN since 2014
Pavel Zemtsov writes technical posts on performance and low-level bugs in Java, C, and C++, such as alignment, hashing, and timing.
What HN saysHN commenters cite his posts as concrete examples of alignment-related undefined behavior, a Game of Life implementation, and the real cost of system calls.
23HN people shared it
10linked it in comments
16stories submitted
751story points
6 months agolast shared
2014people per year2026
Most-shared posts
- 1A bug story: data alignment on x869 people · 325 points · first shared 2016 · 107 comments on HN
- 2The slow currentTimeMillis()4 people · 326 points · first shared 2017 · 52 comments on HN
- 3Game of Life, hash tables and hash codes2 people · 34 points · first shared 2015 · discussion on HN
- 4Building a fast queue between C++ and Java2 people · 3 points · first shared 2018 · discussion on HN
- 5Abnormal String Hashing1 people · 52 points · first shared 2019 · 15 comments on HN
- 6Making a fast char searcher in C1 people · 3 points · first shared 2019 · discussion on HN
- 7Statistical variables in Java: not quite legal but very fast1 people · 3 points · first shared 2017 · discussion on HN
- 8Home-made hash tables in Java1 people · 2 points · first shared 2016 · discussion on HN
- 9Searching in a constant set using conflict-free hashing1 people · 1 points · first shared 2016 · discussion on HN
- 10Searching for a Better IndexOf1 people · 1 points · first shared 2019 · discussion on HN
- 11Demultiplexing of E1 Streams1 people · 1 points · first shared 2021 · discussion on HN
- 12How to make C as fast as java1 people · first shared 2014
What HN people wrote when they linked it
ineiti · 2021-03-08
Did you consider something like the following to speed up the calculation? This method can go forward _really_ fast. Not sur e if it can also go backward...
https://pzemtsov.github.io/2015/04/24/game-of-life-hash-tables-and-has…
oconnor663 · 2018-11-04
> A compiled binary that worked correctly won't suddenly run into undefined behaviour, that can only happen if you upgrade compiler versions...
Upgrading the compiler version and causing undefined behavior sounds pretty sudden. Here's my favorite story along those lines: http://pzemtsov.github.io/2016/11/06/bug-story-alignment-on-x86.html
rom1v · 2026-05-20
A concrete example of undefined behavior caused by an unaligned pointer: https://pzemtsov.github.io/2016/11/06/bug-story-alignment-on-x86.html
SomeoneFromCA · 2020-04-18
Interestingly enough, I've just checked the code from this article (https://pzemtsov.github.io/2016/11/06/bug-story-alignment-on-x86.html)… linked by the OP's article, and guess what - CLANG generates code that does not crash, although it still uses SSE4.
ambrop7 · 2018-01-02
I think syscalls are not as slow as many people imagine they are, especially with modern CPUs and kernels (there are special instruction for syscalls that are faster than the old "interrupt" approach). See here: http://pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.html ("Off-topic: A system call"). But they will be slow with this mitigation.
daemin · 2017-08-03
I believe the article was http://pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.html Although I couldn't easily find it in my history or on HN. I had to resort to the Googles.
dleskov · 2014-07-05
> creating a super-optimized tight loop of a program in C++, C or (better) assembly might be much easier to do than in higher level JITted languages
Sometimes, the situation is exactly opposite, though:
http://pzemtsov.github.io/2014/05/15/how-to-make-C-as-fast-as-java.htm…
Asooka · 2019-05-02
Oh I see you didn't get to caveat 5: you can't read anything more complicated than raw bytes, i.e. chars, because of unaligned memory access errors. Let's say you mmap a file and do something like this:
char *fileContents=...mmap etc...;
int headerOffset=*(int*)fileContents;
int *someListOfNumbers=(int*)(fileContents+headerOffset);
int importantSum=
someListOfNumbers[0] +
someListOfNumbers[1] +
someListOfNumbers[2] +
someListOfNumbers[3];
If headerOffset is not a multiple of 4, bad things will happen. On x86 you'll get away with it... Unless you were summing many more ints and the compiler decides to use aligned SSE loads for speed[1]. On ARM you'll get a SIGBUS just for trying to read unaligned ints (IIRC). You can fix that by wrapping your ints or whatever you're trying to read in a packed struct, but it is yet another thing to keep in mind.
[1] http://pzemtsov.github.io/2016/11/06/bug-story-alignment-on-x86.html
exikyut · 2018-09-05
> I like the idea of software, libraries and application code all being accessible to each other and have the ability to call each other. Too much functionality is siloed behind application A or B, and the interface exposed by these applications is often woefully inadequate for anything interesting.
Maybe I'm skeptical, but I've gotten to the point where I believe that this specific problem is not going to be solved anytime soon.
Here's how I see it. I believe that unification, specifically within software, is universally based on the idea that we can clean up the world (where "the world" refers to a given software environment) if only we can reimagine it clearly enough and, to borrow a few technical concepts, compute a delta with enough detail and resolution that it'll carry us from where we are to where we want to be. (With the implicit [mis]understanding that all we need to do is make said delta exist, and then it'll do all the work of carrying us.)
I think the above is what we're trying to do - and that we're doing it because we're staring at/barking up the wrong set of trees (the associated forests of which got lost long ago).
Ultimately, the world is a disorganized mess. Any security researcher could entertain you for days with highly-detailed hair-raising examples and proofs of this. I've very recently (finally) realized this is because, at a very high level, the world operates somewhat similarly to the bazaar model Linux uses. Evolution is highly organic, often…
Dylan16807 · 2017-10-08
> Optimizers don't look for undefined behaviour to then do whatever, they look for the set of defined behaviours and then try to generate the cheapest code that behaves correctly in all those cases--and if that means that undefined cases do weird stuff, that's an acceptable side effect.
> if any of the bytes are not inside any valid C object, then that would produce undefined behaviour
The compiler might also assume that every one of these loads will be exactly 4 bytes apart. Even worse, it might know that int32_t allocations will always be aligned, so it will assume that every load will be 4-byte-aligned. It then might output code that loses track of the bottom two bits, or SSE instructions that only work with certain alignments.
This isn't theoretical, this exact kind of bug has happened before, on a normal non-malicious compiler: http://pzemtsov.github.io/2016/11/06/bug-story-alignment-on-x86.html https://news.ycombinator.com/item?id=12889855
It's true that the buffer overrun issue is the same for either version; I misread what was being replaced. But the alignment issue is specific to this version, and can't be ignored.