[Bug sanitizer/112727] New: UBSAN creates GIMPLE path with uninitialized variable
sirl at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Mon Nov 27 13:28:04 GMT 2023
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112727
Bug ID: 112727
Summary: UBSAN creates GIMPLE path with uninitialized variable
Product: gcc
Version: 14.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: sanitizer
Assignee: unassigned at gcc dot gnu.org
Reporter: sirl at gcc dot gnu.org
CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org,
jakub at gcc dot gnu.org, kcc at gcc dot gnu.org, marxin at gcc dot gnu.org
Target Milestone: ---
Hi,
this simple code:
struct Cfg_t
{
bool bX[8];
};
void Encode(const Cfg_t* pCfg)
{
unsigned nCfg = 0;
for (unsigned j = 0; j < 8; j++) {
nCfg |= ((!pCfg->bX[j])?1:0) << (16 + j);
}
}
compiled with "gcc-trunk@r14+5779 -c -O2 -fsanitize=undefined
-fno-sanitize=shift-base -fsanitize=bounds-strict -Wuninitialized"
issues this warning:
gcc_wuninitialized_bug.cpp: In function 'void Encode(const Cfg_t*)':
gcc_wuninitialized_bug.cpp:11:38: warning: 'j.1' is used uninitialized
[-Wuninitialized]
11 | nCfg |= ((!pCfg->bX[j])?1:0) << (16 + j);
| ~~~~~~~~~~^
gcc_wuninitialized_bug.cpp:11:38: note: 'j.1' was declared here
11 | nCfg |= ((!pCfg->bX[j])?1:0) << (16 + j);
| ~~~~~~~~~~^
This is a regression starting with gcc-9. gcc-7 and gcc-8 don't create an
invalid path and thus don't warn.
With -fdump-tree-all the .original dump looks like this:
{
unsigned int nCfg = 0;
<<cleanup_point unsigned int nCfg = 0;>>;
{
unsigned int j = 0;
<<cleanup_point unsigned int j = 0;>>;
goto <D.3254>;
<D.3253>:;
<<cleanup_point <<< Unknown tree: expr_stmt
(void) (nCfg = TARGET_EXPR <D.3250, if (SAVE_EXPR <j + 16>;, SAVE_EXPR <j
+ 16> > 31;)
{
__builtin___ubsan_handle_shift_out_of_bounds (&*.Lubsan_data0, (bool)
pCfg->bX[.UBSAN_BOUNDS (0B, SAVE_EXPR <j>, 8);, SAVE_EXPR <j>;] ? 0 : 1,
(unsigned long) (SAVE_EXPR <j + 16>));
}
else
{
<<< Unknown tree: void_cst >>>
}, ((bool) pCfg->bX[.UBSAN_BOUNDS (0B, SAVE_EXPR <j>, 8);, SAVE_EXPR
<j>;] ? 0 : 1) << SAVE_EXPR <j + 16>;>;, nCfg | (unsigned int) D.3250;) >>>>>;
<<cleanup_point (void) j++ >>;
<D.3254>:;
if (j <= 7) goto <D.3253>; else goto <D.3251>;
<D.3251>:;
}
}
And then in the .gimple dump:
void Encode (const struct Cfg_t * pCfg)
{
int D.3250;
unsigned int D.3255;
unsigned long iftmp.0;
unsigned int j.1;
int iftmp.2;
unsigned int nCfg;
nCfg = 0;
{
unsigned int j;
j = 0;
goto <D.3254>;
<D.3253>:
D.3255 = j + 16;
if (D.3255 > 31) goto <D.3256>; else goto <D.3257>;
<D.3256>:
_1 = (unsigned long) D.3255;
j.1 = j;
.UBSAN_BOUNDS (0B, j.1, 8);
_2 = pCfg->bX[j.1];
if (_2 != 0) goto <D.3260>; else goto <D.3261>;
<D.3260>:
iftmp.0 = 0;
goto <D.3262>;
<D.3261>:
iftmp.0 = 1;
<D.3262>:
__builtin___ubsan_handle_shift_out_of_bounds (&*.Lubsan_data0, iftmp.0,
_1);
goto <D.3263>;
<D.3257>:
<D.3263>:
.UBSAN_BOUNDS (0B, j.1, 8);
_3 = pCfg->bX[j.1];
if (_3 != 0) goto <D.3265>; else goto <D.3266>;
<D.3265>:
iftmp.2 = 0;
goto <D.3267>;
<D.3266>:
iftmp.2 = 1;
<D.3267>:
D.3250 = iftmp.2 << D.3255;
_4 = (unsigned int) D.3250;
nCfg = nCfg | _4;
j = j + 1;
<D.3254>:
if (j <= 7) goto <D.3253>; else goto <D.3251>;
<D.3251>:
}
}
Clearly j.1 is initialized from j only in the D.3256 branch, the D.3257 branch
misses the initialization.
More information about the Gcc-bugs
mailing list