diff options
author | Ted Kremenek <kremenek@apple.com> | 2011-02-22 04:55:05 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2011-02-22 04:55:05 +0000 |
commit | be4242ce039f0542ea0dd5f234aa0ee698f90c53 (patch) | |
tree | 782d4dd22d1cb659c979f9509a2fb9babfdc1dd8 /lib/StaticAnalyzer/Checkers/CStringChecker.cpp | |
parent | 6f17433b2d50262856ab09f52af96c6132b01012 (diff) |
Add CStringChecker support for strnlen. Patch by Lenny Maiorani!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126187 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/CStringChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 03f9047e96..e9722a6de6 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -54,6 +54,9 @@ public: void evalMemcmp(CheckerContext &C, const CallExpr *CE); void evalstrLength(CheckerContext &C, const CallExpr *CE); + void evalstrnLength(CheckerContext &C, const CallExpr *CE); + void evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, + bool IsStrnlen = false); void evalStrcpy(CheckerContext &C, const CallExpr *CE); void evalStpcpy(CheckerContext &C, const CallExpr *CE); @@ -776,6 +779,16 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) { void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) { // size_t strlen(const char *s); + evalstrLengthCommon(C, CE, /* IsStrnlen = */ false); +} + +void CStringChecker::evalstrnLength(CheckerContext &C, const CallExpr *CE) { + // size_t strnlen(const char *s, size_t maxlen); + evalstrLengthCommon(C, CE, /* IsStrnlen = */ true); +} + +void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, + bool IsStrnlen) { const GRState *state = C.getState(); const Expr *Arg = CE->getArg(0); SVal ArgVal = state->getSVal(Arg); @@ -791,6 +804,32 @@ void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) { if (strLength.isUndef()) return; + // If the check is for strnlen() then bind the return value to no more than + // the maxlen value. + if (IsStrnlen) { + const Expr *maxlenExpr = CE->getArg(1); + SVal maxlenVal = state->getSVal(maxlenExpr); + + NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength); + NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal); + + QualType cmpTy = C.getSValBuilder().getContext().IntTy; + const GRState *stateTrue, *stateFalse; + + // Check if the strLength is greater than or equal to the maxlen + llvm::tie(stateTrue, stateFalse) = + state->assume(cast<DefinedOrUnknownSVal> + (C.getSValBuilder().evalBinOpNN(state, BO_GE, + *strLengthNL, *maxlenValNL, + cmpTy))); + + // If the strLength is greater than or equal to the maxlen, set strLength + // to maxlen + if (stateTrue && !stateFalse) { + strLength = maxlenVal; + } + } + // If getCStringLength couldn't figure out the length, conjure a return // value, so it can be used in constraints, at least. if (strLength.isUnknown()) { @@ -914,6 +953,7 @@ bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) { .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy) .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy) .Case("strlen", &CStringChecker::evalstrLength) + .Case("strnlen", &CStringChecker::evalstrnLength) .Case("bcopy", &CStringChecker::evalBcopy) .Default(NULL); |