aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2011-02-22 04:55:05 +0000
committerTed Kremenek <kremenek@apple.com>2011-02-22 04:55:05 +0000
commitbe4242ce039f0542ea0dd5f234aa0ee698f90c53 (patch)
tree782d4dd22d1cb659c979f9509a2fb9babfdc1dd8 /lib/StaticAnalyzer/Checkers/CStringChecker.cpp
parent6f17433b2d50262856ab09f52af96c6132b01012 (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.cpp40
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);