xiangzhai created this revision.
Hi LLVM developers,
As Anna mentioned:
> One idea is to check that we do not pass a pointer that is known to be NULL
> to functions that are known to dereference pointers such as memcpy. There is
> a checker that determines if a null pointer could be dereferenced already,
> but there is no extension to check if such a pointer could be passed to a
> function tat could dereference it.
So I implemented `evalMemset` in the CStringChecker to detect null-deref issue.
please review my patch, thanks a lot!
Regards,
Leslie Zhai
Repository:
rL LLVM
https://reviews.llvm.org/D31868
Files:
lib/StaticAnalyzer/Checkers/CStringChecker.cpp
test/Analysis/null-deref-ps-region.c
Index: test/Analysis/null-deref-ps-region.c
===================================================================
--- test/Analysis/null-deref-ps-region.c
+++ test/Analysis/null-deref-ps-region.c
@@ -1,6 +1,9 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s
-// expected-no-diagnostics
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,unix,alpha.unix -std=gnu99 -analyzer-store=region -verify %s
+#include "Inputs/system-header-simulator.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *memset (void *__s, int __c, size_t __n);
// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
// also be live roots.
@@ -13,3 +16,18 @@
i = *p; // no-warning
}
}
+
+void f531() {
+ int *x = 0;
+ memset(x, 0, 1); // expected-warning {{Null pointer argument in call to memory set function}}
+}
+
+void f66() {
+ char buf[1];
+ memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+}
+
+void f77() {
+ char buf[1];
+ memset(buf, 0, sizeof(buf)); // no-warning
+}
Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -120,6 +120,7 @@
void evalStdCopy(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemset(CheckerContext &C, const CallExpr *CE) const;
// Utility methods
std::pair<ProgramStateRef , ProgramStateRef >
@@ -1999,6 +2000,63 @@
C.addTransition(State);
}
+void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
+ CurrentFunctionDescription = "memory set function";
+
+ const Expr *S = CE->getArg(0);
+ const Expr *Size = CE->getArg(2);
+ ProgramStateRef state = C.getState();
+
+ // See if the size argument is zero.
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal sizeVal = state->getSVal(Size, LCtx);
+ QualType sizeTy = Size->getType();
+
+ ProgramStateRef stateZeroSize, stateNonZeroSize;
+ std::tie(stateZeroSize, stateNonZeroSize) =
+ assumeZero(C, state, sizeVal, sizeTy);
+
+ // Get the value of the memory area pointed to by S.
+ SVal sVal = state->getSVal(S, LCtx);
+
+ // If the size is zero, there won't be any actual memory access, so
+ // just bind the return value to the destination buffer and return.
+ if (stateZeroSize && !stateNonZeroSize) {
+ stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, sVal);
+ C.addTransition(stateZeroSize);
+ return;
+ }
+
+ // If the size can be nonzero, we have to check the other arguments.
+ if (stateNonZeroSize) {
+ state = stateNonZeroSize;
+
+ // Ensure the memory area pointed to by s is not null.
+ // If it is NULL there will be a NULL pointer dereference.
+ state = checkNonNull(C, state, S, sVal);
+ if (!state)
+ return;
+
+ // Ensure the accesses are valid.
+ state = CheckBufferAccess(C, state, Size, S);
+ if (!state)
+ return;
+
+ // Return the memory area pointed to by s buffer.
+ state = state->BindExpr(CE, LCtx, sVal);
+
+ // Invalidate the memory area pointed to by s (regular invalidation without
+ // pointer-escaping the address of the top-level region).
+ state = InvalidateBuffer(C, state, S, C.getSVal(S),
+ /*IsSourceBuffer*/false, Size);
+
+ C.addTransition(state);
+ }
+}
+
static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name) {
IdentifierInfo *II = FD->getIdentifier();
if (!II)
@@ -2032,6 +2090,8 @@
evalFunction = &CStringChecker::evalMemcmp;
else if (C.isCLibraryFunction(FDecl, "memmove"))
evalFunction = &CStringChecker::evalMemmove;
+ else if (C.isCLibraryFunction(FDecl, "memset"))
+ evalFunction = &CStringChecker::evalMemset;
else if (C.isCLibraryFunction(FDecl, "strcpy"))
evalFunction = &CStringChecker::evalStrcpy;
else if (C.isCLibraryFunction(FDecl, "strncpy"))
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits