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;

}

Reply via email to