diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 93e598a273756a2cc0536d8d0e9b0ab3d6c81cb8..d5555daecdca7f36912dc6f8575a1e5599bc309c 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -58,6 +58,26 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, if (!B->isAssignmentOp()) { StmtNodeBuilder Bldr(*it, Tmp2, *currentBuilderContext); + + if (B->isAdditiveOp()) { + // If one of the operands is a location, conjure a symbol for the other + // one (offset) if it's unknown so that memory arithmetic always + // results in an ElementRegion. + // TODO: This can be removed after we enable history tracking with + // SymSymExpr. + unsigned Count = currentBuilderContext->getCurrentBlockCount(); + if (isa<Loc>(LeftV) && + RHS->getType()->isIntegerType() && RightV.isUnknown()) { + RightV = svalBuilder.getConjuredSymbolVal(RHS, LCtx, + RHS->getType(), Count); + } + if (isa<Loc>(RightV) && + LHS->getType()->isIntegerType() && LeftV.isUnknown()) { + LeftV = svalBuilder.getConjuredSymbolVal(LHS, LCtx, + LHS->getType(), Count); + } + } + // Process non-assignments except commas or short-circuited // logical expressions (LAnd and LOr). SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index 27e34e9039c1ace2929134ca8e9a1e9dd4ce5031..9c09051c31b49b17e7f53bd90c1b97a8946dae0d 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -776,6 +776,13 @@ int rdar11269741(struct rdar11269741_b_t o) return p->n.m; // expected-warning {{leak}} } +// Pointer arithmetic, returning an ElementRegion. +void *radar11329382(unsigned bl) { + void *ptr = malloc (16); + ptr = ptr + (2 - bl); + return ptr; // no warning +} + void __assert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__)); int strcmp(const char *, const char *); char *a (void);