4 ms·
No. [as in: this isn't about GCC.] The C standard requires that pointers generally be created from referencing a valid, existing object. A misaligned integer
by eqvinox 7y ago
No. [as in: this isn't about GCC.]
The C standard requires that pointers generally be created from referencing a valid, existing object. A misaligned integer is not a valid "object", thus the compiler may assume that all pointers to ints are aligned (to 4 bytes.)
https://en.cppreference.com/w/cpp/language/pointer https://en.cppreference.com/w/cpp/language/pointer
Every value of pointer type is one of the following:
- a pointer to an object or function (in which case the pointer is said to point to the object or function), or
- a pointer past the end of an object, or
- the null pointer value for that type, or
- an invalid pointer value.
Relatedly, `malloc` is required to return a pointer with the largest alignment of any type ("suitably aligned to hold an object".)
Edit/Add: that's C++ in the link above, but it's the same in C. You can get a pointer from either a valid static/stack object, or malloc, which is "max" aligned. Either way it's required to point to a valid object, which includes correct alignment. If you implement your own memory management / allocator, it's also your responsibility to meet these same alignment requirements.
https://en.cppreference.com/w/c/language/object https://en.cppreference.com/w/c/language/object
- dooglius 7y agoWhy "no", you're agreeing with the conclusion
- eqvinox 7y ago"No, it's not GCC's fault / doing something weird." :) But, yes. Edited to clarify. FWIW this isn't a new problem either. If you wrote some C code in the 90ies using misaligned pointers, and then tried porting it to, say, a DEC Alpha, you'd get a SIGBUS in your face on first dereferencing such a pointer.
- guenthert 7y agoMC68k (anno 1979) didn't like misaligned memory access either and I have no reasons to believe that this started with Motorola. But yes, it's always fun watching a new generation falling into the old traps.
- hazeii 7y agoIndeed, PDP/11s don't like it. Older ARM designs too, though I believe they allow it since about ARM6 (perhaqps because x86 does?).
- simcop2387 7y agoThe arms allow it since ARMv5, but it's still not quite what one would expect until ARMv7. However it has a significant performance penalty when doing it. https://medium.com/@iLevex/the-curious-case-of-unaligned-access-on-arm-5dd0ebe24965 https://medium.com/@iLevex/the-curious-case-of-unaligned-acc...
- elgfare 7y agoCortex-M0 still does not allow it, and fun fact: Cortex-M4 allows unaligned access, but can be configured run-time to not allow it.
- icedchai 7y agoYes, I remember running into this on the Amiga. The later processors, like the 68020 and 030, removed this restriction.
- IshKebab 7y agoSort of. He definitely talks about the fact that it is undefined behaviour to create a misaligned pointer: > Strictly speaking, the function f invokes Undefined Behavior when it computes [the misaligned pointer] But he thinks it is still a problem with GCC, in that GCC should not be allowed to take advantage of this particular UB. He explains his view much better in the bug report: > GCC assumes that pointers must be aligned as part of its optimizations, even if the ISA does not force it (for instance, x86-64 without the vector instructions). The present feature wish as for an option to make it not make this assumption. > Since the late 1990s, GCC has been adding optimizations based on undefined behavior, and “breaking” existing C programs that used to “work” by relying on the assumption that since they were compiled for architecture X, they would be fine. The reasonable developers have been kept happy by giving them options to preserve the old behavior. These options are -fno-strict-aliasing, -fwrapv, ... and I think there should be another one.
- cyphar 7y agoThe problem with disabling this optimisation is that it will produce garbage code for basically every architecture. Code which does unaligned accesses are noticeably slow compared to aligned accesses -- this is why there are separate instructions and intrinsics for aligned and unaligned addresses on most architectures. That way you don't pay the penalty of unaligned accesses all the time. But if you try to use the aligned instructions on unaligned pointers you will get all sorts of fun errors. And note that this slowdown would have to apply to every pointer operation in your program because GCC can't know whether a pointer is aligned at compile-time. I'm sure many more people would complain about significant performance slowdowns in a GCC update than about unaligned memory accesses being something you need to do with great care in C.
- pron 7y ago> And note that this slowdown would have to apply to every pointer operation in your program because No, because I think that on x86 the instructions are the same for aligned and unaligned up to, and including, 64 bits (quadword). The only slowdown that would occur is due to missed compiler optimizations, and the author proposed disabling them as an option.
- efdwefwfwerf 7y agoI'm glad the OP posted this article to remind of some of the complexities of C (and C issues in C++) development. However, to coerce some of the bad examples OP used casting. This breaks the larger claim. A proper example of the issue would start with a bonafide int* word aligned and get to a non-aligned access without casting. Others mention packed v. non-packed structures ... this seems a more likely way to shoot yourself in the foot.
- pron 7y agoThat misaligned access is UB and that gcc's particular behaviour is assuming alignment are two related but different things. The article says that both are true, and the title is simply the second, as that is the more impactful fact.
- eqvinox 7y agoI disagree that the second is more impactful, but that's because I work with oddball architectures where the UB actually crashes the program ;). I'm wondering though, does UBSAN catch this?
- saagarjha 7y agoIn my experience, yes, it’ll warn you if you access something aligned to the wrong boundary.
- pron 7y agoIf gcc crashed the program, then that would have been the headline. It's more interesting to know the actual behavior a popular compiler exhibits for a given UB, especially if it's a potentially harmful one, than the mere fact that something is a UB (which you can also just see in the standard).
- phkahler 7y ago>> The C standard requires that pointers generally be created from referencing a valid, existing object. It is common to reference memory mapped peripherals by casting an integer to a struct pointer. In that case only a human can certify the validity of the object.
- chrisseaton 7y agoThe C language does not support what you're trying to do. You should use assembly to do this.
- pjmlp 7y agoI bet plenty of embedded C code is full of such casts.
- icedchai 7y agoC does support this and has for decades. Many device drivers are written in C and do this exact thing.
- chrisseaton 7y agoThe claim was: > It is common to reference memory mapped peripherals by casting an integer to a struct pointer. If you check the C standard you'll see that C guarantees nothing about what happens when you do this. I work with a compliant C implementation where this would not work.
- icedchai 7y agoThe fact is that many (most?) implementations do support this. It is implementation specific. If it never worked, you'd never be able to write a device driver using memory mapped IO in C, which is pure lunacy.
- chrisseaton 7y ago> The fact is that many (most?) implementations do support this. Which implementations? GCC? The compiler used for the Linux kernel? Why do you think that? https://gcc.gnu.org/onlinedocs/gcc/Arrays-and-pointers-implementation.html https://gcc.gnu.org/onlinedocs/gcc/Arrays-and-pointers-imple... does not clarify what they do in this case. So it's not defined by the language nor the compiler documentation. How do we know what it does? Do you check the disassembly? What if it compiles one way one day and another the next because something else changed in your code? If you write C code to do this and compile it with the most common C compiler, and it works, then you're just lucky! Nobody is guaranteeing it will do anything at all! It's much better to do it in assembly, where you know it's doing what you want.