Live data from Hacker News

GCC always assumes aligned pointer accesses

trust-in-soft.com

71–80 of 93 posts

Re: GCC always assumes aligned pointer accesses

#71
post #61

Earlier quoted context omitted.

I genuinely can't follow you completely, but half suspect you're violently agreeing with me. Are you saying the optimization in the linked article is, or is not, in violation of the standard? Edit: this is the text I was remembering, from 6.5.16.1 ("Simple Assignment"): " If the value being stored in an object is read from another object that overlaps in any way the storage of the first object, then the overlap shall…

6.5.16.1 is the “rule that only apply to “lvalue = lvalue;” assignments and is not relevant here” It does not apply to “lvalue = 1;” or to “lvalue = 2;”, which are the two relevant assignments in the example in the article. For context, I think I made it clear in the article that the program being discussed is UB, and therefore that the compiler is not to blame. But since I wrote this article, I have had people telli…

You're being unnecessarily combative.

> No. You are wrong. There are no words in the standard that say that “basic types cannot overlap in memory”.

§ J.2, Undefined Behavior

An object is assigned to an inexactly overlapping object or to an exactly overlapping object with incompatible type (6.5.16.1).

> There is not even a notion of “basic type”.

"Object."

You repeatedly (in this thread, and on your blog) express that you don't really understand "strict" (ISO standard) aliasing rules, and that seems to be the case.

Re: GCC always assumes aligned pointer accesses

#72
post #20
post #3

Earlier quoted context omitted.

Yes, this is the compiler optimizing UB due to aliasing , not due to alignment.

Yes, the optimization assumes that given two pointers to int, either they point to the same int, or they point to distinct, non-overlapping ints. Under that restriction the result is guaranteed to be 1. It's allowed to do so by the standard because those are the rules. C was portable assembly back in the early 1980s. The result was that it was crushed in performance by Fortran for scientific codes, and most of the di…

> The result was that it was crushed in performance by Fortran for scientific codes, and most of the difference had to do with assumptions the compiler could make about aliasing (or the lack of it). This was fixed

Calling it "fixed", as if it were a problem of the language rather than programmers' expectations, is a rather slanted view of the history.

Re: GCC always assumes aligned pointer accesses

#73

Earlier quoted context omitted.

>> 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.

The C language does not support what you're trying to do. You should use assembly to do this.

This is actually more subtle than one would think.

Say you were trying to talk to three UART registers at 0xA000, 0xA004, and 0xA008. It's legal to access:

    *(volatile uint32_t *)(0xA000);
    *(volatile uint32_t *)(0xA004);
    *(volatile uint32_t *)(0xA008);
The struct equivalent of this would be something like:

    struct UART_Peripheral {
        volatile uint32_t control;
        volatile uint32_t txdata;
        volatile uint32_t rxdata;
    };

    struct UART_Peripheral *uart0 = 0xA000;
    uart0->control;
    uart0->txdata;
    uart0->txdata;
As long as your structure is packed/aligned correctly, this is perfectly valid C. You can enforce the structure packing with an __attribute__ ((__packed__)) if using GCC or Clang. I think MSVC has a pragma for it.

I know that the C language spec allows for structure padding, but I'm not sure if the concept is applicable if every member of the structure is the native word-size of the target CPU.

But regardless of whether the spec specifies this expicitly or not, I've never seen a compiler insert padding in-between struct members that are already word-aligned.

So the code might be very slightly questionable if written in pure C with no packing pragmas/attributes - but even then it would probably work on almost every target. And if used with the right pragma/attribute for your compiler, it's a perfectly valid construct. And it's also a common one - especially in embedded work or hardware drivers.

Re: GCC always assumes aligned pointer accesses

#74

Earlier quoted context omitted.

>> 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.

The C language does not support what you're trying to do. You should use assembly to do this.

C does support this and has for decades. Many device drivers are written in C and do this exact thing.

Re: GCC always assumes aligned pointer accesses

#75
post #14

Earlier quoted context omitted.

"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.

MC68k (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.

Yes, I remember running into this on the Amiga. The later processors, like the 68020 and 030, removed this restriction.

Re: GCC always assumes aligned pointer accesses

#76
post #71

Earlier quoted context omitted.

6.5.16.1 is the “rule that only apply to “lvalue = lvalue;” assignments and is not relevant here” It does not apply to “lvalue = 1;” or to “lvalue = 2;”, which are the two relevant assignments in the example in the article. For context, I think I made it clear in the article that the program being discussed is UB, and therefore that the compiler is not to blame. But since I wrote this article, I have had people telli…

You're being unnecessarily combative. > No. You are wrong. There are no words in the standard that say that “basic types cannot overlap in memory”. § J.2, Undefined Behavior An object is assigned to an inexactly overlapping object or to an exactly overlapping object with incompatible type (6.5.16.1). > There is not even a notion of “basic type”. "Object." You repeatedly (in this thread, and on your blog) express that…

This line of J.2 only refers to the already cited 6.5.16.1.

You keep quoting this clause as if it applied to any of the assignments in the program being discussed.

It doesn't.

That clause says that in an assignment of the form “lvalue1 = lvalue2;”, there must only be exact overlap or no overlap between lvalue1 and lvalue2. This does not apply to assignments of the form “lvalue = 1;” or “lvalue = 2;” which are the interesting assignments in the program being discussed.

Objects are not “basic types” for the original sentence that claimed that “basic types cannot overlap in memory”. Objects overlap in memory all the time.

> You repeatedly (in this thread, and on your blog) express that you don't really understand "strict" (ISO standard) aliasing rules, and that seems to be the case.

If you say so. I'm not the one who thinks that “* p” and “1” overlap.

Re: GCC always assumes aligned pointer accesses

#77
post #66

Earlier quoted context omitted.

6.5.16.1 is the “rule that only apply to “lvalue = lvalue;” assignments and is not relevant here” It does not apply to “lvalue = 1;” or to “lvalue = 2;”, which are the two relevant assignments in the example in the article. For context, I think I made it clear in the article that the program being discussed is UB, and therefore that the compiler is not to blame. But since I wrote this article, I have had people telli…

I'm sorry, can you explain how that's not relevant here? You're being incongruously combative, but I still think you're mostly agreeing with me. The section on "simple" assignments doesn't say that the rvalue must be an lvalue expression syntactically . I think it applies very well to "*p = 1;", which is the statement in the linked code. What am I missing? > There are no words in the standard that say that “basic typ…

1 is not an object, but even if it was one, it would not be an object that overlaps with “* p”.

You are interpreting the C standard as if it were a philosophy text. It contains a rule that says that in very precise circumstances (for an assignment from one to the other) objects must not partially overlap, and you are claiming that it means that “two pointers to the same basic type cannot overlap in memory”. The clause does not say that, sorry. The clause applies to the objects that are on one side and the other of an assignment.

> I said the standard expressly allowed the optimization in the linked article.

I hope that the article makes it clear that the standard expressly allows the optimization. Specific, explicit rules, cited in the article, about pointer alignment, allow the optimization.

For this reason, I, “violently” as you say, disagree with the sentence “The complaint isn't about alignment at all, it's that the optimizer assumes that two pointers to the same basic type cannot overlap in memory”. This sentence gets it all wrong. It is about alignment; it is not about “pointers to basic types”, whatever that is, not being allowed to overlap in memory; they are allowed to overlap for large enough “basic types” because it is about alignment, not overlap:

https://gcc.godbolt.org/z/ZAMkeH

You could argue that GCC 9.3 only missed the optimization in the example in this Compiler Explorer link for some other reason and that absence of optimization doesn't mean that p and q cannot overlap. This would be correct, this aspect is one of the difficulties in studying the rules that these compilers implement. However, what I am saying is that if you reported this missed optimization to GCC developers, they would tell you that GCC can't optimize the function f because p and q can overlap. There is no clause in the C standard that prevent them to (apart from strict aliasing rules, but I used the option to tell the compiler I didn't want it to take advantage of these ones).

(Please do not bother them with this, or if you do, at least leave me out of it; I have nothing better to do than to write this because it's the week-end but they have better things to do.)

Re: GCC always assumes aligned pointer accesses

#78

Earlier quoted context omitted.

Sort 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…

Author here! I am not saying or thinking that there is a problem with GCC. I do think that GCC and Clang would be more useful with an option to make them not assume that every pointer is aligned if the target architecture does not impose this, but that's not the same thing as saying there is something wrong with GCC. The message of the post, rather than “something is wrong with GCC”, is, “Beware. You might think that…

Do you know if there is a compiler switch that can insert run-time checks any time it makes assumptions which could be invalid (such as “this random pointer is aligned”) and abort with an error message (or something) when it is not true? I think this would be invaluable for tracking down odd bugs caused by things like this.

Re: GCC always assumes aligned pointer accesses

#79
post #70

Earlier quoted context omitted.

Could you clarify which clause of the C standard you are referring to when you say “due to aliasing, not due to alignment”? I make sense of the C standard for a living (this is literally my day job) and I do not see what clause of the C standard you are referring to. It would be very useful to me to know which clause you are referring to, and I would be eternally thankful.

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

So the clause about assignment? Thanks, that was helpful.

Re: GCC always assumes aligned pointer accesses

#80
post #71

Earlier quoted context omitted.

You're being unnecessarily combative. > No. You are wrong. There are no words in the standard that say that “basic types cannot overlap in memory”. § J.2, Undefined Behavior An object is assigned to an inexactly overlapping object or to an exactly overlapping object with incompatible type (6.5.16.1). > There is not even a notion of “basic type”. "Object." You repeatedly (in this thread, and on your blog) express that…

This line of J.2 only refers to the already cited 6.5.16.1. You keep quoting this clause as if it applied to any of the assignments in the program being discussed. It doesn't. That clause says that in an assignment of the form “lvalue1 = lvalue2;”, there must only be exact overlap or no overlap between lvalue1 and lvalue2. This does not apply to assignments of the form “lvalue = 1;” or “lvalue = 2;” which are the int…

> You keep quoting this clause as if it applied to any of the assignments in the program being discussed.

> It doesn't.

You keep asserting that 6.5.16.1 is not relevant, as if it makes it so; but it doesn't. It's your opinion; the assertions are not persuasive.

  void f(void) {
    char *t = malloc(1 + sizeof(int));
    if (!t) abort();
    int *fp = (int*)t;
    int *fq = (int*)(t+1);
    h(fp, fq);

  int h(int *p, int *q){
    *p = 1;
    *q = 1;
    return *p;
  }
Please explain to me why you continue to believe that is not an object being assigned to an inexactly overlapping object or to an exactly overlapping object with incompatible type?
Post reply on HN