On 03/04/15 02:08, Martin Sebor wrote: > On 04/02/2015 02:13 AM, Andrew Haley wrote: >> On 04/01/2015 07:15 PM, Martin Sebor wrote: >>> On 04/01/2015 08:49 AM, Andrew Haley wrote: >>>> On 04/01/2015 03:36 PM, Andreas Schuh wrote: >>>> >>>>> I believe I have encountered a bug in the optimization at least in >>>>> versions 4.8.4 and 4.9.2. The problem is not present in version >>>>> 4.6.3. The attached complete example code can be used to reproduce >>>>> the error (my system is Ubuntu 12.04). This code is crucial in >>>>> medical image processing where the NIfTI-1 file format is commonly >>>>> used. The respective function that is optimized incorrectly by most >>>>> recent C/C++ compilers of GCC was copied from the NIfTI-1 C library >>>>> and is used by many medical image processing tools. It is >>>>> responsible for swapping the bytes if necessary when the image data >>>>> was written on a system with differing endianness. >>>> >>>> Sure, but it's not standard C. You really don't need to alias a >>>> struct of two bytes and a short, and these are not compatible types. >>>> (I can give you chapter and verse of the C standard if you really want >>>> it, but the rule is simple: don't expect a cast between pointers to >>>> different types to work. Doing so via a hidden void* doesn't help.) >>> >>> The C requirement is that "An object shall have its stored value >>> accessed only by an lvalue expression of ... a character type." >>> The original program accesses the value object via the tb[ii].a >>> and tb[ii].b expressions, which are both unsigned char lvalues. >>> That the program derives those lvalues from pointers to some >>> other type (*) doesn't violate the aliasing rule. >>> >>> [*] As if by: >>> >>> unsigned char *b0 = &((twobytes*)ar + ii)->a; >>> unsigned char *b1 = &((twobytes*)ar + ii)->b; >>> tt = *b0; >>> *b0 = *b1; >>> *b1 = tt; >> >> This is a common misconception. >> >> It's wrong because a->b is identical to (*(a)).b and a[i] is identical >> to (*((a)+(i))) . >> >> Therefore, in the section above, the expression >> >> &((twobytes*)ar + ii)->a >> >> is the same as >> >> &(((twobytes*)ar)[ii].b) > > Correct (with b replaced by a). This equivalence is also > why accessing the result doesn't violate the aliasing rules. > >> and the illegal access is more obvious. > > For the aliasing rule to be violated the access (defined in 3.1, p1 > as an action to read or modify an object) to the object would need > to be via an lvalue of a type other than character or short (such as > struct twobytes in the example program). I'm not convinced that's true. If you look at 6.3.2.3 you'll see that you have permission to convert a pointer to an object type to a pointer to a different object type (possibly several times) and back to the original type, or to a character type. That's it. You can't do anything else with the converted pointers. It would have been legal to convert that pointer to a char* and dereference it, but not to access a structure member. I think that would have worked in GCC. > However, none of the relevant subexpressions above > (as stated in 6.6, p9, neither the [] subscripting expression > nor the -> or . member selection operators accesses an object). > The access is only performed by the assignment expression when > the object designated by its right operand is read. The right > operand is, in all cases, an lvalue of character type. But in any case, I can't see that there is any point in such a fine nitpicking argument. It's not going to fix the problem, and I doubt that GCC is going to change. Andrew.