Bug 83382 - UBSAN triggers false-positive warning [-Werror=uninitialized]
Summary: UBSAN triggers false-positive warning [-Werror=uninitialized]
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: sanitizer (show other bugs)
Version: 8.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Wuninitialized 99945 yarpgen
  Show dependency treegraph
 
Reported: 2017-12-12 01:50 UTC by Dmitry Babokin
Modified: 2024-06-15 01:48 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 10.2.0, 11.0, 8.3.0, 9.3.0
Last reconfirmed: 2021-04-06 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dmitry Babokin 2017-12-12 01:50:36 UTC
gcc trunk, rev 255537, x86_64.

Not sure if this is duplicate of #42145 or not, so filing as a separate bug.

The issue goes away if either sanitizer flags removed, "extern" removed from tf_0_var_14 definition, or "const" removed from the same definition. Though it points to different variable. So, something fishy is going on here.

You may argue that this analysis is inexact and I shouldn't rely on that, but it's definitely usability bug, when unrelated things are causing troubles. And it stops me from using -Werror=uninitialized in test case reduction, where it really does useful job. 

> cat f.cpp
int tf_0_var_36;
signed char tf_0_var_58;
extern const int tf_0_var_14;
int *tf_0_ptr_8;
void tf_0_foo() {
  tf_0_var_36 >> ((!0 || tf_0_var_58) && (0 ? tf_0_var_14 : *tf_0_ptr_8));
}

> g++  -std=c++11 -fsanitize=undefined -Werror=uninitialized -o ubsan_gcc_o2_func.o -c f.cpp
f.cpp: In function ‘void tf_0_foo()’:
f.cpp:6:72: error: ‘tf_0_ptr_8.1’ is used uninitialized in this function [-Werror=uninitialized]
   tf_0_var_36 >> ((!0 || tf_0_var_58) && (0 ? tf_0_var_14 : *tf_0_ptr_8));
                                                                        ^
cc1plus: some warnings being treated as errors
Comment 1 Richard Biener 2017-12-12 08:58:21 UTC
The interaction between sanitizers and middle-end emitted warnings is difficult at best.  Can you avoid -Werror when sanitizing?
Comment 2 Dmitry Babokin 2017-12-12 19:27:02 UTC
(In reply to Richard Biener from comment #1)
> The interaction between sanitizers and middle-end emitted warnings is
> difficult at best.  Can you avoid -Werror when sanitizing?

I can, if it's absolutely needed. But it's convenient. I use it in creduce as a criteria that reduction haven't introduced undefined behavior. UBSAN doesn't catch uninitialized variables, so I have to add this switch. An alternative is to have two separate runs.
Comment 3 Martin Sebor 2021-04-06 23:38:48 UTC
Reconfirmed with GCC 11.  The warning sees the IL below and triggers for the call to .UBSAN_NULL() after the CFG pass has removed the initialization of p.1.  A simple way to avoid it is to suppress warnings for calls to the sanitizer internal functions.

Interestingly, this bug is only reproducible with C++, not when the same code is compiled as C.

$ gcc -O0 -S -Wall -fsanitize=undefined -fdump-tree-cfg-details=/dev/stdout -xc++ pr83382.c
pr83382.c: In function ‘void f()’:
pr83382.c:6:5: warning: value computed is not used [-Wunused-value]
    6 |   i >> ((!0 || c) && (0 ? j : *p));
      |   ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

;; Function f (_Z1fv, funcdef_no=0, decl_uid=2788, cgraph_uid=1, symbol_order=5)

Scope blocks:

{ Scope block #0 

}
Removing basic block 3
;; basic block 3, loop depth 0
;;  pred:      
p.1 = p;                      <<< initialization removed
.UBSAN_NULL (p.1, 2B, 4);
_1 = MEM[(const int &)p.1];
_2 = _1 != 0;
_3 = (int) _2;
_4 = (unsigned long) _3;
_5 = (unsigned long) i.0;
__builtin___ubsan_handle_shift_out_of_bounds (&*.Lubsan_data0, _5, _4);
;;  succ:       4


;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2 3
;; 2 succs { 3 }
;; 3 succs { 1 }
void f ()
{
  int * p.1;                  <<< not initialized
  int i.0;

  <bb 2> :
  i.0 = i;

  <bb 3> :
  .UBSAN_NULL (p.1, 2B, 4);   <<< -Wuninitialized
  _6 = MEM[(const int &)p.1];
  _7 = _6 != 0;
  _8 = (int) _7;
  return;

}


pr83382.c:6:25: warning: ‘p.1’ is used uninitialized [-Wuninitialized]
    6 |   i >> ((!0 || c) && (0 ? j : *p));
      |                      ~~~^~~~~~~~~
pr83382.c:6:25: note: ‘p.1’ was declared here
    6 |   i >> ((!0 || c) && (0 ? j : *p));
      |                      ~~~^~~~~~~~~