Bug 52078 - Bogus may be used uninitialized warning
Summary: Bogus may be used uninitialized warning
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Wuninitialized
  Show dependency treegraph
 
Reported: 2012-02-01 02:37 UTC by Ryan Mansfield
Modified: 2017-03-31 18:12 UTC (History)
2 users (show)

See Also:
Host: x86_64-linux-gnu
Target: x86_64-linux-gnu
Build: x86_64-linux-gnu
Known to work:
Known to fail:
Last reconfirmed: 2012-02-01 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ryan Mansfield 2012-02-01 02:37:52 UTC
gcc version 4.7.0 20120201 (experimental) [trunk revision 183790] (GCC) 

Testcase:

#include <string.h>

int
foo (char *nname, char *oname)
{
  int cmp;

  while (nname != oname && (cmp = strcmp (nname, oname)) < 0)
    {
      break;
    }
  if (nname == oname || cmp == 0)
    {
      return 1;
    }
  else
    {
      return 0;
    }
}


$ ./xgcc -B. -O2 -Wall ~/init.c -c 
/home/ryan/init.c: In function 'foo':
/home/ryan/init.c:12:29: warning: 'cmp' may be used uninitialized in this function [-Wmaybe-uninitialized]

Since both && and || operators guarantee left-to-right evaluation, in the case where nname == oname, strcmp is never called but in the (name == oname || cmp == 0) expression, nname == oname and the second operand is not evaluated so cmp is never used uninitialized.
Comment 1 Manuel López-Ibáñez 2012-02-01 08:17:27 UTC
I haven't followed development for a while, but I don't think GCC uninit analysis is powerful enough to detect this or even simpler cases like PR36550 and PR20968.
Comment 2 Richard Biener 2012-02-01 09:28:49 UTC
Yeah, it's simply too confusing code for GCCs static analysis.  Thus the "may be used uninitialized".
Comment 3 Jeffrey A. Law 2017-03-31 18:12:25 UTC
If we look at the VRP dump after ASSERT_EXPR insertion it's obvious what needs to happen here:

;   basic block 2, loop depth 0, count 0, freq 10000, maybe hot
;;    prev block 0, next block 7, flags: (NEW, REACHABLE, VISITED)
;;    pred:       ENTRY [100.0%]  (FALLTHRU,EXECUTABLE)
  if (nname_6(D) != oname_7(D))
    goto <bb 3>; [70.00%]
  else
    goto <bb 7>; [30.00%]
;;    succ:       3 [70.0%]  (TRUE_VALUE,EXECUTABLE)
;;                7 [30.0%]  (FALSE_VALUE,EXECUTABLE)

;;   basic block 7, loop depth 0, count 0, freq 3000, maybe hot
;;    prev block 2, next block 3, flags: (NEW)
;;    pred:       2 [30.0%]  (FALSE_VALUE,EXECUTABLE)
  nname_12 = ASSERT_EXPR <nname_6(D), nname_6(D) == oname_7(D)>;
  oname_15 = ASSERT_EXPR <oname_7(D), oname_7(D) == nname_12>;
  goto <bb 4>; [100.00%]
;;    succ:       4 [100.0%]  (FALLTHRU)

;;   basic block 3, loop depth 0, count 0, freq 7000, maybe hot
;;    prev block 7, next block 4, flags: (NEW, REACHABLE, VISITED)
;;    pred:       2 [70.0%]  (TRUE_VALUE,EXECUTABLE)
  nname_11 = ASSERT_EXPR <nname_6(D), nname_6(D) != oname_7(D)>;
  oname_14 = ASSERT_EXPR <oname_7(D), oname_7(D) != nname_11>;
  _10 = __builtin_strcmp (nname_11, oname_14);
  oname_16 = ASSERT_EXPR <oname_14, oname_14 != 0B>;
  nname_13 = ASSERT_EXPR <nname_11, nname_11 != 0B>;
;;    succ:       4 [100.0%]  (FALLTHRU,EXECUTABLE)

;;   basic block 4, loop depth 0, count 0, freq 10000, maybe hot
;;    prev block 3, next block 5, flags: (NEW, REACHABLE, VISITED)
;;    pred:       3 [100.0%]  (FALLTHRU,EXECUTABLE)
;;                7 [100.0%]  (FALLTHRU)
  # cmp_4 = PHI <_10(3), cmp_8(D)(7)>
  _1 = nname_6(D) == oname_7(D);
  _2 = cmp_4 == 0;
  _3 = _1 | _2;
  if (_3 != 0)
    goto <bb 6>; [46.00%]
  else
    goto <bb 5>; [54.00%]
;;    succ:       6 [46.0%]  (TRUE_VALUE,EXECUTABLE)
;;                5 [54.0%]  (FALSE_VALUE,EXECUTABLE)

If we traverse the edge 2->7, then we know that nname == oname (which is shown in the IL via the ASSERT_EXPRs in BB7).    We can use that to simplify the computation of _3 in BB4 and ultimately thread 2->7->6 and eliminate the test of cmp_4 on the threaded path (it becomes dead).

That eliminates the uninitialized use.

This is fixed on the trunk, most likely due to the work for pr71437 which looks to exploit ASSERT_EXPRs more aggressively.