diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/BasicConstraintManager.cpp | 4 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | 12 | ||||
-rw-r--r-- | test/Analysis/reference.cpp | 17 |
3 files changed, 32 insertions, 1 deletions
diff --git a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp index 8897756a92..fb6d4be09d 100644 --- a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp @@ -363,6 +363,10 @@ const llvm::APSInt* BasicConstraintManager::getSymVal(ProgramStateRef state, bool BasicConstraintManager::isNotEqual(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& V) const { + // Special case: references are known to be non-zero. + if (sym->getType(getBasicVals().getContext())->isReferenceType()) + if (V == 0) + return true; // Retrieve the NE-set associated with the given symbol. const ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym); diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 550404a510..2b883cf9b9 100644 --- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -380,7 +380,17 @@ RangeConstraintManager::GetRange(ProgramStateRef state, SymbolRef sym) { // given symbol type. BasicValueFactory &BV = getBasicVals(); QualType T = sym->getType(BV.getContext()); - return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T)); + + RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T)); + + // Special case: references are known to be non-zero. + if (T->isReferenceType()) { + APSIntType IntType = BV.getAPSIntType(T); + Result = Result.Intersect(BV, F, ++IntType.getZeroValue(), + --IntType.getZeroValue()); + } + + return Result; } //===------------------------------------------------------------------------=== diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp index 06e4a50e44..d901bfee8a 100644 --- a/test/Analysis/reference.cpp +++ b/test/Analysis/reference.cpp @@ -1,3 +1,4 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=basic -verify -Wno-null-dereference %s // RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -verify -Wno-null-dereference %s void clang_analyzer_eval(bool); @@ -110,6 +111,16 @@ void testRetroactiveNullReference(int *x) { y = 5; // expected-warning{{Dereference of null pointer}} } +void testReferenceAddress(int &x) { + clang_analyzer_eval(&x != 0); // expected-warning{{TRUE}} + clang_analyzer_eval(&ref() != 0); // expected-warning{{TRUE}} + + struct S { int &x; }; + + extern S *getS(); + clang_analyzer_eval(&getS()->x != 0); // expected-warning{{TRUE}} +} + // ------------------------------------ // False negatives @@ -127,5 +138,11 @@ namespace rdar11212286 { B *x = 0; return *x; // should warn here! } +} + +void testReferenceFieldAddress() { + struct S { int &x; }; + extern S getS(); + clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}} } |