[PATCH] Avoid negative bitpos in expand_expr_real_1 (PR 86984)

Jeff Law law@redhat.com
Mon Aug 20 14:16:00 GMT 2018


On 08/20/2018 07:28 AM, Richard Biener wrote:
> On Mon, 20 Aug 2018, Bernd Edlinger wrote:
> 
>> On 08/20/18 12:41, Richard Biener wrote:
>>> On Sun, 19 Aug 2018, Bernd Edlinger wrote:
>>>
>>>> Hi!
>>>>
>>>>
>>>> This fixes a wrong code issue in expand_expr_real_1 which happens because
>>>> a negative bitpos is actually able to reach extract_bit_field which
>>>> does all computations with poly_uint64, thus the offset 0x1ffffffffffffff0.
>>>>
>>>> To avoid that I propose to use Jakub's r204444 patch from the expand_assignment
>>>> also in the expand_expr_real_1.
>>>>
>>>> This is a rather unlikely thing to happen, as there are lots of checks that are
>>>> of course all target dependent between the get_inner_reference and the
>>>> actual extract_bit_field call, and all other code paths may or may not have a problem
>>>> with negative bit offsets.  Most don't have a problem, but the bitpos needs to be
>>>> folded into offset before it is used, therefore it is necessary to handle the negative
>>>> bitpos very far away from the extract_bit_field call.  Doing that later is IMHO not
>>>> possible.
>>>>
>>>> The fix in CONSTANT_ADDRESS_P is actually unrelated, and I only spotted it because
>>>> this macro is used in alpha_legitimize_address which is of course what one looks
>>>> at first if something like that happens.
>>>>
>>>> I think even with this bogus offset it should not have caused a linker error, so there
>>>> is probably a second problem in the *movdi code pattern of the alpha.md, because it
>>>> should be split into instructions that don't cause a link error.
>>>>
>>>> Once the target is fixed to split the impossible assembler instruction, the test case
>>>> will probably no longer be able to detect the pattern in the assembly.
>>>>
>>>> Therefore the test case looks both at the assembler output and the expand rtl dump
>>>> to spot the bogus offset.  I only check the first 12 digits of the bogus constant,
>>>> because it is actually dependent on the target configuration:
>>>>
>>>> I built first a cross-compiler without binutils, and it did used a slightly different
>>>> offset of 0x2000000000000000, (configured with: --target=alpha-linux-gnu --enable-languages=c
>>>> --disable-libgcc --disable-libssp --disable-libquadmath --disable-libgomp --disable-libatomic)
>>>> when the binutils are installed at where --prefix points, the offset is 0x1ffffffffffffff0.
>>>>
>>>> Regarding the alpha target, I could not do more than build a cross compiler and run
>>>> make check-gcc-c RUNTESTFLAGS="alpha.exp=pr86984.c".
>>>>
>>>>
>>>> Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
>>>> Is it OK for trunk?
>>>
>>> Hmm, I don't remember why we are inconsistent in get_inner_reference
>>> with respect to negative bitpos.  I think we should be consistent
>>> here and may not be only by accident?  That is, does
>>>
>>> diff --git a/gcc/expr.c b/gcc/expr.c
>>> index c071be67783..9dc78587136 100644
>>> --- a/gcc/expr.c
>>> +++ b/gcc/expr.c
>>> @@ -7272,7 +7272,7 @@ get_inner_reference (tree exp, poly_int64_pod
>>> *pbitsize,
>>>                                        TYPE_PRECISION (sizetype));
>>>         tem <<= LOG2_BITS_PER_UNIT;
>>>         tem += bit_offset;
>>> -      if (tem.to_shwi (pbitpos))
>>> +      if (tem.to_shwi (pbitpos) && !maybe_lt (*pbitpos, 0))
>>>          *poffset = offset = NULL_TREE;
>>>       }
>>>   
>>> fix the issue?
>>>
>>
>> Yes, at first sight, however, I was involved at PR 58970,
>> see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58970
>>
>> and I proposed a similar patch, which was objected by Jakub:
>>
>> see comment #25 of PR 58970:
>> "Jakub Jelinek 2013-11-05 19:41:12 UTC
>>
>> (In reply to Bernd Edlinger from comment #24)
>>> Created attachment 31169 [details] https://gcc.gnu.org/bugzilla/attachment.cgi?id=31169
>>> Another (better) attempt at fixing this ICE.
>>>
>>> This avoids any negative bitpos from get_inner_reference.
>>> These negative bitpos values are just _very_ dangerous all the
>>> way down to expmed.c
>>
>> I disagree that it is better, you are forgetting get_inner_reference has other > 20 callers outside of expansion and there is no reason why negative bitpos would be a problem in those cases."
>>
>> So that is what Jakub said at that time, and with the
>> suggested change in get_inner_reference,
>> this part of the r204444 change would be effectively become superfluous:
>>
>> @@ -4721,6 +4721,15 @@ expand_assignment (tree to, tree from, bool nontem
>>         tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
>>                                   &unsignedp, &volatilep, true);
>>   
>> +      /* Make sure bitpos is not negative, it can wreak havoc later.  */
>> +      if (bitpos < 0)
>> +       {
>> +         gcc_assert (offset == NULL_TREE);
>> +         offset = size_int (bitpos >> (BITS_PER_UNIT == 8
>> +                                       ? 3 : exact_log2 (BITS_PER_UNIT)));
>> +         bitpos &= BITS_PER_UNIT - 1;
>> +       }
>> +
>>         if (TREE_CODE (to) == COMPONENT_REF
>>            && DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1)))
>>          get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset);
>>
>> and should be reverted.  I did not really like it then, but I'd respect Jakub's advice.
> 
> Hmm.  I agree that there are other callers and yes, replicating Jakubs
> fix is certainly more safe.  Still it's somewhat inconsistent in that
> get_inner_reference already has code to mitigate negative bitpos, but
> only in the case 'offset' wasn't just an INTEGER_CST ...
> 
> So your patch is OK (please change the gcc_asserts to 
> gcc_checking_asserts though to avoid ICEing for release compilers).
> 
> We still might want to revisit get_inner_reference (and make its
> bitpos unsigned then!)
Given this is keeping my tester from running on alpha, I'm going to make
the adjustment to Bernd's patch and commit it momentarily.

jeff



More information about the Gcc-patches mailing list