diff options
author | Ted Kremenek <kremenek@apple.com> | 2011-02-22 04:58:34 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2011-02-22 04:58:34 +0000 |
commit | 0ef473f75426f0a95635d0a9dd567d27b07dbd5b (patch) | |
tree | 6fb77799777d2a0b1714ecb91e8088df92f598c1 | |
parent | be4242ce039f0542ea0dd5f234aa0ee698f90c53 (diff) |
Add CStringChecker support for strncpy. Patch by Lenny Maiorani!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126188 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 41 | ||||
-rw-r--r-- | test/Analysis/string.c | 68 |
2 files changed, 105 insertions, 4 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index e9722a6de6..ddeb368f2b 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -59,8 +59,10 @@ public: bool IsStrnlen = false); void evalStrcpy(CheckerContext &C, const CallExpr *CE); + void evalStrncpy(CheckerContext &C, const CallExpr *CE); void evalStpcpy(CheckerContext &C, const CallExpr *CE); - void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd); + void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd, + bool isStrncpy); // Utility methods std::pair<const GRState*, const GRState*> @@ -845,16 +847,21 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) { // char *strcpy(char *restrict dst, const char *restrict src); - evalStrcpyCommon(C, CE, /* returnEnd = */ false); + evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ false); +} + +void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) { + // char *strcpy(char *restrict dst, const char *restrict src); + evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ true); } void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) { // char *stpcpy(char *restrict dst, const char *restrict src); - evalStrcpyCommon(C, CE, /* returnEnd = */ true); + evalStrcpyCommon(C, CE, /* returnEnd = */ true, /* isStrncpy = */ false); } void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, - bool returnEnd) { + bool returnEnd, bool isStrncpy) { const GRState *state = C.getState(); // Check that the destination is non-null @@ -879,6 +886,31 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, if (strLength.isUndef()) return; + if (isStrncpy) { + // Get the max number of characters to copy + const Expr *lenExpr = CE->getArg(2); + SVal lenVal = state->getSVal(lenExpr); + + NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength); + NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal); + + QualType cmpTy = C.getSValBuilder().getContext().IntTy; + const GRState *stateTrue, *stateFalse; + + // Check if the max number to copy is less than the length of the src + llvm::tie(stateTrue, stateFalse) = + state->assume(cast<DefinedOrUnknownSVal> + (C.getSValBuilder().evalBinOpNN(state, BO_GT, + *strLengthNL, *lenValNL, + cmpTy))); + + if (stateTrue) { + // Max number to copy is less than the length of the src, so the actual + // strLength copied is the max number arg. + strLength = lenVal; + } + } + SVal Result = (returnEnd ? UnknownVal() : DstVal); // If the destination is a MemRegion, try to check for a buffer overflow and @@ -951,6 +983,7 @@ bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) { .Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp) .Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove) .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy) + .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy) .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy) .Case("strlen", &CStringChecker::evalstrLength) .Case("strnlen", &CStringChecker::evalstrnLength) diff --git a/test/Analysis/string.c b/test/Analysis/string.c index d19439fde5..ac53ae472b 100644 --- a/test/Analysis/string.c +++ b/test/Analysis/string.c @@ -328,6 +328,74 @@ void strcpy_no_overflow(char *y) { } //===----------------------------------------------------------------------=== +// strncpy() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __strncpy_chk BUILTIN(__strncpy_chk) +char *__strncpy_chk(char *restrict s1, const char *restrict s2, size_t n, size_t destlen); + +#define strncpy(a,b,c) __strncpy_chk(a,b,c, (size_t)-1) + +#else /* VARIANT */ + +#define strncpy BUILTIN(strncpy) +char *strncpy(char *restrict s1, const char *restrict s2, size_t n); + +#endif /* VARIANT */ + + +void strncpy_null_dst(char *x) { + strncpy(NULL, x, 1); // expected-warning{{Null pointer argument in call to byte string function}} +} + +void strncpy_null_src(char *x) { + strncpy(x, NULL, 1); // expected-warning{{Null pointer argument in call to byte string function}} +} + +void strncpy_fn(char *x) { + strncpy(x, (char*)&strncpy_fn, 1); // expected-warning{{Argument to byte string function is the address of the function 'strncpy_fn', which is not a null-terminated string}} +} + +void strncpy_effects(char *x, char *y) { + char a = x[0]; + + if (strncpy(x, y, strlen(y)) != x) + (void)*(char*)0; // no-warning + + if (strlen(x) != strlen(y)) + (void)*(char*)0; // no-warning + + if (a != x[0]) + (void)*(char*)0; // expected-warning{{null}} +} + +void strncpy_overflow(char *y) { + char x[4]; + if (strlen(y) == 4) + strncpy(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}} +} + +void strncpy_len_overflow(char *y) { + char x[4]; + if (strlen(y) == 3) + strncpy(x, y, sizeof(x)); // no-warning +} + +void strncpy_no_overflow(char *y) { + char x[4]; + if (strlen(y) == 3) + strncpy(x, y, strlen(y)); // no-warning +} + +void strncpy_no_len_overflow(char *y) { + char x[4]; + if (strlen(y) == 4) + strncpy(x, y, sizeof(x)-1); // no-warning +} + +//===----------------------------------------------------------------------=== // stpcpy() //===----------------------------------------------------------------------=== |