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

Jeffrey A. Law <law at redhat dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |law at redhat dot com

--- Comment #21 from Jeffrey A. Law <law at redhat dot com> ---
Sorry, but when I look at this, the warning seems correct and valid to me.

In the .fre1 dump we have:

;;   basic block 2, loop depth 0, maybe hot
;;    prev block 0, next block 3, flags: (NEW, VISITED)
;;    pred:       ENTRY (FALLTHRU,EXECUTABLE)
  f.1_1 = f;
  _10 = f.1_1 + 1;
  if (_10 != 0)
    goto <bb 3>; [INV]
  else
    goto <bb 4>; [INV]
;;    succ:       3 (TRUE_VALUE,EXECUTABLE)
;;                4 (FALSE_VALUE,EXECUTABLE)

;;   basic block 3, loop depth 0, maybe hot
;;    prev block 2, next block 4, flags: (NEW, VISITED)
;;    pred:       2 (TRUE_VALUE,EXECUTABLE)
  iftmp.0_11 = (char) _10;
  goto <bb 5>; [INV]
;;    succ:       5 (FALLTHRU,EXECUTABLE)

;;   basic block 4, loop depth 0, maybe hot
;;    prev block 3, next block 5, flags: (NEW, VISITED)
;;    pred:       2 (FALSE_VALUE,EXECUTABLE)
  iftmp.0_12 = (char) f.1_1;
;;    succ:       5 (FALLTHRU,EXECUTABLE)

;;   basic block 5, loop depth 0, maybe hot
;;    prev block 4, next block 6, flags: (NEW, VISITED)
;;    pred:       3 (FALLTHRU,EXECUTABLE)
;;                4 (FALLTHRU,EXECUTABLE)
  # iftmp.0_7 = PHI <iftmp.0_11(3), iftmp.0_12(4)>
  _4 = (long unsigned int) f.1_1;
  x.4_5 = x;
  c.5_6 = c;
  __builtin_strncpy (c.5_6, x.4_5, _4);

In particular note the conditional at the end of bb2 and the dataflow when _10
is zero.  WHen that occurs we'll go to bb4 and we'll know that f.1_1 must have
the value -1.   WHich in turn means iftmp_0.12 has the value -1 which flows
into the PHI at the start of BB5.  We see all this in the .evrp dump:

;;   basic block 2, loop depth 0, maybe hot
;;    prev block 0, next block 3, flags: (NEW, VISITED)
;;    pred:       ENTRY (FALLTHRU,EXECUTABLE)
  f.1_1 = f;
  _10 = f.1_1 + 1;
  if (_10 != 0)
    goto <bb 3>; [INV]
  else
    goto <bb 4>; [INV]
;;    succ:       3 (TRUE_VALUE,EXECUTABLE)
;;                4 (FALSE_VALUE,EXECUTABLE)

;;   basic block 3, loop depth 0, maybe hot
;;    prev block 2, next block 4, flags: (NEW, VISITED)
;;    pred:       2 (TRUE_VALUE,EXECUTABLE)
  iftmp.0_11 = (char) _10;
;;    succ:       4 (FALLTHRU,EXECUTABLE)

;;   basic block 4, loop depth 0, maybe hot
;;    prev block 3, next block 5, flags: (NEW, VISITED)
;;    pred:       3 (FALLTHRU,EXECUTABLE)
;;                2 (FALSE_VALUE,EXECUTABLE)
  # iftmp.0_7 = PHI <iftmp.0_11(3), -1(2)>
  _4 = (long unsigned int) f.1_1;
  x.4_5 = x;
  c.5_6 = c;
  __builtin_strncpy (c.5_6, x.4_5, _4);
  if (iftmp.0_7 != 0)
    goto <bb 5>; [INV]
  else
    goto <bb 6>; [INV]


Jump threading will want to optimize away the test at the end of bb4, so it
duplicates bb4 isolating each incoming edge.  The duplicate for the edge 2->4
will look like:

;;   basic block 6, loop depth 0, count 536870912 (estimated locally), maybe
hot
;;    prev block 5, next block 1, flags: (NEW, VISITED)
;;    pred:       2 [50.0% (guessed)]  count:536870912 (estimated locally)
(FALSE_VALUE,EXECUTABLE)
  # _17 = PHI <-1(2)>
  iftmp.0_18 = (char) _17;
  _19 = (long unsigned int) f.1_1;
  x.4_20 = x;
  c.5_21 = c;
  __builtin_strncpy (c.5_21, x.4_20, _19);
  goto <bb 4>; [100.00%]
;;    succ:       4 [always (guessed)]  count:536870912 (estimated locally)
(FALLTHRU)


Which is exactly what we want and highlights the error in the original user
code.  Namely that when f+1 is zero we'll make a totally bogus call to strncpy.

Suppressing warnings per Jakub's comment in c#10 would just hide the fact that
the user's code is just plain broken.  If you find yourself blaming threading
for exposing a warning like this, you're barking up the wrong tree Jakub.  
Threading is just exposing what's already broken in the user's original code
and we absolutely do want these warnings.

Reply via email to