Live data from Hacker News

A bug story: data alignment on x86

pzemtsov.github.io

81–90 of 111 posts

Re: A bug story: data alignment on x86

#82

What if you put the array in a struct and made a union of both uint32_t and uint8_t? Would the union with the larger size force the compiler to generate a 4-byte aligned array for the bytes? I suggest this because it would be portable without any compiler specific stuff.

It's already too late, the data is read from a file so the base of the array can be say at address 0xYYYYY2.

Re: A bug story: data alignment on x86

#83
post #77

Earlier quoted context omitted.

Well, portable except for `uint8_t` not being guaranteed to exist. =)

It isn't? At least that would be a failure at compile-time, rather than run-time.

`uint8_t` cannot exist on any platform with `CHAR_BIT > 8`. Such platforms are non-existent in the mainstream CPU world, but surprisingly common in the DSP world.

And yes, it's a compile-time failure, which is great. My comment should not be read as criticism at all (though I would likely use `uint16_t`, as the OP says the code is intended to work with [presumably aligned] 16-bit words).

Re: A bug story: data alignment on x86

#84

Again someone who relies on undefined behavior. Casting pointer of wrong alignement is not a platform specific behavior, it's an undefined behavior. Relying on it is an error. The author did not know "What Every C Programmer Should Know About Undefined Behavior": http://blog.llvm.org/2011/05/what-every-c-programmer-should-... Another good link about that: http://blog.regehr.org/archives/213

Again someone blaming the victim. I'm kind of sick of this. While true, your comment doesn't get at the root of the problem. The obvious fact here is that there is a mismatch between the C standard and how the users really use it. The less obvious fact/opinion/fallacy, is that it is not automatically the user's fault. The standard could be wrong. Sure, there are reasons why such and such behaviour ended up undefined.…

> The alignment bug here is such an example.

I would even claim that the language on all platforms definitely should be able to specify the "inconvenient" alignments, but that the platforms which can produce the fast code should. If you actually need some suboptimal alignment, you'll need it no matter if the '"language lawyers" cry now. I'd agree, the standard is potentially wrong for not having the possibility. It should be visually obvious that it's not optimal, but it shouldn't be too ugly to use it.

It's better to be able to declare something uniformly than to have pages of #ifdefs or to write a lot of ugly code.

This article and the comments here are good example. The article doesn't end there, it hopefully ends here in the comments, as qb45 claims that there is actually a declarative way for gcc, which at least on one version (the one which he tried) did produce the correct code:

https://news.ycombinator.com/item?id=12890429

But also see the other comments where some question if it realy works across the gcc versions.

Re: A bug story: data alignment on x86

#85
post #66

Earlier quoted context omitted.

Specifying alignment might make the crash go away. Like the "disable SSE" solution of the post, it does not make the undefined behavior go away and is not actually a solution.

If certain compilers provide functionality like __aligned__ or __packed__ it isn't undefined anymore on these particular compilers. I was specific about this being a GCC/clang thing (GCC to be exact, but somebody else confirmed clang).

__aligned__/__packed__ allow you to control alignment and packing, useful for e.g. avoiding false sharing in multithreaded code, and potentially useful if you're doing some of the type aliasing allowed by the standard - namely, type punning to/from char.

Unless __aligned__ or __packed__ is documented as also relaxing the strict aliasing rules - if such documentation exists, I haven't found it - there's still undefined behavior from the strict aliasing violation by type punning size_t uint32_t.

Bad alignment is not the only possible "bad" optimization compilers can apply that relies on this being undefined behavior. For example, they may mistakenly assume a size_t value in memory can be cached in a register, and not reloaded from memory when it calls code that uses only uint32_t* pointers, because in a standards compliant program these cannot be used to modify size_t values.

You need __may_alias__ as well.

Re: A bug story: data alignment on x86

#86

Earlier quoted context omitted.

I doubt you can count on all items being allocated at addresses that are multiples if their size. It's not optimal but you can always use libc::posix_memalign()

The final element of the struct is a zero length array of elements of size N bytes. So that element isn't padding, it has size 0! It's pure hinting. I'm not sure why or how this works under the hood I'm afraid. I used it successfully to call a library with pretty strict alignment requirements (Intel Embree).

The zero length array still must be aligned correctly. You can create a pointer to it (e.g. by taking &something._alignment[..] to create a slice) and pointers must have correct alignment, so it follows that a zero length array has the same alignment requirements as a longer array. So padding must be inserted in your struct so that the address of the zero-length array is correctly aligned.

Re: A bug story: data alignment on x86

#87

Again someone who relies on undefined behavior. Casting pointer of wrong alignement is not a platform specific behavior, it's an undefined behavior. Relying on it is an error. The author did not know "What Every C Programmer Should Know About Undefined Behavior": http://blog.llvm.org/2011/05/what-every-c-programmer-should-... Another good link about that: http://blog.regehr.org/archives/213

Again someone blaming the victim. I'm kind of sick of this. While true, your comment doesn't get at the root of the problem. The obvious fact here is that there is a mismatch between the C standard and how the users really use it. The less obvious fact/opinion/fallacy, is that it is not automatically the user's fault. The standard could be wrong. Sure, there are reasons why such and such behaviour ended up undefined.…

> Again someone blaming the victim. I'm kind of sick of this.

C and C++ blame the victim - as do, in practice, compilers for them - by labeling what they've done "undefined behavior" and telling you to do better. I'm kind of sick of C and C++ too. Plenty better than I have attempted to argue the case for optimizers to hold back and behave saner, to stop their abuse. They have failed. I've done plenty of arguing against choosing C or C++ for projects that do not need it. I have failed. I can educate on undefined behavior, that victims may attempt to avoid and combat their abuse. Maybe someday they will break the cycle, and I will have had a hand in enabling them.

While perhaps ogoffart does not perfectly outline that maybe the language is at fault for some UB, ogoffart's links make the case. TIL about yet another source of undefined behavior:

>>> An unmatched ‘ or ” character is encountered on a logical source line during tokenization.

>> With all due respect to the C standard committee, this is just lazy.

My understanding is that this:

  int main() { return !"
Could launch NetHack. Disgusting.

Re: A bug story: data alignment on x86

#88

Again someone who relies on undefined behavior. Casting pointer of wrong alignement is not a platform specific behavior, it's an undefined behavior. Relying on it is an error. The author did not know "What Every C Programmer Should Know About Undefined Behavior": http://blog.llvm.org/2011/05/what-every-c-programmer-should-... Another good link about that: http://blog.regehr.org/archives/213

Again someone blaming the victim. I'm kind of sick of this. While true, your comment doesn't get at the root of the problem. The obvious fact here is that there is a mismatch between the C standard and how the users really use it. The less obvious fact/opinion/fallacy, is that it is not automatically the user's fault. The standard could be wrong. Sure, there are reasons why such and such behaviour ended up undefined.…

Well, it is blaming someone who does not know how to use its tools. If I had writen a blog post aboug how I spent one day trying to fix a leak and then discovered that I always had to call free() after malloc(); would it still be victim blaming than blame me for not knowing the basic of C?

> The alignment bug here is such an example.

It is not since it allows vectorisation. The error was to assume that what one writes in C translates directly to assembly.

Re: A bug story: data alignment on x86

#89
post #53

Earlier quoted context omitted.

> If a particular compiler specified that casting pointers of wrong alignments causes a segfault, it'd be perfectly acceptable to rely on that behavior. This is a great way to make your programs "fun" to port to new platforms with new compilers in terrifyingly subtle ways. I prefer not to recommend this approach to solving specific cases of undefined behavior, although if you happen to disable strict aliasing (with e…

You can also defensively add a quick test to your program's startup code and unit tests. Startup will take a tiny bit longer, but those porting your code will be thankful if they hit the problem, double so if you manage to emit a useful diagnostic.

That would not work. Since the test may not cause any problems. While the compiler might find more optimzation opportuinities in the real program. (Just as the begining of the function did not have problem, but the for loop had.)

Just don't use undefined behavior.

Re: A bug story: data alignment on x86

#90

Earlier quoted context omitted.

Again someone blaming the victim. I'm kind of sick of this. While true, your comment doesn't get at the root of the problem. The obvious fact here is that there is a mismatch between the C standard and how the users really use it. The less obvious fact/opinion/fallacy, is that it is not automatically the user's fault. The standard could be wrong. Sure, there are reasons why such and such behaviour ended up undefined.…

> Again someone blaming the victim. I'm kind of sick of this. C and C++ blame the victim - as do, in practice, compilers for them - by labeling what they've done "undefined behavior" and telling you to do better. I'm kind of sick of C and C++ too. Plenty better than I have attempted to argue the case for optimizers to hold back and behave saner, to stop their abuse. They have failed. I've done plenty of arguing again…

> by labeling what they've done "undefined behavior" and telling you to do better.

If only they did that. But no, they instead label what they've done "undefined behavior", and silently perform optimizations that may or may not break their program entirely. Double emphasis on silently.

Post reply on HN