[cfe-commits] r126188 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/CStringChecker.cpp test/Analysis/string.c
Ted Kremenek
kremenek at apple.com
Mon Feb 21 20:58:34 PST 2011
Author: kremenek
Date: Mon Feb 21 22:58:34 2011
New Revision: 126188
URL: http://llvm.org/viewvc/llvm-project?rev=126188&view=rev
Log:
Add CStringChecker support for strncpy. Patch by Lenny Maiorani!
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
cfe/trunk/test/Analysis/string.c
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=126188&r1=126187&r2=126188&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Mon Feb 21 22:58:34 2011
@@ -59,8 +59,10 @@
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::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 @@
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 @@
.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)
Modified: cfe/trunk/test/Analysis/string.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/string.c?rev=126188&r1=126187&r2=126188&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/string.c (original)
+++ cfe/trunk/test/Analysis/string.c Mon Feb 21 22:58:34 2011
@@ -328,6 +328,74 @@
}
//===----------------------------------------------------------------------===
+// 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()
//===----------------------------------------------------------------------===
More information about the cfe-commits
mailing list