mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 23:51:56 +00:00
This patch adds modeling of strcmp() to the CString checker. Validates inputs are not NULL and are real C strings, then does the comparison and binds the proper return value. Unit tests included.
llvm-svn: 129364
This commit is contained in:
parent
240400b746
commit
f3539ad5c7
@ -74,6 +74,8 @@ public:
|
||||
void evalStrcat(CheckerContext &C, const CallExpr *CE) const;
|
||||
void evalStrncat(CheckerContext &C, const CallExpr *CE) const;
|
||||
|
||||
void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
|
||||
|
||||
// Utility methods
|
||||
std::pair<const GRState*, const GRState*>
|
||||
static assumeZero(CheckerContext &C,
|
||||
@ -87,6 +89,11 @@ public:
|
||||
SVal getCStringLength(CheckerContext &C, const GRState *&state,
|
||||
const Expr *Ex, SVal Buf) const;
|
||||
|
||||
const StringLiteral *getCStringLiteral(CheckerContext &C,
|
||||
const GRState *&state,
|
||||
const Expr *expr,
|
||||
SVal val) const;
|
||||
|
||||
static const GRState *InvalidateBuffer(CheckerContext &C,
|
||||
const GRState *state,
|
||||
const Expr *Ex, SVal V);
|
||||
@ -587,6 +594,26 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
|
||||
}
|
||||
}
|
||||
|
||||
const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
|
||||
const GRState *&state, const Expr *expr, SVal val) const {
|
||||
|
||||
// Get the memory region pointed to by the val.
|
||||
const MemRegion *bufRegion = val.getAsRegion();
|
||||
if (!bufRegion)
|
||||
return NULL;
|
||||
|
||||
// Strip casts off the memory region.
|
||||
bufRegion = bufRegion->StripCasts();
|
||||
|
||||
// Cast the memory region to a string region.
|
||||
const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
|
||||
if (!strRegion)
|
||||
return NULL;
|
||||
|
||||
// Return the actual string in the string region.
|
||||
return strRegion->getStringLiteral();
|
||||
}
|
||||
|
||||
const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C,
|
||||
const GRState *state,
|
||||
const Expr *E, SVal V) {
|
||||
@ -1074,6 +1101,61 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
|
||||
C.addTransition(state);
|
||||
}
|
||||
|
||||
void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
|
||||
//int strcmp(const char *restrict s1, const char *restrict s2);
|
||||
|
||||
const GRState *state = C.getState();
|
||||
|
||||
// Check that the first string is non-null
|
||||
const Expr *s1 = CE->getArg(0);
|
||||
SVal s1Val = state->getSVal(s1);
|
||||
state = checkNonNull(C, state, s1, s1Val);
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
// Check that the second string is non-null.
|
||||
const Expr *s2 = CE->getArg(1);
|
||||
SVal s2Val = state->getSVal(s2);
|
||||
state = checkNonNull(C, state, s2, s2Val);
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
// Get the string length of the first string or give up.
|
||||
SVal s1Length = getCStringLength(C, state, s1, s1Val);
|
||||
if (s1Length.isUndef())
|
||||
return;
|
||||
|
||||
// Get the string length of the second string or give up.
|
||||
SVal s2Length = getCStringLength(C, state, s2, s2Val);
|
||||
if (s2Length.isUndef())
|
||||
return;
|
||||
|
||||
// Get the string literal of the first string.
|
||||
const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val);
|
||||
if (!s1StrLiteral)
|
||||
return;
|
||||
llvm::StringRef s1StrRef = s1StrLiteral->getString();
|
||||
|
||||
// Get the string literal of the second string.
|
||||
const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val);
|
||||
if (!s2StrLiteral)
|
||||
return;
|
||||
llvm::StringRef s2StrRef = s2StrLiteral->getString();
|
||||
|
||||
// Compare string 1 to string 2 the same way strcmp() does.
|
||||
int result = s1StrRef.compare(s2StrRef);
|
||||
|
||||
// Build the SVal of the comparison to bind the return value.
|
||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||
QualType intTy = svalBuilder.getContext().IntTy;
|
||||
SVal resultVal = svalBuilder.makeIntVal(result, intTy);
|
||||
|
||||
// Bind the return value of the expression.
|
||||
// Set the return value.
|
||||
state = state->BindExpr(CE, resultVal);
|
||||
C.addTransition(state);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The driver method, and other Checker callbacks.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1108,6 +1190,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
|
||||
.Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat)
|
||||
.Case("strlen", &CStringChecker::evalstrLength)
|
||||
.Case("strnlen", &CStringChecker::evalstrnLength)
|
||||
.Case("strcmp", &CStringChecker::evalStrcmp)
|
||||
.Case("bcopy", &CStringChecker::evalBcopy)
|
||||
.Default(NULL);
|
||||
|
||||
|
@ -596,3 +596,89 @@ void strncat_no_overflow_2(char *y) {
|
||||
if (strlen(y) == 4)
|
||||
strncat(x, y, 1); // no-warning
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===
|
||||
// strcmp()
|
||||
//===----------------------------------------------------------------------===
|
||||
|
||||
#define strcmp BUILTIN(strcmp)
|
||||
int strcmp(const char *restrict s1, const char *restrict s2);
|
||||
|
||||
void strcmp_constant0() {
|
||||
if (strcmp("123", "123") != 0)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_constant_and_var_0() {
|
||||
char *x = "123";
|
||||
if (strcmp(x, "123") != 0)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_constant_and_var_1() {
|
||||
char *x = "123";
|
||||
if (strcmp("123", x) != 0)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_0() {
|
||||
char *x = "123";
|
||||
char *y = "123";
|
||||
if (strcmp(x, y) != 0)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_1() {
|
||||
char *x = "234";
|
||||
char *y = "123";
|
||||
if (strcmp(x, y) != 1)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_2() {
|
||||
char *x = "123";
|
||||
char *y = "234";
|
||||
if (strcmp(x, y) != -1)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_null_0() {
|
||||
char *x = NULL;
|
||||
char *y = "123";
|
||||
strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
|
||||
}
|
||||
|
||||
void strcmp_null_1() {
|
||||
char *x = "123";
|
||||
char *y = NULL;
|
||||
strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
|
||||
}
|
||||
|
||||
void strcmp_diff_length_0() {
|
||||
char *x = "12345";
|
||||
char *y = "234";
|
||||
if (strcmp(x, y) != -1)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_diff_length_1() {
|
||||
char *x = "123";
|
||||
char *y = "23456";
|
||||
if (strcmp(x, y) != -1)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_diff_length_2() {
|
||||
char *x = "12345";
|
||||
char *y = "123";
|
||||
if (strcmp(x, y) != 1)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
void strcmp_diff_length_3() {
|
||||
char *x = "123";
|
||||
char *y = "12345";
|
||||
if (strcmp(x, y) != -1)
|
||||
(void)*(char*)0; // no-warning
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user