};
} // end anonymous namespace
-void NonNullParamChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
+/// \return Bitvector marking non-null attributes.
+static llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) {
const Decl *FD = Call.getDecl();
- if (!FD)
- return;
-
- // Merge all non-null attributes
unsigned NumArgs = Call.getNumArgs();
llvm::SmallBitVector AttrNonNull(NumArgs);
for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
AttrNonNull.set(Val);
}
}
+ return AttrNonNull;
+}
- ProgramStateRef state = C.getState();
+void NonNullParamChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ if (!Call.getDecl())
+ return;
+
+ llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call);
+ unsigned NumArgs = Call.getNumArgs();
- CallEvent::param_type_iterator TyI = Call.param_type_begin(),
- TyE = Call.param_type_end();
+ ProgramStateRef state = C.getState();
+ ArrayRef<ParmVarDecl*> parms = Call.parameters();
for (unsigned idx = 0; idx < NumArgs; ++idx) {
+ // For vararg functions, a corresponding parameter decl may not exist.
+ bool HasParam = idx < parms.size();
// Check if the parameter is a reference. We want to report when reference
// to a null pointer is passed as a parameter.
- bool haveRefTypeParam = false;
- if (TyI != TyE) {
- haveRefTypeParam = (*TyI)->isReferenceType();
- TyI++;
- }
-
+ bool haveRefTypeParam =
+ HasParam ? parms[idx]->getType()->isReferenceType() : false;
bool haveAttrNonNull = AttrNonNull[idx];
- if (!haveAttrNonNull) {
- // Check if the parameter is also marked 'nonnull'.
- ArrayRef<ParmVarDecl*> parms = Call.parameters();
- if (idx < parms.size())
- haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
- }
- if (!haveRefTypeParam && !haveAttrNonNull)
+ // Check if the parameter is also marked 'nonnull'.
+ if (!haveAttrNonNull && HasParam)
+ haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
+
+ if (!haveAttrNonNull && !haveRefTypeParam)
continue;
// If the value is unknown or undefined, we can't perform this check.
const Expr *ArgE = Call.getArgExpr(idx);
SVal V = Call.getArgSVal(idx);
- Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
+ auto DV = V.getAs<DefinedSVal>();
if (!DV)
continue;
- // Process the case when the argument is not a location.
assert(!haveRefTypeParam || DV->getAs<Loc>());
+ // Process the case when the argument is not a location.
if (haveAttrNonNull && !DV->getAs<Loc>()) {
// If the argument is a union type, we want to handle a potential
// transparent_union GCC extension.
if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
continue;
- if (Optional<nonloc::CompoundVal> CSV =
- DV->getAs<nonloc::CompoundVal>()) {
- nonloc::CompoundVal::iterator CSV_I = CSV->begin();
- assert(CSV_I != CSV->end());
- V = *CSV_I;
- DV = V.getAs<DefinedSVal>();
- assert(++CSV_I == CSV->end());
- // FIXME: Handle (some_union){ some_other_union_val }, which turns into
- // a LazyCompoundVal inside a CompoundVal.
- if (!V.getAs<Loc>())
- continue;
- // Retrieve the corresponding expression.
- if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
- if (const InitListExpr *IE =
- dyn_cast<InitListExpr>(CE->getInitializer()))
- ArgE = dyn_cast<Expr>(*(IE->begin()));
-
- } else {
- // FIXME: Handle LazyCompoundVals?
+ auto CSV = DV->getAs<nonloc::CompoundVal>();
+
+ // FIXME: Handle LazyCompoundVals?
+ if (!CSV)
continue;
- }
+
+ V = *(CSV->begin());
+ DV = V.getAs<DefinedSVal>();
+ assert(++CSV->begin() == CSV->end());
+ // FIXME: Handle (some_union){ some_other_union_val }, which turns into
+ // a LazyCompoundVal inside a CompoundVal.
+ if (!V.getAs<Loc>())
+ continue;
+
+ // Retrieve the corresponding expression.
+ if (const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
+ if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
+ ArgE = dyn_cast<Expr>(*(IE->begin()));
}
ConstraintManager &CM = C.getConstraintManager();
ProgramStateRef stateNotNull, stateNull;
std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
- if (stateNull) {
- if (!stateNotNull) {
- // Generate an error node. Check for a null node in case
- // we cache out.
- if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
-
- std::unique_ptr<BugReport> R;
- if (haveAttrNonNull)
- R = genReportNullAttrNonNull(errorNode, ArgE);
- else if (haveRefTypeParam)
- R = genReportReferenceToNullPointer(errorNode, ArgE);
-
- // Highlight the range of the argument that was null.
- R->addRange(Call.getArgSourceRange(idx));
-
- // Emit the bug report.
- C.emitReport(std::move(R));
- }
-
- // Always return. Either we cached out or we just emitted an error.
- return;
+ // Generate an error node. Check for a null node in case
+ // we cache out.
+ if (stateNull && !stateNotNull) {
+ if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
+
+ std::unique_ptr<BugReport> R;
+ if (haveAttrNonNull)
+ R = genReportNullAttrNonNull(errorNode, ArgE);
+ else if (haveRefTypeParam)
+ R = genReportReferenceToNullPointer(errorNode, ArgE);
+
+ // Highlight the range of the argument that was null.
+ R->addRange(Call.getArgSourceRange(idx));
+
+ // Emit the bug report.
+ C.emitReport(std::move(R));
}
+
+ // Always return. Either we cached out or we just emitted an error.
+ return;
+ }
+
+ if (stateNull) {
if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
ImplicitNullDerefEvent event = {
- V, false, N, &C.getBugReporter(),
- /*IsDirectDereference=*/haveRefTypeParam};
+ V, false, N, &C.getBugReporter(),
+ /*IsDirectDereference=*/haveRefTypeParam};
dispatchEvent(event);
}
}
// If a pointer value passed the check we should assume that it is
// indeed not null from this point forward.
- assert(stateNotNull);
state = stateNotNull;
}