/// Insert a diagnostic piece at function exit /// if a function parameter is annotated as "os_consumed", /// but it does not actually consume the reference. static std::shared_ptr<PathDiagnosticEventPiece> annotateConsumedSummaryMismatch(const ExplodedNode *N, CallExitBegin &CallExitLoc, const SourceManager &SM, CallEventManager &CEMgr) { const ExplodedNode *CN = getCalleeNode(N); if (!CN) return nullptr; CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState()); std::string sbuf; llvm::raw_string_ostream os(sbuf); ArrayRef<const ParmVarDecl *> Parameters = Call->parameters(); for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) { const ParmVarDecl *PVD = Parameters[I]; if (!PVD->hasAttr<OSConsumedAttr>()) continue; if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) { const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR); const RefVal *CountAtExit = getRefBinding(N->getState(), SR); if (!CountBeforeCall || !CountAtExit) continue; unsigned CountBefore = CountBeforeCall->getCount(); unsigned CountAfter = CountAtExit->getCount(); bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1; if (!AsExpected) { os << "Parameter '"; PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), /*Qualified=*/false); os << "' is marked as consuming, but the function did not consume " << "the reference\n"; } } } if (os.str().empty()) return nullptr; // FIXME: remove the code duplication with NoStoreFuncVisitor. PathDiagnosticLocation L; if (const ReturnStmt *RS = CallExitLoc.getReturnStmt()) { L = PathDiagnosticLocation::createBegin(RS, SM, N->getLocationContext()); } else { L = PathDiagnosticLocation( Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(), SM); } return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); }
PathDiagnosticPiece * UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) { ProgramStateRef State = N->getState(); ProgramPoint ProgLoc = N->getLocation(); // We are only interested in visiting CallEnter nodes. Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>(); if (!CEnter) return 0; // Check if one of the arguments is the region the visitor is tracking. CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager(); CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State); unsigned Idx = 0; for (CallEvent::param_iterator I = Call->param_begin(), E = Call->param_end(); I != E; ++I, ++Idx) { const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion(); // Are we tracking the argument or its subregion? if ( !ArgReg || (ArgReg != R && !R->isSubRegionOf(ArgReg->StripCasts()))) continue; // Check the function parameter type. const ParmVarDecl *ParamDecl = *I; assert(ParamDecl && "Formal parameter has no decl?"); QualType T = ParamDecl->getType(); if (!(T->isAnyPointerType() || T->isReferenceType())) { // Function can only change the value passed in by address. continue; } // If it is a const pointer value, the function does not intend to // change the value. if (T->getPointeeType().isConstQualified()) continue; // Mark the call site (LocationContext) as interesting if the value of the // argument is undefined or '0'/'NULL'. SVal BoundVal = State->getSVal(R); if (BoundVal.isUndef() || BoundVal.isZeroConstant()) { BR.markInteresting(CEnter->getCalleeContext()); return 0; } } return 0; }