diff options
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 18 | ||||
-rw-r--r-- | test/Analysis/string.c | 22 |
2 files changed, 40 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index bd1a56a1aa..942280d03d 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -1404,6 +1404,24 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // For strncpy, this is just checking that lenVal <= sizeof(dst) // (Yes, strncpy and strncat differ in how they treat termination. // strncat ALWAYS terminates, but strncpy doesn't.) + + // We need a special case for when the copy size is zero, in which + // case strncpy will do no work at all. Our bounds check uses n-1 + // as the last element accessed, so n == 0 is problematic. + ProgramStateRef StateZeroSize, StateNonZeroSize; + llvm::tie(StateZeroSize, StateNonZeroSize) = + assumeZero(C, state, *lenValNL, sizeTy); + + // If the size is known to be zero, we're done. + if (StateZeroSize && !StateNonZeroSize) { + StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal); + C.addTransition(StateZeroSize); + return; + } + + // Otherwise, go ahead and figure out the last element we'll touch. + // We don't record the non-zero assumption here because we can't + // be sure. We won't warn on a possible zero. NonLoc one = cast<NonLoc>(svalBuilder.makeIntVal(1, sizeTy)); maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy); diff --git a/test/Analysis/string.c b/test/Analysis/string.c index 24e29ebb02..dc38681b35 100644 --- a/test/Analysis/string.c +++ b/test/Analysis/string.c @@ -578,6 +578,17 @@ void strncpy_exactly_matching_buffer2(char *y) { (void)*(int*)0; // no-warning } +void strncpy_zero(char *src) { + char dst[] = "123"; + strncpy(dst, src, 0); // no-warning +} + +void strncpy_empty() { + char dst[] = "123"; + char src[] = ""; + strncpy(dst, src, 4); // no-warning +} + //===----------------------------------------------------------------------=== // strncat() //===----------------------------------------------------------------------=== @@ -716,6 +727,17 @@ void strncat_too_big(char *dst, char *src) { strncat(dst, src, 2); // expected-warning{{This expression will create a string whose length is too big to be represented as a size_t}} } +void strncat_zero(char *src) { + char dst[] = "123"; + strncat(dst, src, 0); // no-warning +} + +void strncat_empty() { + char dst[8] = "123"; + char src[] = ""; + strncat(dst, src, 4); // no-warning +} + //===----------------------------------------------------------------------=== // strcmp() //===----------------------------------------------------------------------=== |