[clang] ab58238 - [analyzer] Find better description for tracked symbolic values
Valeriy Savchenko via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 28 08:38:20 PDT 2021
Author: Valeriy Savchenko
Date: 2021-04-28T18:37:38+03:00
New Revision: ab5823867c4aee7f3e02ddfaa217905c87471bf9
URL: https://github.com/llvm/llvm-project/commit/ab5823867c4aee7f3e02ddfaa217905c87471bf9
DIFF: https://github.com/llvm/llvm-project/commit/ab5823867c4aee7f3e02ddfaa217905c87471bf9.diff
LOG: [analyzer] Find better description for tracked symbolic values
When searching for stores and creating corresponding notes, the
analyzer is more specific about the target region of the store
as opposed to the stored value. While this description was tweaked
for constant and undefined values, it lacked in the most general
case of symbolic values.
This patch tries to find a memory region, where this value is stored,
to use it as a better alias for the value.
rdar://76645710
Differential Revision: https://reviews.llvm.org/D101041
Added:
Modified:
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
clang/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
clang/test/Analysis/osobject-retain-release.cpp
clang/test/Analysis/retain-release-path-notes.m
clang/test/Analysis/uninit-const.c
clang/test/Analysis/uninit-const.cpp
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index fd334b0bc9c36..c0526469909b3 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -153,6 +153,28 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) {
return E;
}
+static const MemRegion *
+getLocationRegionIfReference(const Expr *E, const ExplodedNode *N,
+ bool LookingForReference = true) {
+ if (const auto *DR = dyn_cast<DeclRefExpr>(E)) {
+ if (const auto *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ if (LookingForReference && !VD->getType()->isReferenceType())
+ return nullptr;
+ return N->getState()
+ ->getLValue(VD, N->getLocationContext())
+ .getAsRegion();
+ }
+ }
+
+ // FIXME: This does not handle other kinds of null references,
+ // for example, references from FieldRegions:
+ // struct Wrapper { int &ref; };
+ // Wrapper w = { *(int *)0 };
+ // w.ref = 1;
+
+ return nullptr;
+}
+
/// Comparing internal representations of symbolic values (via
/// SVal::operator==()) is a valid way to check if the value was updated,
/// unless it's a LazyCompoundVal that may have a
diff erent internal
@@ -1241,16 +1263,17 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
/// Show diagnostics for initializing or declaring a region \p R with a bad value.
static void showBRDiagnostics(const char *action, llvm::raw_svector_ostream &os,
- const MemRegion *R, SVal V, const DeclStmt *DS) {
- if (R->canPrintPretty()) {
- R->printPretty(os);
+ const MemRegion *NewR, SVal V,
+ const MemRegion *OldR, const DeclStmt *DS) {
+ if (NewR->canPrintPretty()) {
+ NewR->printPretty(os);
os << " ";
}
if (V.getAs<loc::ConcreteInt>()) {
bool b = false;
- if (R->isBoundable()) {
- if (const auto *TR = dyn_cast<TypedValueRegion>(R)) {
+ if (NewR->isBoundable()) {
+ if (const auto *TR = dyn_cast<TypedValueRegion>(NewR)) {
if (TR->getValueType()->isObjCObjectPointerType()) {
os << action << "nil";
b = true;
@@ -1262,29 +1285,31 @@ static void showBRDiagnostics(const char *action, llvm::raw_svector_ostream &os,
} else if (auto CVal = V.getAs<nonloc::ConcreteInt>()) {
os << action << CVal->getValue();
+ } else if (OldR && OldR->canPrintPretty()) {
+ os << action << "the value of ";
+ OldR->printPretty(os);
} else if (DS) {
if (V.isUndef()) {
- if (isa<VarRegion>(R)) {
+ if (isa<VarRegion>(NewR)) {
const auto *VD = cast<VarDecl>(DS->getSingleDecl());
if (VD->getInit()) {
- os << (R->canPrintPretty() ? "initialized" : "Initializing")
- << " to a garbage value";
+ os << (NewR->canPrintPretty() ? "initialized" : "Initializing")
+ << " to a garbage value";
} else {
- os << (R->canPrintPretty() ? "declared" : "Declaring")
- << " without an initial value";
+ os << (NewR->canPrintPretty() ? "declared" : "Declaring")
+ << " without an initial value";
}
}
} else {
- os << (R->canPrintPretty() ? "initialized" : "Initialized")
- << " here";
+ os << (NewR->canPrintPretty() ? "initialized" : "Initialized") << " here";
}
}
}
/// Display diagnostics for passing bad region as a parameter.
-static void showBRParamDiagnostics(llvm::raw_svector_ostream& os,
- const VarRegion *VR,
- SVal V) {
+static void showBRParamDiagnostics(llvm::raw_svector_ostream &os,
+ const VarRegion *VR, SVal V,
+ const MemRegion *ValueR) {
const auto *Param = cast<ParmVarDecl>(VR->getDecl());
os << "Passing ";
@@ -1298,6 +1323,8 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream& os,
os << "uninitialized value";
} else if (auto CI = V.getAs<nonloc::ConcreteInt>()) {
os << "the value " << CI->getValue();
+ } else if (ValueR && ValueR->canPrintPretty()) {
+ ValueR->printPretty(os);
} else {
os << "value";
}
@@ -1313,11 +1340,12 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream& os,
/// Show default diagnostics for storing bad region.
static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &os,
- const MemRegion *R, SVal V) {
+ const MemRegion *NewR, SVal V,
+ const MemRegion *OldR) {
if (V.getAs<loc::ConcreteInt>()) {
bool b = false;
- if (R->isBoundable()) {
- if (const auto *TR = dyn_cast<TypedValueRegion>(R)) {
+ if (NewR->isBoundable()) {
+ if (const auto *TR = dyn_cast<TypedValueRegion>(NewR)) {
if (TR->getValueType()->isObjCObjectPointerType()) {
os << "nil object reference stored";
b = true;
@@ -1325,34 +1353,44 @@ static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &os,
}
}
if (!b) {
- if (R->canPrintPretty())
+ if (NewR->canPrintPretty())
os << "Null pointer value stored";
else
os << "Storing null pointer value";
}
} else if (V.isUndef()) {
- if (R->canPrintPretty())
+ if (NewR->canPrintPretty())
os << "Uninitialized value stored";
else
os << "Storing uninitialized value";
} else if (auto CV = V.getAs<nonloc::ConcreteInt>()) {
- if (R->canPrintPretty())
+ if (NewR->canPrintPretty())
os << "The value " << CV->getValue() << " is assigned";
else
os << "Assigning " << CV->getValue();
+ } else if (OldR && OldR->canPrintPretty()) {
+ if (NewR->canPrintPretty()) {
+ os << "The value of ";
+ OldR->printPretty(os);
+ os << " is assigned";
+ } else {
+ os << "Assigning the value of ";
+ OldR->printPretty(os);
+ }
+
} else {
- if (R->canPrintPretty())
+ if (NewR->canPrintPretty())
os << "Value assigned";
else
os << "Assigning value";
}
- if (R->canPrintPretty()) {
+ if (NewR->canPrintPretty()) {
os << " to ";
- R->printPretty(os);
+ NewR->printPretty(os);
}
}
@@ -1451,8 +1489,76 @@ FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
if (!IsParam)
InitE = InitE->IgnoreParenCasts();
- bugreporter::trackExpressionValue(
- StoreSite, InitE, BR, TKind, EnableNullFPSuppression);
+ bugreporter::trackExpressionValue(StoreSite, InitE, BR, TKind,
+ EnableNullFPSuppression);
+ }
+
+ // Let's try to find the region where the value came from.
+ const MemRegion *OldRegion = nullptr;
+
+ // If we have init expression, it might be simply a reference
+ // to a variable, so we can use it.
+ if (InitE) {
+ // That region might still be not exactly what we are looking for.
+ // In situations like `int &ref = val;`, we can't say that
+ // `ref` is initialized with `val`, rather refers to `val`.
+ //
+ // In order, to mitigate situations like this, we check if the last
+ // stored value in that region is the value that we track.
+ //
+ // TODO: support other situations better.
+ if (const MemRegion *Candidate =
+ getLocationRegionIfReference(InitE, Succ, false)) {
+ const StoreManager &SM = BRC.getStateManager().getStoreManager();
+
+ // Here we traverse the graph up to find the last node where the
+ // candidate region is still in the store.
+ for (const ExplodedNode *N = StoreSite; N; N = N->getFirstPred()) {
+ if (SM.includedInBindings(N->getState()->getStore(), Candidate)) {
+ // And if it was bound to the target value, we can use it.
+ if (N->getState()->getSVal(Candidate) == V) {
+ OldRegion = Candidate;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Otherwise, if the current region does indeed contain the value
+ // we are looking for, we can look for a region where this value
+ // was before.
+ //
+ // It can be useful for situations like:
+ // new = identity(old)
+ // where the analyzer knows that 'identity' returns the value of its
+ // first argument.
+ //
+ // NOTE: If the region R is not a simple var region, it can contain
+ // V in one of its subregions.
+ if (!OldRegion && StoreSite->getState()->getSVal(R) == V) {
+ // Let's go up the graph to find the node where the region is
+ // bound to V.
+ const ExplodedNode *NodeWithoutBinding = StoreSite->getFirstPred();
+ for (;
+ NodeWithoutBinding && NodeWithoutBinding->getState()->getSVal(R) == V;
+ NodeWithoutBinding = NodeWithoutBinding->getFirstPred()) {
+ }
+
+ if (NodeWithoutBinding) {
+ // Let's try to find a unique binding for the value in that node.
+ // We want to use this to find unique bindings because of the following
+ // situations:
+ // b = a;
+ // c = identity(b);
+ //
+ // Telling the user that the value of 'a' is assigned to 'c', while
+ // correct, can be confusing.
+ StoreManager::FindUniqueBinding FB(V.getAsLocSymbol());
+ BRC.getStateManager().iterBindings(NodeWithoutBinding->getState(), FB);
+ if (FB)
+ OldRegion = FB.getRegion();
+ }
}
if (TKind == TrackingKind::Condition &&
@@ -1490,15 +1596,15 @@ FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
}
}
if (action)
- showBRDiagnostics(action, os, R, V, DS);
+ showBRDiagnostics(action, os, R, V, OldRegion, DS);
} else if (StoreSite->getLocation().getAs<CallEnter>()) {
if (const auto *VR = dyn_cast<VarRegion>(R))
- showBRParamDiagnostics(os, VR, V);
+ showBRParamDiagnostics(os, VR, V, OldRegion);
}
if (os.str().empty())
- showBRDefaultDiagnostics(os, R, V);
+ showBRDefaultDiagnostics(os, R, V, OldRegion);
if (TKind == bugreporter::TrackingKind::Condition)
os << WillBeUsedForACondition;
@@ -1825,27 +1931,6 @@ TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
// Implementation of trackExpressionValue.
//===----------------------------------------------------------------------===//
-static const MemRegion *getLocationRegionIfReference(const Expr *E,
- const ExplodedNode *N) {
- if (const auto *DR = dyn_cast<DeclRefExpr>(E)) {
- if (const auto *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- if (!VD->getType()->isReferenceType())
- return nullptr;
- ProgramStateManager &StateMgr = N->getState()->getStateManager();
- MemRegionManager &MRMgr = StateMgr.getRegionManager();
- return MRMgr.getVarRegion(VD, N->getLocationContext());
- }
- }
-
- // FIXME: This does not handle other kinds of null references,
- // for example, references from FieldRegions:
- // struct Wrapper { int &ref; };
- // Wrapper w = { *(int *)0 };
- // w.ref = 1;
-
- return nullptr;
-}
-
/// \return A subexpression of @c Ex which represents the
/// expression-of-interest.
static const Expr *peelOffOuterExpr(const Expr *Ex,
diff --git a/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist b/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
index 3b0ce877b76e6..fb92943d00dc0 100644
--- a/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
+++ b/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
@@ -5398,9 +5398,9 @@
</array>
<key>depth</key><integer>0</integer>
<key>extended_message</key>
- <string>'New' initialized here</string>
+ <string>'New' initialized to the value of 'Original'</string>
<key>message</key>
- <string>'New' initialized here</string>
+ <string>'New' initialized to the value of 'Original'</string>
</dict>
<dict>
<key>kind</key><string>control</string>
@@ -5886,9 +5886,9 @@
</array>
<key>depth</key><integer>0</integer>
<key>extended_message</key>
- <string>'Intermediate' initialized here</string>
+ <string>'Intermediate' initialized to the value of 'Original'</string>
<key>message</key>
- <string>'Intermediate' initialized here</string>
+ <string>'Intermediate' initialized to the value of 'Original'</string>
</dict>
<dict>
<key>kind</key><string>control</string>
@@ -5949,9 +5949,9 @@
</array>
<key>depth</key><integer>0</integer>
<key>extended_message</key>
- <string>'New' initialized here</string>
+ <string>'New' initialized to the value of 'Intermediate'</string>
<key>message</key>
- <string>'New' initialized here</string>
+ <string>'New' initialized to the value of 'Intermediate'</string>
</dict>
<dict>
<key>kind</key><string>control</string>
@@ -6438,9 +6438,9 @@
</array>
<key>depth</key><integer>0</integer>
<key>extended_message</key>
- <string>Value assigned to 'New'</string>
+ <string>The value of 'Original' is assigned to 'New'</string>
<key>message</key>
- <string>Value assigned to 'New'</string>
+ <string>The value of 'Original' is assigned to 'New'</string>
</dict>
<dict>
<key>kind</key><string>control</string>
diff --git a/clang/test/Analysis/diagnostics/deref-track-symbolic-region.cpp b/clang/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
index 61993f0872f40..e258a60aa966a 100644
--- a/clang/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
+++ b/clang/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
@@ -28,16 +28,16 @@ void testRefParam(int *ptr) {
}
int testRefToNullPtr() {
- int *p = 0; // expected-note {{'p' initialized to a null pointer value}}
+ int *p = 0; // expected-note {{'p' initialized to a null pointer value}}
int *const &p2 = p; // expected-note{{'p2' initialized here}}
- int *p3 = p2; // expected-note {{'p3' initialized to a null pointer value}}
- return *p3; // expected-warning {{Dereference of null pointer}}
- // expected-note at -1{{Dereference of null pointer}}
+ int *p3 = p2; // expected-note {{'p3' initialized to a null pointer value}}
+ return *p3; // expected-warning {{Dereference of null pointer}}
+ // expected-note at -1{{Dereference of null pointer}}
}
int testRefToNullPtr2() {
- int *p = 0; // expected-note {{'p' initialized to a null pointer value}}
- int *const &p2 = p;// expected-note{{'p2' initialized here}}
- return *p2; //expected-warning {{Dereference of null pointer}}
- // expected-note at -1{{Dereference of null pointer}}
-}
\ No newline at end of file
+ int *p = 0; // expected-note {{'p' initialized to a null pointer value}}
+ int *const &p2 = p; // expected-note{{'p2' initialized here}}
+ return *p2; //expected-warning {{Dereference of null pointer}}
+ // expected-note at -1{{Dereference of null pointer}}
+}
diff --git a/clang/test/Analysis/osobject-retain-release.cpp b/clang/test/Analysis/osobject-retain-release.cpp
index 38d5968a0b28f..81eb88ebf086c 100644
--- a/clang/test/Analysis/osobject-retain-release.cpp
+++ b/clang/test/Analysis/osobject-retain-release.cpp
@@ -536,7 +536,7 @@ void check_dynamic_cast_null_check() {
void check_dynamic_cast_alias() {
OSObject *originalPtr = OSObject::generateObject(1); // expected-note {{Call to method 'OSObject::generateObject' returns an OSObject}}
- OSArray *newPtr = OSDynamicCast(OSArray, originalPtr); // expected-note {{'newPtr' initialized here}}
+ OSArray *newPtr = OSDynamicCast(OSArray, originalPtr); // expected-note {{'newPtr' initialized to the value of 'originalPtr'}}
if (newPtr) { // expected-note {{'newPtr' is non-null}}
// expected-note at -1 {{Taking true branch}}
originalPtr = OSObject::generateObject(42);
@@ -549,7 +549,7 @@ void check_dynamic_cast_alias() {
void check_dynamic_cast_alias_cond() {
OSObject *originalPtr = OSObject::generateObject(1); // expected-note {{Call to method 'OSObject::generateObject' returns an OSObject}}
OSArray *newPtr = 0;
- if ((newPtr = OSDynamicCast(OSArray, originalPtr))) { // expected-note {{Value assigned to 'newPtr'}}
+ if ((newPtr = OSDynamicCast(OSArray, originalPtr))) { // expected-note {{The value of 'originalPtr' is assigned to 'newPtr'}}
// expected-note at -1 {{'newPtr' is non-null}}
// expected-note at -2 {{Taking true branch}}
originalPtr = OSObject::generateObject(42);
@@ -563,7 +563,7 @@ void check_dynamic_cast_alias_intermediate() {
OSObject *originalPtr = OSObject::generateObject(1); // expected-note {{Call to method 'OSObject::generateObject' returns an OSObject of type 'OSObject' with a +1 retain count}}
OSObject *intermediate = originalPtr; // TODO: add note here as well
OSArray *newPtr = 0;
- if ((newPtr = OSDynamicCast(OSArray, intermediate))) { // expected-note {{Value assigned to 'newPtr'}}
+ if ((newPtr = OSDynamicCast(OSArray, intermediate))) { // expected-note {{The value of 'intermediate' is assigned to 'newPtr'}}
// expected-note at -1 {{'newPtr' is non-null}}
// expected-note at -2 {{Taking true branch}}
intermediate = OSObject::generateObject(42);
@@ -573,6 +573,21 @@ void check_dynamic_cast_alias_intermediate() {
// expected-note at -1 {{Object leaked: object allocated and stored into 'newPtr' is not referenced later in this execution path and has a retain count of +1}}
}
+void check_dynamic_cast_alias_intermediate_2() {
+ OSObject *originalPtr = OSObject::generateObject(1); // expected-note {{Call to method 'OSObject::generateObject' returns an OSObject of type 'OSObject' with a +1 retain count}}
+ OSObject *intermediate = originalPtr; // TODO: add note here as well
+ OSArray *newPtr = 0;
+ if ((newPtr = OSDynamicCast(OSArray, intermediate))) { // expected-note {{Value assigned to 'newPtr'}}
+ // expected-note at -1 {{'newPtr' is non-null}}
+ // expected-note at -2 {{Taking true branch}}
+ intermediate = OSObject::generateObject(42);
+ (void)originalPtr;
+ }
+ (void)newPtr;
+ intermediate->release(); // expected-warning {{Potential leak of an object stored into 'newPtr'}}
+ // expected-note at -1 {{Object leaked: object allocated and stored into 'newPtr' is not referenced later in this execution path and has a retain count of +1}}
+}
+
void use_after_release() {
OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
arr->release(); // expected-note{{Object released}}
diff --git a/clang/test/Analysis/retain-release-path-notes.m b/clang/test/Analysis/retain-release-path-notes.m
index 9bf3b74add218..25d40bc825266 100644
--- a/clang/test/Analysis/retain-release-path-notes.m
+++ b/clang/test/Analysis/retain-release-path-notes.m
@@ -339,7 +339,7 @@ +(void)testLeakAliasSimple {
// expected-note at 216 {{Returning pointer (loaded from 'self')}}
// expected-note at -3 {{Returning from 'initY'}}
// expected-note at -4 {{'Original' initialized here}}
- id New = Original; // expected-note {{'New' initialized here}}
+ id New = Original; // expected-note {{'New' initialized to the value of 'Original'}}
Original = [[MyObj alloc] initZ];
(void)New;
[Original release]; // expected-warning {{Potential leak of an object stored into 'New'}}
@@ -352,8 +352,8 @@ +(void)testLeakAliasChain {
// expected-note at 216 {{Returning pointer (loaded from 'self')}}
// expected-note at -3 {{Returning from 'initY'}}
// expected-note at -4 {{'Original' initialized here}}
- id Intermediate = Original; // expected-note {{'Intermediate' initialized here}}
- id New = Intermediate; // expected-note {{'New' initialized here}}
+ id Intermediate = Original; // expected-note {{'Intermediate' initialized to the value of 'Original'}}
+ id New = Intermediate; // expected-note {{'New' initialized to the value of 'Intermediate'}}
Original = [[MyObj alloc] initZ];
(void)New;
[Original release]; // expected-warning {{Potential leak of an object stored into 'New'}}
@@ -380,7 +380,7 @@ +(void)testLeakAliasDeathInExpr {
// expected-note at -3 {{Returning from 'initY'}}
// expected-note at -4 {{'Original' initialized here}}
id New = 0;
- New = Original; // expected-note {{Value assigned to 'New'}}
+ New = Original; // expected-note {{The value of 'Original' is assigned to 'New'}}
Original = [[MyObj alloc] initZ];
[self log:New with:[self calculate]];
[Original release]; // expected-warning {{Potential leak of an object stored into 'New'}}
diff --git a/clang/test/Analysis/uninit-const.c b/clang/test/Analysis/uninit-const.c
index 051c6dd510cbd..c3f3e7f70d8e2 100644
--- a/clang/test/Analysis/uninit-const.c
+++ b/clang/test/Analysis/uninit-const.c
@@ -37,7 +37,7 @@ void f_1(void) {
void f_1_1(void) {
int t; // expected-note {{'t' declared without an initial value}}
int *tp1 = &t; // expected-note {{'tp1' initialized here}}
- int* tp2 = tp1; // expected-note {{'tp2' initialized here}}
+ int *tp2 = tp1; // expected-note {{'tp2' initialized to the value of 'tp1'}}
doStuff_pointerToConstInt(tp2); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note at -1 {{1st function call argument is a pointer to uninitialized value}}
}
@@ -53,7 +53,7 @@ void f_2(void) {
// expected-note at -1{{Calling 'f_2_sub'}}
// expected-note at -2{{Returning from 'f_2_sub'}}
// expected-note at -3{{'p' initialized here}}
- int* tp = p; // expected-note {{'tp' initialized here}}
+ int *tp = p; // expected-note {{'tp' initialized to the value of 'p'}}
doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note at -1 {{1st function call argument is a pointer to uninitialized value}}
}
@@ -70,7 +70,7 @@ void f_4(void) {
void f_5(void) {
int ta[5]; // expected-note {{'ta' initialized here}}
- int* tp = ta; // expected-note {{'tp' initialized here}}
+ int *tp = ta; // expected-note {{'tp' initialized here}}
doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note at -1 {{1st function call argument is a pointer to uninitialized value}}
}
diff --git a/clang/test/Analysis/uninit-const.cpp b/clang/test/Analysis/uninit-const.cpp
index 1920a42fb8d00..69c2c007aee4b 100644
--- a/clang/test/Analysis/uninit-const.cpp
+++ b/clang/test/Analysis/uninit-const.cpp
@@ -63,7 +63,7 @@ int& f6_1_sub(int &p) {
}
void f6_1(void) {
- int t; // expected-note{{'t' declared without an initial value}}
+ int t; // expected-note{{'t' declared without an initial value}}
int p = f6_1_sub(t); //expected-warning {{Assigned value is garbage or undefined}}
//expected-note at -1 {{Passing value via 1st parameter 'p'}}
//expected-note at -2 {{Calling 'f6_1_sub'}}
@@ -76,8 +76,8 @@ void f6_1(void) {
void f6_2(void) {
int t; //expected-note {{'t' declared without an initial value}}
int &p = t; //expected-note {{'p' initialized here}}
- int &s = p; //expected-note {{'s' initialized here}}
- int &q = s; //expected-note {{'q' initialized here}}
+ int &s = p; //expected-note {{'s' initialized to the value of 'p'}}
+ int &q = s; //expected-note {{'q' initialized to the value of 's'}}
doStuff6(q); //expected-warning {{1st function call argument is an uninitialized value}}
//expected-note at -1 {{1st function call argument is an uninitialized value}}
}
More information about the cfe-commits
mailing list