Index: clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -304,6 +304,8 @@ auto R = llvm::make_unique(*BT, os.str(), N); R->addRange(ArgRange); + if (ArgEx) + bugreporter::trackNullOrUndefValue(N, ArgEx, *R); // FIXME: enhance track back for uninitialized value for arbitrary // memregions C.emitReport(std::move(R)); Index: clang/test/Analysis/uninit-vals-ps-region.m =================================================================== --- clang/test/Analysis/uninit-vals-ps-region.m +++ clang/test/Analysis/uninit-vals-ps-region.m @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core -verify %s +// RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core -analyzer-output=text -verify %s struct s { int data; @@ -24,19 +24,22 @@ void test_uninit_pos() { struct TestUninit v1 = { 0, 0 }; struct TestUninit v2 = test_uninit_aux(); - int z; + int z; // expected-note{{'z' declared without an initial value}} v1.y = z; // expected-warning{{Assigned value is garbage or undefined}} + // expected-note@-1{{Assigned value is garbage or undefined}} test_unit_aux2(v2.x + v1.y); } void test_uninit_pos_2() { struct TestUninit v1 = { 0, 0 }; struct TestUninit v2; test_unit_aux2(v2.x + v1.y); // expected-warning{{The left operand of '+' is a garbage value}} + // expected-note@-1{{The left operand of '+' is a garbage value}} } void test_uninit_pos_3() { struct TestUninit v1 = { 0, 0 }; struct TestUninit v2; test_unit_aux2(v1.y + v2.x); // expected-warning{{The right operand of '+' is a garbage value}} + // expected-note@-1{{The right operand of '+' is a garbage value}} } void test_uninit_neg() { @@ -47,16 +50,18 @@ extern void test_uninit_struct_arg_aux(struct TestUninit arg); void test_uninit_struct_arg() { - struct TestUninit x; + struct TestUninit x; // expected-note{{'x' initialized here}} test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} + // expected-note@-1{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} } @interface Foo - (void) passVal:(struct TestUninit)arg; @end void testFoo(Foo *o) { - struct TestUninit x; + struct TestUninit x; // expected-note{{'x' initialized here}} [o passVal:x]; // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} + // expected-note@-1{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} } // Test case from . That shows an uninitialized value @@ -65,6 +70,7 @@ typedef struct s_r7780304 { int x; } s_r7780304; s_r7780304 b; b.x |= 1; // expected-warning{{The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage}} + // expected-note@-1{{The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage}} } @@ -74,6 +80,7 @@ void PR10163 (void) { float x[2]; test_PR10163(x[1]); // expected-warning{{uninitialized value}} + // expected-note@-1{{1st function call argument is an uninitialized value}} } struct MyStr { @@ -83,11 +90,13 @@ void swap(struct MyStr *To, struct MyStr *From) { // This is not really a swap but close enough for our test. To->x = From->x; - To->y = From->y; // no warning + To->y = From->y; // expected-note{{Uninitialized value stored to field 'y'}} } int test_undefined_member_assignment_in_swap(struct MyStr *s2) { struct MyStr s1; s1.x = 5; - swap(s2, &s1); + swap(s2, &s1); // expected-note{{Calling 'swap'}} + // expected-note@-1{{Returning from 'swap'}} return s2->y; // expected-warning{{Undefined or garbage value returned to caller}} + // expected-note@-1{{Undefined or garbage value returned to caller}} }