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

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
           Keywords|                            |diagnostic
   Last reconfirmed|                            |2020-03-03
          Component|c                           |tree-optimization
                 CC|                            |msebor at gcc dot gnu.org
             Blocks|                            |85741
     Ever confirmed|0                           |1
            Summary|-Werror=format-truncation=  |-Wformat-truncation false
                   |seems to cause incorrect    |positive due to excessive
                   |warning, thus error.        |integer range
      Known to fail|                            |10.0, 9.2.0

--- Comment #4 from Martin Sebor <msebor at gcc dot gnu.org> ---
Confirmed with the small test case below.  The warning code works correctly but
the integer conditionals are somehow confusing EVRP into thinking h's range is
[0, 596523], which causes the warning to trigger.  The dump shows that the
warning thinks the result of the first %02i directive is between 2 and 6
characters:

  Directive 2 at offset 2: "%02i"
    Result: 2, 6, 6, 6 (3, 7, 7, 7)

$ cat pr94021.c && gcc -O2 -S -Wall -fdump-tree-strlen=/dev/stdout pr94021.c
char a[8];

void format_utc_offset (int x)
{
  if (x < 0)
    x = -x;

  int h = x / 3600, m = (x % 3600) / 60;

  if (h < 0 || h >= 24 || m < 0 || m >= 60)
    __builtin_puts ("");

  if (0 <= m && m <= 60 && 0 <= h && h <= 24)
    __builtin_snprintf (a, sizeof a, "%s%02i%02i", "+", h, m);
}

;; Function format_utc_offset (format_utc_offset, funcdef_no=0, decl_uid=1931,
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 5 6
;; 2 succs { 3 6 }
;; 3 succs { 6 }
;; 4 succs { 5 }
;; 5 succs { 1 }
;; 6 succs { 4 5 }
pr94021.c:14: __builtin_snprintf: objsize = 8, fmtstr = "%s%02i%02i"
  Directive 1 at offset 0: "%s"
    Result: 1, 1, 1, 1 (1, 1, 1, 1)
  Directive 2 at offset 2: "%02i"
    Result: 2, 6, 6, 6 (3, 7, 7, 7)
  Directive 3 at offset 6: "%02i"
pr94021.c: In function ‘format_utc_offset’:
pr94021.c:14:45: warning: ‘%02i’ directive output may be truncated writing 2
bytes into a region of size between 1 and 5 [-Wformat-truncation=]
   14 |     __builtin_snprintf (a, sizeof a, "%s%02i%02i", "+", h, m);
      |                                             ^~~~
pr94021.c:14:38: note: directive argument in the range [0, 59]
   14 |     __builtin_snprintf (a, sizeof a, "%s%02i%02i", "+", h, m);
      |                                      ^~~~~~~~~~~~
    Result: 2, 2, 2, 2 (5, 9, 9, 9)
  Directive 4 at offset 10: "", length = 1
pr94021.c:14:5: note: ‘__builtin_snprintf’ output between 6 and 10 bytes into a
destination of size 8
   14 |     __builtin_snprintf (a, sizeof a, "%s%02i%02i", "+", h, m);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Moving the test for hours etc. being out-of-bounds after the test for them
being in-bounds avoids the warning (and streamlines the code so it seems like
an overall improvement).


Referenced Bugs:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85741
[Bug 85741] [meta-bug] bogus/missing -Wformat-overflow

Reply via email to