https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78969
Bug ID: 78969
Summary: bogus snprintf truncation warning due to missing range
info
Product: gcc
Version: 7.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: msebor at gcc dot gnu.org
Target Milestone: ---
In both functions in the following test case the %3u argument to snprintf is in
the range [0, 999] and so the directive writes exactly 3 bytes into the
destination buffer of size 4. As the VRP dump shows, GCC exposes that range to
the -Wformat-length checker via the get_range_info() function in the call in
function f() allowing it to avoid a warning. But in the call in function g(),
even though the same range is also known, it's not made available for the
argument to the directive, resulting in a false positive.
$ cat t.c && gcc -O2 -S -Wall -Wformat-length=2 -fdump-tree-vrp=/dev/stdout t.c
void f (unsigned j, char *p)
{
if (j > 999)
j = 0;
__builtin_snprintf (p, 4, "%3u", j);
}
void g (unsigned j, char *p)
{
if (j > 999)
return;
__builtin_snprintf (p, 4, "%3u", j);
}
;; Function f (f, funcdef_no=0, decl_uid=1796, cgraph_uid=0, symbol_order=0)
;; 1 loops found
;;
;; Loop 0
;; header 0, latch 1
;; depth 0, outer -1
;; nodes: 0 1 2 3 4
;; 2 succs { 3 4 }
;; 3 succs { 4 }
;; 4 succs { 1 }
SSA replacement table
N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j
j_6 -> { j_2(D) }
j_7 -> { j_2(D) }
Incremental SSA update started at block: 2
Number of blocks in CFG: 6
Number of blocks to update: 4 ( 67%)
Value ranges after VRP:
j_1: [0, 999] EQUIVALENCES: { } (0 elements)
j_2(D): VARYING
j_6: [1000, +INF] EQUIVALENCES: { j_2(D) } (1 elements)
j_7: [0, 999] EQUIVALENCES: { j_2(D) } (1 elements)
Removing basic block 3
f (unsigned int j, char * p)
{
<bb 2> [100.00%]:
if (j_2(D) > 999)
goto <bb 4>; [54.00%]
else
goto <bb 3>; [46.00%]
<bb 3> [46.00%]:
<bb 4> [100.00%]:
# j_1 = PHI <j_2(D)(3), 0(2)>
__builtin_snprintf (p_4(D), 4, "%3u", j_1);
return;
}
;; Function f (f, funcdef_no=0, decl_uid=1796, cgraph_uid=0, symbol_order=0)
;; 1 loops found
;;
;; Loop 0
;; header 0, latch 1
;; depth 0, outer -1
;; nodes: 0 1 2 3 4
;; 2 succs { 3 4 }
;; 3 succs { 4 }
;; 4 succs { 1 }
SSA replacement table
N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j
j_6 -> { j_2(D) }
j_7 -> { j_2(D) }
Incremental SSA update started at block: 2
Number of blocks in CFG: 6
Number of blocks to update: 4 ( 67%)
Value ranges after VRP:
j_1: [0, 999] EQUIVALENCES: { } (0 elements)
j_2(D): VARYING
j_6: [1000, +INF] EQUIVALENCES: { j_2(D) } (1 elements)
j_7: [0, 999] EQUIVALENCES: { j_2(D) } (1 elements)
Removing basic block 3
f (unsigned int j, char * p)
{
<bb 2> [100.00%]:
if (j_2(D) > 999)
goto <bb 4>; [54.00%]
else
goto <bb 3>; [46.00%]
<bb 3> [46.00%]:
<bb 4> [100.00%]:
# j_1 = PHI <j_2(D)(3), 0(2)>
__builtin_snprintf (p_4(D), 4, "%3u", j_1);
return;
}
;; Function g (g, funcdef_no=1, decl_uid=1800, cgraph_uid=1, symbol_order=1)
;; 1 loops found
;;
;; Loop 0
;; header 0, latch 1
;; depth 0, outer -1
;; nodes: 0 1 2 3 4
;; 2 succs { 4 3 }
;; 3 succs { 4 }
;; 4 succs { 1 }
SSA replacement table
N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j
j_6 -> { j_2(D) }
Incremental SSA update started at block: 2
Number of blocks in CFG: 5
Number of blocks to update: 2 ( 40%)
Value ranges after VRP:
.MEM_1: VARYING
j_2(D): VARYING
j_6: [0, 999] EQUIVALENCES: { j_2(D) } (1 elements)
g (unsigned int j, char * p)
{
<bb 2> [100.00%]:
if (j_2(D) > 999)
goto <bb 4>; [51.01%]
else
goto <bb 3>; [48.99%]
<bb 3> [48.99%]:
__builtin_snprintf (p_4(D), 4, "%3u", j_2(D));
<bb 4> [100.00%]:
return;
}
t.c: In function āgā:
t.c:14:30: warning: ā%3uā directive output may be truncated writing between 3
and 10 bytes into a region of size 4 [-Wformat-length=]
__builtin_snprintf (p, 4, "%3u", j);
^~~
t.c:14:29: note: using the range [1, 4294967295] for directive argument
__builtin_snprintf (p, 4, "%3u", j);
^~~~~
t.c:14:3: note: format output between 4 and 11 bytes into a destination of size
4
__builtin_snprintf (p, 4, "%3u", j);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;; Function g (g, funcdef_no=1, decl_uid=1800, cgraph_uid=1, symbol_order=1)
;; 1 loops found
;;
;; Loop 0
;; header 0, latch 1
;; depth 0, outer -1
;; nodes: 0 1 2 3 4
;; 2 succs { 4 3 }
;; 3 succs { 4 }
;; 4 succs { 1 }
SSA replacement table
N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j
j_6 -> { j_2(D) }
Incremental SSA update started at block: 2
Number of blocks in CFG: 5
Number of blocks to update: 2 ( 40%)
Value ranges after VRP:
.MEM_1: VARYING
j_2(D): VARYING
j_6: [0, 999] EQUIVALENCES: { j_2(D) } (1 elements)
g (unsigned int j, char * p)
{
<bb 2> [100.00%]:
if (j_2(D) > 999)
goto <bb 4>; [51.01%]
else
goto <bb 3>; [48.99%]
<bb 3> [48.99%]:
__builtin_snprintf (p_4(D), 4, "%3u", j_2(D));
<bb 4> [100.00%]:
return;
}