Re: GCC 4.8.4 4.9.2 nifti_swap_2bytes optimization bug

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux