Revert "[analyzer] Support generating and reasoning over more symbolic constraint types"

Assertion `Loc::isLocType(SSE->getLHS()->getType())' failed in Analysis/PR3991.m

This reverts commit e469ff2759275e67f9072b3d67fac90f647c0fe6.

llvm-svn: 307853
This commit is contained in:
Dominic Chen 2017-07-12 21:43:42 +00:00
parent 845b981329
commit c0402c6916
13 changed files with 65 additions and 1837 deletions

View File

@ -125,14 +125,8 @@ public:
return OS.str();
}
std::string VisitIntSymExpr(const IntSymExpr *S) {
std::string Str;
llvm::raw_string_ostream OS(Str);
OS << S->getLHS()
<< std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
<< "(" << Visit(S->getRHS()) << ") ";
return OS.str();
}
// TODO: IntSymExpr doesn't appear in practice.
// Add the relevant code once it does.
std::string VisitSymSymExpr(const SymSymExpr *S) {
return "(" + Visit(S->getLHS()) + ") " +
@ -140,10 +134,8 @@ public:
" (" + Visit(S->getRHS()) + ")";
}
std::string VisitSymbolCast(const SymbolCast *S) {
return "cast of type '" + S->getType().getAsString() + "' of " +
Visit(S->getOperand());
}
// TODO: SymbolCast doesn't appear in practice.
// Add the relevant code once it does.
std::string VisitSymbolicRegion(const SymbolicRegion *R) {
// Explain 'this' object here.

View File

@ -100,7 +100,7 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
if (T->isNullPtrType())
return makeZeroVal(T);
if (!SymbolManager::canSymbolicate(T))
return UnknownVal();
@ -354,6 +354,9 @@ SVal SValBuilder::makeSymExprValNN(ProgramStateRef State,
BinaryOperator::Opcode Op,
NonLoc LHS, NonLoc RHS,
QualType ResultTy) {
if (!State->isTainted(RHS) && !State->isTainted(LHS))
return UnknownVal();
const SymExpr *symLHS = LHS.getAsSymExpr();
const SymExpr *symRHS = RHS.getAsSymExpr();
// TODO: When the Max Complexity is reached, we should conjure a symbol
@ -361,7 +364,7 @@ SVal SValBuilder::makeSymExprValNN(ProgramStateRef State,
const unsigned MaxComp = 10000; // 100000 28X
if (symLHS && symRHS &&
(symLHS->computeComplexity() + symRHS->computeComplexity()) < MaxComp)
(symLHS->computeComplexity() + symRHS->computeComplexity()) < MaxComp)
return makeNonLoc(symLHS, Op, symRHS, ResultTy);
if (symLHS && symLHS->computeComplexity() < MaxComp)

View File

@ -669,12 +669,12 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// If one of the operands is a symbol and the other is a constant,
// build an expression for use by the constraint manager.
if (SymbolRef rSym = rhs.getAsLocSymbol()) {
const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue();
// Prefer expressions with symbols on the left
// We can only build expressions with symbols on the left,
// so we need a reversible operator.
if (!BinaryOperator::isComparisonOp(op))
return makeNonLoc(lVal, op, rSym, resultTy);
return UnknownVal();
const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue();
op = BinaryOperator::reverseComparisonOp(op);
return makeNonLoc(rSym, op, lVal, resultTy);
}
@ -994,8 +994,7 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
if (SymbolRef Sym = V.getAsSymbol())
return state->getConstraintManager().getSymVal(state, Sym);
// FIXME: Add support for SymExprs in RangeConstraintManager.
// FIXME: Add support for SymExprs.
return nullptr;
}
@ -1020,11 +1019,8 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
return nonloc::SymbolVal(S);
}
SVal VisitIntSymExpr(const IntSymExpr *S) {
SVal RHS = Visit(S->getRHS());
SVal LHS = SVB.makeIntVal(S->getLHS());
return SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType());
}
// TODO: Support SymbolCast. Support IntSymExpr when/if we actually
// start producing them.
SVal VisitSymIntExpr(const SymIntExpr *S) {
SVal LHS = Visit(S->getLHS());
@ -1049,11 +1045,6 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
return SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType());
}
SVal VisitSymbolCast(const SymbolCast *S) {
SVal V = Visit(S->getOperand());
return SVB.evalCast(V, S->getType(), S->getOperand()->getType());
}
SVal VisitSymSymExpr(const SymSymExpr *S) {
SVal LHS = Visit(S->getLHS());
SVal RHS = Visit(S->getRHS());
@ -1067,8 +1058,7 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) {
// Simplification is much more costly than computing complexity.
// For high complexity, it may be not worth it.
// Use a lower bound to avoid recursive blowup, e.g. on PR24184.cpp
if (V.getSymbol()->computeComplexity() > 10)
if (V.getSymbol()->computeComplexity() > 100)
return V;
return Visit(V.getSymbol());
}

View File

@ -1034,19 +1034,16 @@ ProgramStateRef Z3ConstraintManager::assumeSym(ProgramStateRef State,
ProgramStateRef Z3ConstraintManager::assumeSymInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
const llvm::APSInt &To, bool InRange) {
ASTContext &Ctx = getBasicVals().getContext();
// FIXME: This should be a cast from a 1-bit integer type to a boolean type,
// but the former is not available in Clang. Instead, extend the APSInt
// directly.
bool isBoolTy = From.getBitWidth() == 1 && getAPSIntType(From).isNull();
QualType RetTy;
// The expression may be casted, so we cannot call getZ3DataExpr() directly
Z3Expr Exp = getZ3Expr(Sym, &RetTy);
QualType RTy = isBoolTy ? Ctx.BoolTy : getAPSIntType(From);
Z3Expr FromExp =
isBoolTy ? Z3Expr::fromAPSInt(From.extend(Ctx.getTypeSize(Ctx.BoolTy)))
: Z3Expr::fromAPSInt(From);
assert((getAPSIntType(From) == getAPSIntType(To)) &&
"Range values have different types!");
QualType RTy = getAPSIntType(From);
bool isSignedTy = RetTy->isSignedIntegerOrEnumerationType();
Z3Expr FromExp = Z3Expr::fromAPSInt(From);
Z3Expr ToExp = Z3Expr::fromAPSInt(To);
// Construct single (in)equality
if (From == To)
@ -1054,10 +1051,6 @@ ProgramStateRef Z3ConstraintManager::assumeSymInclusiveRange(
getZ3BinExpr(Exp, RetTy, InRange ? BO_EQ : BO_NE,
FromExp, RTy, nullptr));
assert((getAPSIntType(From) == getAPSIntType(To)) &&
"Range values have different types!");
Z3Expr ToExp = Z3Expr::fromAPSInt(To);
// Construct two (in)equalities, and a logical and/or
Z3Expr LHS =
getZ3BinExpr(Exp, RetTy, InRange ? BO_GE : BO_LT, FromExp, RTy, nullptr);
@ -1065,8 +1058,7 @@ ProgramStateRef Z3ConstraintManager::assumeSymInclusiveRange(
getZ3BinExpr(Exp, RetTy, InRange ? BO_LE : BO_GT, ToExp, RTy, nullptr);
return assumeZ3Expr(
State, Sym,
Z3Expr::fromBinOp(LHS, InRange ? BO_LAnd : BO_LOr, RHS,
RetTy->isSignedIntegerOrEnumerationType()));
Z3Expr::fromBinOp(LHS, InRange ? BO_LAnd : BO_LOr, RHS, isSignedTy));
}
ProgramStateRef Z3ConstraintManager::assumeSymUnsupported(ProgramStateRef State,
@ -1414,7 +1406,6 @@ void Z3ConstraintManager::doTypeConversion(Z3Expr &LHS, Z3Expr &RHS,
QualType &LTy, QualType &RTy) const {
ASTContext &Ctx = getBasicVals().getContext();
assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!");
// Perform type conversion
if (LTy->isIntegralOrEnumerationType() &&
RTy->isIntegralOrEnumerationType()) {
@ -1477,10 +1468,10 @@ template <typename T,
void Z3ConstraintManager::doIntTypeConversion(T &LHS, QualType &LTy, T &RHS,
QualType &RTy) const {
ASTContext &Ctx = getBasicVals().getContext();
uint64_t LBitWidth = Ctx.getTypeSize(LTy);
uint64_t RBitWidth = Ctx.getTypeSize(RTy);
assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!");
// Always perform integer promotion before checking type equality.
// Otherwise, e.g. (bool) a + (bool) b could trigger a backend assertion
if (LTy->isPromotableIntegerType()) {

View File

@ -1,4 +1,3 @@
import copy
import lit.formats
import lit.TestRunner
@ -9,21 +8,18 @@ class AnalyzerTest(lit.formats.ShTest):
results = []
# Parse any test requirements ('REQUIRES: ')
saved_test = copy.deepcopy(test)
saved_test = test
lit.TestRunner.parseIntegratedTestScript(test)
# If the test does not require z3, drop it from the available features
# to satisfy tests that explicitly require !z3
if 'z3' not in test.requires:
test.config.available_features.discard('z3')
results.append(self.executeWithAnalyzeSubstitution(
test, litConfig, '-analyzer-constraints=range'))
saved_test, litConfig, '-analyzer-constraints=range'))
if results[-1].code != lit.Test.PASS:
if results[-1].code == lit.Test.FAIL:
return results[-1]
# If z3 backend available, add an additional run line for it
if test.config.clang_staticanalyzer_z3 == '1' and '!z3' not in test.requires:
if test.config.clang_staticanalyzer_z3 == '1':
results.append(self.executeWithAnalyzeSubstitution(
saved_test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3'))

View File

@ -7,9 +7,10 @@ void testPersistentConstraints(int x, int y) {
// Sanity check
CHECK(x); // expected-warning{{TRUE}}
CHECK(x & 1); // expected-warning{{TRUE}}
CHECK(1 - x); // expected-warning{{TRUE}}
CHECK(x & y); // expected-warning{{TRUE}}
// False positives due to SValBuilder giving up on certain kinds of exprs.
CHECK(1 - x); // expected-warning{{UNKNOWN}}
CHECK(x & y); // expected-warning{{UNKNOWN}}
}
int testConstantShifts_PR18073(int which) {
@ -28,4 +29,4 @@ int testConstantShifts_PR18073(int which) {
default:
return 0;
}
}
}

View File

@ -43,7 +43,11 @@ void test_BOOL_initialization(int y) {
return;
}
if (y > 200 && y < 250) {
#ifdef ANALYZER_CM_Z3
BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
#else
BOOL x = y; // no-warning
#endif
return;
}
if (y >= 127 && y < 150) {

View File

@ -77,8 +77,7 @@ void testDiagnosableBranchLogical(int a, int b) {
void testNonDiagnosableBranchArithmetic(int a, int b) {
if (a - b) {
// expected-note@-1 {{Assuming the condition is true}}
// expected-note@-2 {{Taking true branch}}
// expected-note@-1 {{Taking true branch}}
*(volatile int *)0 = 1; // expected-warning{{Dereference of null pointer}}
// expected-note@-1 {{Dereference of null pointer}}
}
@ -1574,75 +1573,12 @@ void testNonDiagnosableBranchArithmetic(int a, int b) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <key>ranges</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming the condition is true</string>
// CHECK-NEXT: <key>message</key>
// CHECK-NEXT: <string>Assuming the condition is true</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
// CHECK-NEXT: <key>edges</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@ -1658,12 +1594,12 @@ void testNonDiagnosableBranchArithmetic(int a, int b) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@ -1671,12 +1607,12 @@ void testNonDiagnosableBranchArithmetic(int a, int b) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@ -1688,7 +1624,7 @@ void testNonDiagnosableBranchArithmetic(int a, int b) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@ -1696,12 +1632,12 @@ void testNonDiagnosableBranchArithmetic(int a, int b) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@ -1722,10 +1658,10 @@ void testNonDiagnosableBranchArithmetic(int a, int b) {
// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f56671e5f67c73abef619b56f7c29fa4</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testNonDiagnosableBranchArithmetic</string>
// CHECK-NEXT: <key>issue_hash_function_offset</key><string>4</string>
// CHECK-NEXT: <key>issue_hash_function_offset</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
// CHECK-NEXT: <key>line</key><integer>81</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>

View File

@ -69,7 +69,7 @@ void test_4(int x, int y) {
static int stat;
clang_analyzer_explain(x + 1); // expected-warning-re{{{{^\(argument 'x'\) \+ 1$}}}}
clang_analyzer_explain(1 + y); // expected-warning-re{{{{^\(argument 'y'\) \+ 1$}}}}
clang_analyzer_explain(x + y); // expected-warning-re{{{{^\(argument 'x'\) \+ \(argument 'y'\)$}}}}
clang_analyzer_explain(x + y); // expected-warning-re{{{{^unknown value$}}}}
clang_analyzer_explain(z); // expected-warning-re{{{{^undefined value$}}}}
clang_analyzer_explain(&z); // expected-warning-re{{{{^pointer to local variable 'z'$}}}}
clang_analyzer_explain(stat); // expected-warning-re{{{{^signed 32-bit integer '0'$}}}}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -analyzer-eagerly-assume -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -analyzer-eagerly-assume -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=true %s -o %t.plist
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -analyzer-eagerly-assume -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=ture %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
// REQUIRES: !z3
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
@ -11,13 +11,13 @@ void noteOnMacro(int y) {
y++;
y--;
mallocmemory
y++;
y++;
y++;
delete x; // expected-warning {{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
}
void macroIsFirstInFunction(int y) {
mallocmemory
mallocmemory
y++; // expected-warning {{Potential leak of memory pointed to by 'x'}}
}
@ -39,7 +39,7 @@ int macroInExpressionNoNote(int *p, int y) {;
return *p; // expected-warning {{Dereference of null pointer}}
}
#define macroWithArg(mp) mp==0
#define macroWithArg(mp) mp==0
int macroWithArgInExpression(int *p, int y) {;
y++;
if (macroWithArg(p))
@ -85,7 +85,6 @@ void test1() {
void test2(int *p) {
CALL_FN(p);
}
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
@ -637,69 +636,6 @@ void test2(int *p) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <key>ranges</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming the condition is true</string>
// CHECK-NEXT: <key>message</key>
// CHECK-NEXT: <string>Assuming the condition is true</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
// CHECK-NEXT: <key>edges</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>37</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>

View File

@ -67,8 +67,8 @@ void f7(long foo)
{
unsigned index = -1;
if (index < foo) index = foo;
if (index - 1 == 0)
clang_analyzer_warnIfReached(); // no-warning
if (index - 1 == 0) // Was not reached prior fix.
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
else
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
@ -87,8 +87,8 @@ void f9(long foo)
{
unsigned index = -1;
if (index < foo) index = foo;
if (index - 1L == 0L)
clang_analyzer_warnIfReached(); // no-warning
if (index - 1L == 0L) // Was not reached prior fix.
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
else
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
@ -117,8 +117,8 @@ void f12(long foo)
{
unsigned index = -1;
if (index < foo) index = foo;
if (index - 1UL == 0L)
clang_analyzer_warnIfReached(); // no-warning
if (index - 1UL == 0L) // Was not reached prior fix.
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
else
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}

View File

@ -57,7 +57,8 @@ void test_fread_fwrite(FILE *fp, int *buf) {
size_t y = fread(buf, sizeof(int), 10, fp);
clang_analyzer_eval(y <= 10); // expected-warning{{TRUE}}
size_t z = fwrite(buf, sizeof(int), y, fp);
clang_analyzer_eval(z <= y); // expected-warning{{TRUE}}
// FIXME: should be TRUE once symbol-symbol constraint support is improved.
clang_analyzer_eval(z <= y); // expected-warning{{UNKNOWN}}
}
ssize_t getline(char **, size_t *, FILE *);