The checker used to crash when a mempcpy's length argument is symbolic. In this
case the cast from 'void *' to 'char *' failed because the respective
ElementRegion that represents cast is hard to add on top of the existing
ElementRegion that represents the offset to the last copied byte, while
preseving a sane memory region structure.
Additionally, a few test cases are added (to casts.c) which demonstrate problems
caused by existing sloppy work we do with multi-layer ElementRegions. If said
cast would be modeled properly in the future, these tests would need to be
taken into account.
Differential Revision: https://reviews.llvm.org/D38797
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@315742
91177308-0d34-0410-b5e6-
96231b3b80d8
// If this is mempcpy, get the byte after the last byte copied and
// bind the expr.
if (IsMempcpy) {
- loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>();
-
- // Get the length to copy.
- if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) {
- // Get the byte after the last byte copied.
- SValBuilder &SvalBuilder = C.getSValBuilder();
- ASTContext &Ctx = SvalBuilder.getContext();
- QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
- loc::MemRegionVal DestRegCharVal = SvalBuilder.evalCast(destRegVal,
- CharPtrTy, Dest->getType()).castAs<loc::MemRegionVal>();
- SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
- DestRegCharVal,
- *lenValNonLoc,
- Dest->getType());
-
- // The byte after the last byte copied is the return value.
- state = state->BindExpr(CE, LCtx, lastElement);
- } else {
- // If we don't know how much we copied, we can at least
- // conjure a return value for later.
- SVal result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
+ // Get the byte after the last byte copied.
+ SValBuilder &SvalBuilder = C.getSValBuilder();
+ ASTContext &Ctx = SvalBuilder.getContext();
+ QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
+ SVal DestRegCharVal =
+ SvalBuilder.evalCast(destVal, CharPtrTy, Dest->getType());
+ SVal lastElement = C.getSValBuilder().evalBinOp(
+ state, BO_Add, DestRegCharVal, sizeVal, Dest->getType());
+ // If we don't know how much we copied, we can at least
+ // conjure a return value for later.
+ if (lastElement.isUnknown())
+ lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
C.blockCount());
- state = state->BindExpr(CE, LCtx, result);
- }
+ // The byte after the last byte copied is the return value.
+ state = state->BindExpr(CE, LCtx, lastElement);
} else {
// All other copies return the destination buffer.
// (Well, bcopy() has a void return type, but this won't hurt.)
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
#include "Inputs/system-header-simulator-cxx.h"
#include "Inputs/system-header-simulator-for-malloc.h"
+// This provides us with four possible mempcpy() definitions.
+// See also comments in bstring.c.
+
+#ifdef USE_BUILTINS
+#define BUILTIN(f) __builtin_##f
+#else /* USE_BUILTINS */
+#define BUILTIN(f) f
+#endif /* USE_BUILTINS */
+
+#ifdef VARIANT
+
+#define __mempcpy_chk BUILTIN(__mempcpy_chk)
+void *__mempcpy_chk(void *__restrict__ s1, const void *__restrict__ s2,
+ size_t n, size_t destlen);
+
+#define mempcpy(a,b,c) __mempcpy_chk(a,b,c,(size_t)-1)
+
+#else /* VARIANT */
+
+#define mempcpy BUILTIN(mempcpy)
+void *mempcpy(void *__restrict__ s1, const void *__restrict__ s2, size_t n);
+
+#endif /* VARIANT */
+
void clang_analyzer_eval(int);
int *testStdCopyInvalidatesBuffer(std::vector<int> v) {
return buf;
}
+
+namespace pr34460 {
+short a;
+class b {
+ int c;
+ long g;
+ void d() {
+ int e = c;
+ f += e;
+ mempcpy(f, &a, g);
+ }
+ unsigned *f;
+};
+}
int x = (int) p;
clang_analyzer_eval(++x < 10); // no-crash // expected-warning{{UNKNOWN}}
}
+
+void multiDimensionalArrayPointerCasts() {
+ static int x[10][10];
+ int *y1 = &(x[3][5]);
+ char *z = ((char *) y1) + 2;
+ int *y2 = (int *)(z - 2);
+ int *y3 = ((int *)x) + 35; // This is offset for [3][5].
+
+ clang_analyzer_eval(y1 == y2); // expected-warning{{TRUE}}
+
+ // FIXME: should be FALSE (i.e. equal pointers).
+ clang_analyzer_eval(y1 - y2); // expected-warning{{UNKNOWN}}
+ // FIXME: should be TRUE (i.e. same symbol).
+ clang_analyzer_eval(*y1 == *y2); // expected-warning{{UNKNOWN}}
+
+ clang_analyzer_eval(*((char *)y1) == *((char *) y2)); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(y1 == y3); // expected-warning{{TRUE}}
+
+ // FIXME: should be FALSE (i.e. equal pointers).
+ clang_analyzer_eval(y1 - y3); // expected-warning{{UNKNOWN}}
+ // FIXME: should be TRUE (i.e. same symbol).
+ clang_analyzer_eval(*y1 == *y3); // expected-warning{{UNKNOWN}}
+
+ clang_analyzer_eval(*((char *)y1) == *((char *) y3)); // expected-warning{{TRUE}}
+}