зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
be4242ce03
Коммит
0ef473f754
|
@ -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()
|
||||
//===----------------------------------------------------------------------===
|
||||
|
|
Загрузка…
Ссылка в новой задаче