[Bug middle-end/84184] gcc generates wrong relocations with negative offsets in struct arrays

skvadrik at gmail dot com gcc-bugzilla@gcc.gnu.org
Sat Aug 4 19:12:00 GMT 2018


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84184

Ulya <skvadrik at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |skvadrik at gmail dot com

--- Comment #12 from Ulya <skvadrik at gmail dot com> ---
(In reply to Eric Botcazou from comment #11)
> > Why those are handled differently? First looks like it works, second does
> > not. It was my main signal to file a bug against gcc as asymmetry looked
> > fishy.
> 
> Because the problematic bitfield path is only used for fields in structures,
> i.e. misaligned integers are handled by another, simpler path.

More details on the problematic path for this simple example:

    extern char __some_table[] __attribute__((visibility("hidden")));           
    struct s { long v; };                                                       
    long end(void) { return ((struct s *)__some_table)[-1].v; }                 

1. The problematic path makes an illegal signed-to-unsigned integer conversion
in expand_expr_real_1 (expr.c) when passing the signed 'bitnum' variable, with
value -64, as the 3rd param of extract_bit_field (expmed.c), with value
18446744073709551552.

2. The conversion itself doesn't spoil the value (meaning that the bits of
'bitnum' are not changed), and the value is passed on to extract_bit_field_1,
extract_integral_bit_field and extract_fixed_bit_field unharmed.

3. Finally, 'bitnum' is passed as the 5th param 'bitpos' to
extract_split_bit_field, where it gets involved in unsigned integer arithmetics
and bad things start to happen:


static rtx                                                                      
extract_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,                 
                         unsigned HOST_WIDE_INT bitsize,                        
                         unsigned HOST_WIDE_INT bitpos, int unsignedp,          
                         bool reverse)                                          
{                                                                               
  unsigned int unit;                                                            
  unsigned int bitsdone = 0;                                                    
  // ...                                                                        
  while (bitsdone < bitsize)                                                    
    {                                                                           
      unsigned HOST_WIDE_INT thissize;                                          
      rtx part;                                                                 
      unsigned HOST_WIDE_INT thispos;                                           
      unsigned HOST_WIDE_INT offset;                                            

      offset = (bitpos + bitsdone) / unit;      // <=== BAD THING 1             
      thispos = (bitpos + bitsdone) % unit;     // <=== BAD THING 2             
  // ...


Regardless of whether GCC wants to handle this example or not, implicit
signed-to-unsigned conversion looks wrong to me. Even an assertion failure from
the compiler is better than this silent code corruption. Furthermore, can we
even guess all the possible cases when the problematic path is taken?


Full backtrace:

Breakpoint 15, extract_split_bit_field (op0=0x7ffff6cb7c60, op0_mode=...,
bitsize=64, bitpos=18446744073709551552, unsignedp=0, reverse=false)            
    at ../../gcc/gcc/expmed.c:2266
2266          thispos = (bitpos + bitsdone) % unit;
(gdb) bt
#0  extract_split_bit_field (op0=0x7ffff6cb7c60, op0_mode=..., bitsize=64,
bitpos=18446744073709551552, unsignedp=0, reverse=false) at
../../gcc/gcc/expmed.c:2266       
#1  0x0000000000aafff7 in extract_fixed_bit_field (tmode=E_DImode,
op0=0x7ffff6cb7c60, op0_mode=..., bitsize=64, bitnum=18446744073709551552,
target=0x7ffff6cb7bb8,     
    unsignedp=0, reverse=false) at ../../gcc/gcc/expmed.c:2125
#2  0x0000000000aaf793 in extract_integral_bit_field (op0=0x7ffff6cb7c60,
op0_mode=..., bitsize=64, bitnum=18446744073709551552, unsignedp=0,
target=0x7ffff6cb7bb8,     
    mode=E_DImode, tmode=E_DImode, reverse=false, fallback_p=true) at
../../gcc/gcc/expmed.c:2016                                                     
#3  0x0000000000aaeb74 in extract_bit_field_1 (str_rtx=0x7ffff6cb7c60,
bitsize=..., bitnum=..., unsignedp=0, target=0x7ffff6cb7bb8, mode=E_DImode,
tmode=E_DImode,       
    reverse=false, fallback_p=true, alt_rtl=0x0) at ../../gcc/gcc/expmed.c:1827
#4  0x0000000000aafe8c in extract_bit_field (str_rtx=0x7ffff6cb7c60,
bitsize=..., bitnum=..., unsignedp=0, target=0x7ffff6cb7bb8, mode=E_DImode,
tmode=E_DImode,         
    reverse=false, alt_rtl=0x0) at ../../gcc/gcc/expmed.c:2096
#5  0x0000000000aecaff in expand_expr_real_1 (exp=0x7ffff6ca6840,
target=0x7ffff6cb7bb8, tmode=E_DImode, modifier=EXPAND_NORMAL, alt_rtl=0x0,
inner_reference_p=false)   
    at ../../gcc/gcc/expr.c:10777
#6  0x0000000000adfef9 in expand_expr_real (exp=0x7ffff6ca6840,
target=0x7ffff6cb7bb8, tmode=E_DImode, modifier=EXPAND_NORMAL, alt_rtl=0x0,
inner_reference_p=false)     
    at ../../gcc/gcc/expr.c:8186
#7  0x0000000000ae799e in expand_expr_real_1 (exp=0x7ffff6b9f558,
target=0x7ffff6cb7bb8, tmode=E_DImode, modifier=EXPAND_NORMAL, alt_rtl=0x0,
inner_reference_p=false)   
    at ../../gcc/gcc/expr.c:9838
#8  0x0000000000adfef9 in expand_expr_real (exp=0x7ffff6b9f558,
target=0x7ffff6cb7bb8, tmode=E_DImode, modifier=EXPAND_NORMAL, alt_rtl=0x0,
inner_reference_p=false)     
    at ../../gcc/gcc/expr.c:8186
#9  0x000000000094d615 in expand_expr (exp=0x7ffff6b9f558,
target=0x7ffff6cb7bb8, mode=E_DImode, modifier=EXPAND_NORMAL) at
../../gcc/gcc/expr.h:279                     
#10 0x00000000009590b0 in expand_return (retval=0x7ffff6c85f50) at
../../gcc/gcc/cfgexpand.c:3504                                                  
#11 0x0000000000959507 in expand_gimple_stmt_1 (stmt=0x7ffff6cae000) at
../../gcc/gcc/cfgexpand.c:3607                                                  
#12 0x0000000000959a87 in expand_gimple_stmt (stmt=0x7ffff6cae000) at
../../gcc/gcc/cfgexpand.c:3734                                                  
#13 0x000000000096239c in expand_gimple_basic_block (bb=0x7ffff6c8b138,
disable_tail_calls=false) at ../../gcc/gcc/cfgexpand.c:5769                     
#14 0x0000000000963bd4 in (anonymous namespace)::pass_expand::execute
(this=0x233f680, fun=0x7ffff6ca9000) at ../../gcc/gcc/cfgexpand.c:6372          
#15 0x0000000000e4f77e in execute_one_pass (pass=0x233f680) at
../../gcc/gcc/passes.c:2446                                                     
#16 0x0000000000e4fae3 in execute_pass_list_1 (pass=0x233f680) at
../../gcc/gcc/passes.c:2535                                                     
#17 0x0000000000e4fb6c in execute_pass_list (fn=0x7ffff6ca9000, pass=0x233ba50)
at ../../gcc/gcc/passes.c:2546                                                  
#18 0x00000000009b225b in cgraph_node::expand (this=0x7ffff6cab000) at
../../gcc/gcc/cgraphunit.c:2116                                                 
#19 0x00000000009b28a0 in expand_all_functions () at
../../gcc/gcc/cgraphunit.c:2254
#20 0x00000000009b347d in symbol_table::compile (this=0x7ffff6b99000) at
../../gcc/gcc/cgraphunit.c:2605                                                 
#21 0x00000000009b3714 in symbol_table::finalize_compilation_unit
(this=0x7ffff6b99000) at ../../gcc/gcc/cgraphunit.c:2698                        
#22 0x0000000000f9636c in compile_file () at ../../gcc/gcc/toplev.c:480
#23 0x0000000000f98d72 in do_compile () at ../../gcc/gcc/toplev.c:2161
#24 0x0000000000f99081 in toplev::main (this=0x7fffffffcf66, argc=17,
argv=0x7fffffffd068) at ../../gcc/gcc/toplev.c:2296                             
#25 0x0000000001928030 in main (argc=17, argv=0x7fffffffd068) at
../../gcc/gcc/main.c:39


More information about the Gcc-bugs mailing list