diff options
author | Anton Yartsev <anton.yartsev@gmail.com> | 2016-05-19 23:03:49 +0000 |
---|---|---|
committer | Anton Yartsev <anton.yartsev@gmail.com> | 2016-05-19 23:03:49 +0000 |
commit | 8a88b908175add70df1c67c2eef3d00755c33428 (patch) | |
tree | 9496c05f29e872ae74dc44c5375f59febf4d262c /clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp | |
parent | bb578ef0dd7eebacebfb03a2e7bdfb3e3ba26b7e (diff) | |
download | llvm-8a88b908175add70df1c67c2eef3d00755c33428.zip llvm-8a88b908175add70df1c67c2eef3d00755c33428.tar.gz llvm-8a88b908175add70df1c67c2eef3d00755c33428.tar.bz2 |
[analyzer] Fix for PR23790 : constrain return value of strcmp() rather than returning a concrete value.
The function strcmp() can return any value, not just {-1,0,1} : "The strcmp(const char *s1, const char *s2) function returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string pointed to by s2." [C11 7.24.4.2p3]
https://llvm.org/bugs/show_bug.cgi?id=23790
http://reviews.llvm.org/D16317
llvm-svn: 270154
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 37 |
1 files changed, 20 insertions, 17 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index ff4922d..e951297 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -1837,6 +1837,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val); const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val); bool canComputeResult = false; + SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, + C.blockCount()); if (s1StrLiteral && s2StrLiteral) { StringRef s1StrRef = s1StrLiteral->getString(); @@ -1870,28 +1872,29 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, s2StrRef = s2StrRef.substr(0, s2Term); // Use StringRef's comparison methods to compute the actual result. - int result; + int compareRes = ignoreCase ? s1StrRef.compare_lower(s2StrRef) + : s1StrRef.compare(s2StrRef); - if (ignoreCase) { - // Compare string 1 to string 2 the same way strcasecmp() does. - result = s1StrRef.compare_lower(s2StrRef); - } else { - // Compare string 1 to string 2 the same way strcmp() does. - result = s1StrRef.compare(s2StrRef); + // The strcmp function returns an integer greater than, equal to, or less + // than zero, [c11, p7.24.4.2]. + if (compareRes == 0) { + resultVal = svalBuilder.makeIntVal(compareRes, CE->getType()); + } + else { + DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType()); + // Constrain strcmp's result range based on the result of StringRef's + // comparison methods. + BinaryOperatorKind op = (compareRes == 1) ? BO_GT : BO_LT; + SVal compareWithZero = + svalBuilder.evalBinOp(state, op, resultVal, zeroVal, + svalBuilder.getConditionType()); + DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>(); + state = state->assume(compareWithZeroVal, true); } - - // Build the SVal of the comparison and bind the return value. - SVal resultVal = svalBuilder.makeIntVal(result, CE->getType()); - state = state->BindExpr(CE, LCtx, resultVal); } } - if (!canComputeResult) { - // Conjure a symbolic value. It's the best we can do. - SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, - C.blockCount()); - state = state->BindExpr(CE, LCtx, resultVal); - } + state = state->BindExpr(CE, LCtx, resultVal); // Record this as a possible path. C.addTransition(state); |