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 /lib/StaticAnalyzer/Checkers/CStringChecker.cpp | |
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
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/CStringChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 41 |
1 files changed, 37 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) |