diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2019-12-10 18:23:39 -0800 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2019-12-11 11:22:36 -0800 |
commit | 2b3f2071ec6561c3f10e5291289c47bb3629e354 (patch) | |
tree | c95e1f661ab6ee938523b351ba064e7ffef94616 /clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp | |
parent | 134faae04259b0412a067c73069f61905fc451d7 (diff) | |
download | bcm5719-llvm-2b3f2071ec6561c3f10e5291289c47bb3629e354.tar.gz bcm5719-llvm-2b3f2071ec6561c3f10e5291289c47bb3629e354.zip |
[analyzer] CStringChecker: Fix overly eager assumption that memcmp args overlap.
While analyzing code `memcmp(a, NULL, n);', where `a' has an unconstrained
symbolic value, the analyzer was emitting a warning about the *first* argument
being a null pointer, even though we'd rather have it warn about the *second*
argument.
This happens because CStringChecker first checks whether the two argument
buffers are in fact the same buffer, in order to take the fast path.
This boils down to assuming `a == NULL' to true. Then the subsequent check
for null pointer argument "discovers" that `a' is null.
Don't take the fast path unless we are *sure* that the buffers are the same.
Otherwise proceed as normal.
Differential Revision: https://reviews.llvm.org/D71322
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 27 |
1 files changed, 13 insertions, 14 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index c05a09da3df..4203f790e21 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -1313,9 +1313,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { ProgramStateRef StSameBuf, StNotSameBuf; std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); - // If the two arguments might be the same buffer, we know the result is 0, + // If the two arguments are the same buffer, we know the result is 0, // and we only need to check one size. - if (StSameBuf) { + if (StSameBuf && !StNotSameBuf) { state = StSameBuf; state = CheckBufferAccess(C, state, Size, Left); if (state) { @@ -1323,20 +1323,19 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { svalBuilder.makeZeroVal(CE->getType())); C.addTransition(state); } + return; } - // If the two arguments might be different buffers, we have to check the - // size of both of them. - if (StNotSameBuf) { - state = StNotSameBuf; - state = CheckBufferAccess(C, state, Size, Left, Right); - if (state) { - // The return value is the comparison result, which we don't know. - SVal CmpV = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, - C.blockCount()); - state = state->BindExpr(CE, LCtx, CmpV); - C.addTransition(state); - } + // If the two arguments might be different buffers, we have to check + // the size of both of them. + assert(StNotSameBuf); + state = CheckBufferAccess(C, state, Size, Left, Right); + if (state) { + // The return value is the comparison result, which we don't know. + SVal CmpV = + svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); + state = state->BindExpr(CE, LCtx, CmpV); + C.addTransition(state); } } } |