Index: lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp +++ lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp @@ -44,13 +44,9 @@ }; } // 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()) { @@ -64,43 +60,47 @@ AttrNonNull.set(Val); } } + return AttrNonNull; +} - ProgramStateRef state = C.getState(); +void NonNullParamChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + if (!Call.getDecl()) + return; - CallEvent::param_type_iterator TyI = Call.param_type_begin(), - TyE = Call.param_type_end(); + llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call); + unsigned NumArgs = Call.getNumArgs(); + + ProgramStateRef state = C.getState(); + ArrayRef 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 parms = Call.parameters(); - if (idx < parms.size()) - haveAttrNonNull = parms[idx]->hasAttr(); - } - if (!haveRefTypeParam && !haveAttrNonNull) + // Check if the parameter is also marked 'nonnull'. + if (!haveAttrNonNull && HasParam) + haveAttrNonNull = parms[idx]->hasAttr(); + + 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 DV = V.getAs(); + auto DV = V.getAs(); if (!DV) continue; - // Process the case when the argument is not a location. assert(!haveRefTypeParam || DV->getAs()); + // Process the case when the argument is not a location. if (haveAttrNonNull && !DV->getAs()) { // If the argument is a union type, we want to handle a potential // transparent_union GCC extension. @@ -112,66 +112,63 @@ if (!UT || !UT->getDecl()->hasAttr()) continue; - if (Optional CSV = - DV->getAs()) { - nonloc::CompoundVal::iterator CSV_I = CSV->begin(); - assert(CSV_I != CSV->end()); - V = *CSV_I; - DV = V.getAs(); - assert(++CSV_I == CSV->end()); - // FIXME: Handle (some_union){ some_other_union_val }, which turns into - // a LazyCompoundVal inside a CompoundVal. - if (!V.getAs()) - continue; - // Retrieve the corresponding expression. - if (const CompoundLiteralExpr *CE = dyn_cast(ArgE)) - if (const InitListExpr *IE = - dyn_cast(CE->getInitializer())) - ArgE = dyn_cast(*(IE->begin())); + auto CSV = DV->getAs(); - } else { - // FIXME: Handle LazyCompoundVals? + // FIXME: Handle LazyCompoundVals? + if (!CSV) continue; - } + + V = *(CSV->begin()); + DV = V.getAs(); + assert(++CSV->begin() == CSV->end()); + // FIXME: Handle (some_union){ some_other_union_val }, which turns into + // a LazyCompoundVal inside a CompoundVal. + if (!V.getAs()) + continue; + + // Retrieve the corresponding expression. + if (const auto *CE = dyn_cast(ArgE)) + if (const auto *IE = dyn_cast(CE->getInitializer())) + ArgE = dyn_cast(*(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 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)); - } + // 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 R; + if (haveAttrNonNull) + R = genReportNullAttrNonNull(errorNode, ArgE); + else if (haveRefTypeParam) + R = genReportReferenceToNullPointer(errorNode, ArgE); - // Always return. Either we cached out or we just emitted an error. - return; + // 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; }