return Ex;
}
+/// Walk through nodes until we get one that matches the statement exactly.
+/// Alternately, if we hit a known lvalue for the statement, we know we've
+/// gone too far (though we can likely track the lvalue better anyway).
+static const ExplodedNode* findNodeForStatement(const ExplodedNode *N,
+ const Stmt *S,
+ const Expr *Inner) {
+ do {
+ const ProgramPoint &pp = N->getLocation();
+ if (auto ps = pp.getAs<StmtPoint>()) {
+ if (ps->getStmt() == S || ps->getStmt() == Inner)
+ break;
+ } else if (auto CEE = pp.getAs<CallExitEnd>()) {
+ if (CEE->getCalleeContext()->getCallSite() == S ||
+ CEE->getCalleeContext()->getCallSite() == Inner)
+ break;
+ }
+ N = N->getFirstPred();
+ } while (N);
+ return N;
+}
+
+/// Find the ExplodedNode where the lvalue (the value of 'Ex')
+/// was computed.
+static const ExplodedNode* findNodeForExpression(const ExplodedNode *N,
+ const Expr *Inner) {
+ while (N) {
+ if (auto P = N->getLocation().getAs<PostStmt>()) {
+ if (P->getStmt() == Inner)
+ break;
+ }
+ N = N->getFirstPred();
+ }
+ assert(N && "Unable to find the lvalue node.");
+ return N;
+
+}
+
+/// Performing operator `&' on an lvalue expression is essentially a no-op.
+/// Then, if we are taking addresses of fields or elements, these are also
+/// unlikely to matter.
+static const Expr* peelOfOuterAddrOf(const Expr* Ex) {
+ Ex = Ex->IgnoreParenCasts();
+
+ // FIXME: There's a hack in our Store implementation that always computes
+ // field offsets around null pointers as if they are always equal to 0.
+ // The idea here is to report accesses to fields as null dereferences
+ // even though the pointer value that's being dereferenced is actually
+ // the offset of the field rather than exactly 0.
+ // See the FIXME in StoreManager's getLValueFieldOrIvar() method.
+ // This code interacts heavily with this hack; otherwise the value
+ // would not be null at all for most fields, so we'd be unable to track it.
+ if (const auto *Op = dyn_cast<UnaryOperator>(Ex))
+ if (Op->getOpcode() == UO_AddrOf && Op->getSubExpr()->isLValue())
+ if (const Expr *DerefEx = bugreporter::getDerefExpr(Op->getSubExpr()))
+ return DerefEx;
+ return Ex;
+
+}
+
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
const Stmt *S,
BugReport &report, bool IsArg,
if (!S || !N)
return false;
- if (const Expr *Ex = dyn_cast<Expr>(S))
+ if (const auto *Ex = dyn_cast<Expr>(S))
S = peelOffOuterExpr(Ex, N);
const Expr *Inner = nullptr;
- if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ if (const auto *Ex = dyn_cast<Expr>(S)) {
+ Ex = peelOfOuterAddrOf(Ex);
Ex = Ex->IgnoreParenCasts();
- // Performing operator `&' on an lvalue expression is essentially a no-op.
- // Then, if we are taking addresses of fields or elements, these are also
- // unlikely to matter.
- // FIXME: There's a hack in our Store implementation that always computes
- // field offsets around null pointers as if they are always equal to 0.
- // The idea here is to report accesses to fields as null dereferences
- // even though the pointer value that's being dereferenced is actually
- // the offset of the field rather than exactly 0.
- // See the FIXME in StoreManager's getLValueFieldOrIvar() method.
- // This code interacts heavily with this hack; otherwise the value
- // would not be null at all for most fields, so we'd be unable to track it.
- if (const auto *Op = dyn_cast<UnaryOperator>(Ex))
- if (Op->getOpcode() == UO_AddrOf && Op->getSubExpr()->isLValue())
- if (const Expr *DerefEx = getDerefExpr(Op->getSubExpr()))
- Ex = DerefEx;
-
- if (Ex && (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex)))
+ if (Ex && (ExplodedGraph::isInterestingLValueExpr(Ex)
+ || CallEvent::isCallStmt(Ex)))
Inner = Ex;
}
if (IsArg && !Inner) {
assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call");
} else {
- // Walk through nodes until we get one that matches the statement exactly.
- // Alternately, if we hit a known lvalue for the statement, we know we've
- // gone too far (though we can likely track the lvalue better anyway).
- do {
- const ProgramPoint &pp = N->getLocation();
- if (Optional<StmtPoint> ps = pp.getAs<StmtPoint>()) {
- if (ps->getStmt() == S || ps->getStmt() == Inner)
- break;
- } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) {
- if (CEE->getCalleeContext()->getCallSite() == S ||
- CEE->getCalleeContext()->getCallSite() == Inner)
- break;
- }
- N = N->getFirstPred();
- } while (N);
-
+ N = findNodeForStatement(N, S, Inner);
if (!N)
return false;
}
// At this point in the path, the receiver should be live since we are at the
// message send expr. If it is nil, start tracking it.
if (const Expr *Receiver = NilReceiverBRVisitor::getNilReceiver(S, N))
- trackNullOrUndefValue(N, Receiver, report, false, EnableNullFPSuppression);
-
+ trackNullOrUndefValue(N, Receiver, report, /* IsArg=*/ false,
+ EnableNullFPSuppression);
// See if the expression we're interested refers to a variable.
// If so, we can track both its contents and constraints on its value.
if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) {
- const MemRegion *R = nullptr;
-
- // Find the ExplodedNode where the lvalue (the value of 'Ex')
- // was computed. We need this for getting the location value.
- const ExplodedNode *LVNode = N;
- while (LVNode) {
- if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
- if (P->getStmt() == Inner)
- break;
- }
- LVNode = LVNode->getFirstPred();
- }
- assert(LVNode && "Unable to find the lvalue node.");
+ const ExplodedNode *LVNode = findNodeForExpression(N, Inner);
ProgramStateRef LVState = LVNode->getState();
SVal LVal = LVState->getSVal(Inner, LVNode->getLocationContext());
- if (LVState->isNull(LVal).isConstrainedTrue()) {
- // In case of C++ references, we want to differentiate between a null
- // reference and reference to null pointer.
- // If the LVal is null, check if we are dealing with null reference.
- // For those, we want to track the location of the reference.
- if (const MemRegion *RR = getLocationRegionIfReference(Inner, N))
- R = RR;
- } else {
- R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
-
- // If this is a C++ reference to a null pointer, we are tracking the
- // pointer. In addition, we should find the store at which the reference
- // got initialized.
- if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) {
- if (Optional<KnownSVal> KV = LVal.getAs<KnownSVal>())
- report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
+ const MemRegion *RR = getLocationRegionIfReference(Inner, N);
+ bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
+
+ // If this is a C++ reference to a null pointer, we are tracking the
+ // pointer. In addition, we should find the store at which the reference
+ // got initialized.
+ if (RR && !LVIsNull) {
+ if (auto KV = LVal.getAs<KnownSVal>())
+ report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
*KV, RR, EnableNullFPSuppression));
- }
}
+ // In case of C++ references, we want to differentiate between a null
+ // reference and reference to null pointer.
+ // If the LVal is null, check if we are dealing with null reference.
+ // For those, we want to track the location of the reference.
+ const MemRegion *R = (RR && LVIsNull) ? RR :
+ LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
+
if (R) {
// Mark both the variable region and its contents as interesting.
SVal V = LVState->getRawSVal(loc::MemRegionVal(R));
// If the contents are symbolic, find out when they became null.
if (V.getAsLocSymbol(/*IncludeBaseRegions*/ true))
report.addVisitor(llvm::make_unique<TrackConstraintBRVisitor>(
- V.castAs<DefinedSVal>(), false));
+ V.castAs<DefinedSVal>(), false));
// Add visitor, which will suppress inline defensive checks.
- if (Optional<DefinedSVal> DV = V.getAs<DefinedSVal>()) {
+ if (auto DV = V.getAs<DefinedSVal>()) {
if (!DV->isZeroConstant() && LVState->isNull(*DV).isConstrainedTrue() &&
EnableNullFPSuppression) {
report.addVisitor(
llvm::make_unique<SuppressInlineDefensiveChecksVisitor>(*DV,
- LVNode));
+ LVNode));
}
}
- if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
+ if (auto KV = V.getAs<KnownSVal>())
report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
- *KV, R, EnableNullFPSuppression));
+ *KV, R, EnableNullFPSuppression));
return true;
}
}
// If the value came from an inlined function call, we should at least make
// sure that function isn't pruned in our output.
- if (const Expr *E = dyn_cast<Expr>(S))
+ if (const auto *E = dyn_cast<Expr>(S))
S = E->IgnoreParenCasts();
ReturnVisitor::addVisitorIfNecessary(N, S, report, EnableNullFPSuppression);
// base value that was dereferenced.
// assert(!V.isUnknownOrUndef());
// Is it a symbolic value?
- if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) {
+ if (auto L = V.getAs<loc::MemRegionVal>()) {
+ report.addVisitor(llvm::make_unique<UndefOrNullArgVisitor>(L->getRegion()));
+
// At this point we are dealing with the region's LValue.
// However, if the rvalue is a symbolic region, we should track it as well.
// Try to use the correct type when looking up the value.
SVal RVal;
- if (const Expr *E = dyn_cast<Expr>(S))
+ if (const auto *E = dyn_cast<Expr>(S))
RVal = state->getRawSVal(L.getValue(), E->getType());
else
RVal = state->getSVal(L->getRegion());
- report.addVisitor(llvm::make_unique<UndefOrNullArgVisitor>(L->getRegion()));
- if (Optional<KnownSVal> KV = RVal.getAs<KnownSVal>())
+ if (auto KV = RVal.getAs<KnownSVal>())
report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
- *KV, L->getRegion(), EnableNullFPSuppression));
+ *KV, L->getRegion(), EnableNullFPSuppression));
const MemRegion *RegionRVal = RVal.getAsRegion();
if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
report.markInteresting(RegionRVal);
report.addVisitor(llvm::make_unique<TrackConstraintBRVisitor>(
- loc::MemRegionVal(RegionRVal), false));
+ loc::MemRegionVal(RegionRVal), false));
}
}
-
return true;
}