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
This commit is contained in:
Ted Kremenek 2011-02-22 04:58:34 +00:00
Родитель be4242ce03
Коммит 0ef473f754
2 изменённых файлов: 105 добавлений и 4 удалений

Просмотреть файл

@ -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)

Просмотреть файл

@ -327,6 +327,74 @@ void strcpy_no_overflow(char *y) {
strcpy(x, y); // no-warning
}
//===----------------------------------------------------------------------===
// 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()
//===----------------------------------------------------------------------===