@@ -64,10 +64,8 @@ using namespace clang::ento;
6464namespace {
6565class StdLibraryFunctionsChecker
6666 : public Checker<check::PreCall, check::PostCall, eval::Call> {
67- // / Below is a series of typedefs necessary to define function specs.
68- // / We avoid nesting types here because each additional qualifier
69- // / would need to be repeated in every function spec.
70- struct Summary ;
67+
68+ class Summary ;
7169
7270 // / Specify how much the analyzer engine should entrust modeling this function
7371 // / to us. If he doesn't, he performs additional invalidations.
@@ -114,10 +112,27 @@ class StdLibraryFunctionsChecker
114112 virtual ValueConstraintPtr negate () const {
115113 llvm_unreachable (" Not implemented" );
116114 };
115+
116+ // Check whether the constraint is malformed or not. It is malformed if the
117+ // specified argument has a mismatch with the given FunctionDecl (e.g. the
118+ // arg number is out-of-range of the function's argument list).
119+ bool checkValidity (const FunctionDecl *FD) const {
120+ const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams ();
121+ assert (ValidArg && " Arg out of range!" );
122+ if (!ValidArg)
123+ return false ;
124+ // Subclasses may further refine the validation.
125+ return checkSpecificValidity (FD);
126+ }
117127 ArgNo getArgNo () const { return ArgN; }
118128
119129 protected:
120130 ArgNo ArgN; // Argument to which we apply the constraint.
131+
132+ // / Do polymorphic sanity check on the constraint.
133+ virtual bool checkSpecificValidity (const FunctionDecl *FD) const {
134+ return true ;
135+ }
121136 };
122137
123138 // / Given a range, should the argument stay inside or outside this range?
@@ -168,6 +183,14 @@ class StdLibraryFunctionsChecker
168183 }
169184 return std::make_shared<RangeConstraint>(Tmp);
170185 }
186+
187+ bool checkSpecificValidity (const FunctionDecl *FD) const override {
188+ const bool ValidArg =
189+ getArgType (FD, ArgN)->isIntegralType (FD->getASTContext ());
190+ assert (ValidArg &&
191+ " This constraint should be applied on an integral type" );
192+ return ValidArg;
193+ }
171194 };
172195
173196 class ComparisonConstraint : public ValueConstraint {
@@ -210,6 +233,13 @@ class StdLibraryFunctionsChecker
210233 Tmp.CannotBeNull = !this ->CannotBeNull ;
211234 return std::make_shared<NotNullConstraint>(Tmp);
212235 }
236+
237+ bool checkSpecificValidity (const FunctionDecl *FD) const override {
238+ const bool ValidArg = getArgType (FD, ArgN)->isPointerType ();
239+ assert (ValidArg &&
240+ " This constraint should be applied only on a pointer type" );
241+ return ValidArg;
242+ }
213243 };
214244
215245 // Represents a buffer argument with an additional size argument.
@@ -278,11 +308,52 @@ class StdLibraryFunctionsChecker
278308 typedef std::vector<ValueConstraintPtr> ConstraintSet;
279309
280310 using ArgTypes = std::vector<QualType>;
311+
312+ // A placeholder type, we use it whenever we do not care about the concrete
313+ // type in a Signature.
314+ const QualType Irrelevant{};
315+ bool static isIrrelevant (QualType T) { return T.isNull (); }
316+
317+ // The signature of a function we want to describe with a summary. This is a
318+ // concessive signature, meaning there may be irrelevant types in the
319+ // signature which we do not check against a function with concrete types.
320+ struct Signature {
321+ const ArgTypes ArgTys;
322+ const QualType RetTy;
323+ Signature (ArgTypes ArgTys, QualType RetTy) : ArgTys(ArgTys), RetTy(RetTy) {
324+ assertRetTypeSuitableForSignature (RetTy);
325+ for (size_t I = 0 , E = ArgTys.size (); I != E; ++I) {
326+ QualType ArgTy = ArgTys[I];
327+ assertArgTypeSuitableForSignature (ArgTy);
328+ }
329+ }
330+ bool matches (const FunctionDecl *FD) const ;
331+
332+ private:
333+ static void assertArgTypeSuitableForSignature (QualType T) {
334+ assert ((T.isNull () || !T->isVoidType ()) &&
335+ " We should have no void types in the spec" );
336+ assert ((T.isNull () || T.isCanonical ()) &&
337+ " We should only have canonical types in the spec" );
338+ }
339+ static void assertRetTypeSuitableForSignature (QualType T) {
340+ assert ((T.isNull () || T.isCanonical ()) &&
341+ " We should only have canonical types in the spec" );
342+ }
343+ };
344+
345+ static QualType getArgType (const FunctionDecl *FD, ArgNo ArgN) {
346+ assert (FD && " Function must be set" );
347+ QualType T = (ArgN == Ret)
348+ ? FD->getReturnType ().getCanonicalType ()
349+ : FD->getParamDecl (ArgN)->getType ().getCanonicalType ();
350+ return T;
351+ }
352+
281353 using Cases = std::vector<ConstraintSet>;
282354
283- // / Includes information about
284- // / * function prototype (which is necessary to
285- // / ensure we're modeling the right function and casting values properly),
355+ // / A summary includes information about
356+ // / * function prototype (signature)
286357 // / * approach to invalidation,
287358 // / * a list of branches - a list of list of ranges -
288359 // / A branch represents a path in the exploded graph of a function (which
@@ -299,15 +370,28 @@ class StdLibraryFunctionsChecker
299370 // / * a list of argument constraints, that must be true on every branch.
300371 // / If these constraints are not satisfied that means a fatal error
301372 // / usually resulting in undefined behaviour.
302- struct Summary {
303- const ArgTypes ArgTys;
304- const QualType RetTy;
373+ // /
374+ // / Application of a summary:
375+ // / The signature and argument constraints together contain information
376+ // / about which functions are handled by the summary. The signature can use
377+ // / "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
378+ // / a signature means that type is not compared to the type of the parameter
379+ // / in the found FunctionDecl. Argument constraints may specify additional
380+ // / rules for the given parameter's type, those rules are checked once the
381+ // / signature is matched.
382+ class Summary {
383+ const Signature Sign;
305384 const InvalidationKind InvalidationKd;
306385 Cases CaseConstraints;
307386 ConstraintSet ArgConstraints;
308387
388+ // The function to which the summary applies. This is set after lookup and
389+ // match to the signature.
390+ const FunctionDecl *FD = nullptr ;
391+
392+ public:
309393 Summary (ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd)
310- : ArgTys (ArgTys), RetTy( RetTy), InvalidationKd(InvalidationKd) {}
394+ : Sign (ArgTys, RetTy), InvalidationKd(InvalidationKd) {}
311395
312396 Summary &Case (ConstraintSet&& CS) {
313397 CaseConstraints.push_back (std::move (CS));
@@ -318,24 +402,38 @@ class StdLibraryFunctionsChecker
318402 return *this ;
319403 }
320404
321- private:
322- static void assertTypeSuitableForSummary (QualType T) {
323- assert (!T->isVoidType () &&
324- " We should have had no significant void types in the spec" );
325- assert (T.isCanonical () &&
326- " We should only have canonical types in the spec" );
327- }
405+ InvalidationKind getInvalidationKd () const { return InvalidationKd; }
406+ const Cases &getCaseConstraints () const { return CaseConstraints; }
407+ const ConstraintSet &getArgConstraints () const { return ArgConstraints; }
328408
329- public:
330409 QualType getArgType (ArgNo ArgN) const {
331- QualType T = (ArgN == Ret) ? RetTy : ArgTys[ArgN];
332- assertTypeSuitableForSummary (T);
333- return T;
410+ return StdLibraryFunctionsChecker::getArgType (FD, ArgN);
334411 }
335412
336- // / Try our best to figure out if the summary's signature matches
337- // / *the* library function to which this specification applies.
338- bool matchesSignature (const FunctionDecl *FD) const ;
413+ // Returns true if the summary should be applied to the given function.
414+ // And if yes then store the function declaration.
415+ bool matchesAndSet (const FunctionDecl *FD) {
416+ bool Result = Sign.matches (FD) && validateByConstraints (FD);
417+ if (Result) {
418+ assert (!this ->FD && " FD must not be set more than once" );
419+ this ->FD = FD;
420+ }
421+ return Result;
422+ }
423+
424+ private:
425+ // Once we know the exact type of the function then do sanity check on all
426+ // the given constraints.
427+ bool validateByConstraints (const FunctionDecl *FD) const {
428+ for (const ConstraintSet &Case : CaseConstraints)
429+ for (const ValueConstraintPtr &Constraint : Case)
430+ if (!Constraint->checkValidity (FD))
431+ return false ;
432+ for (const ValueConstraintPtr &Constraint : ArgConstraints)
433+ if (!Constraint->checkValidity (FD))
434+ return false ;
435+ return true ;
436+ }
339437 };
340438
341439 // The map of all functions supported by the checker. It is initialized
@@ -345,11 +443,6 @@ class StdLibraryFunctionsChecker
345443
346444 mutable std::unique_ptr<BugType> BT_InvalidArg;
347445
348- // Auxiliary functions to support ArgNo within all structures
349- // in a unified manner.
350- static QualType getArgType (const Summary &Summary, ArgNo ArgN) {
351- return Summary.getArgType (ArgN);
352- }
353446 static SVal getArgSVal (const CallEvent &Call, ArgNo ArgN) {
354447 return ArgN == Ret ? Call.getReturnValue () : Call.getArgSVal (ArgN);
355448 }
@@ -406,7 +499,7 @@ ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange(
406499 SValBuilder &SVB = Mgr.getSValBuilder ();
407500 BasicValueFactory &BVF = SVB.getBasicValueFactory ();
408501 ConstraintManager &CM = Mgr.getConstraintManager ();
409- QualType T = getArgType (Summary, getArgNo ());
502+ QualType T = Summary. getArgType (getArgNo ());
410503 SVal V = getArgSVal (Call, getArgNo ());
411504
412505 if (auto N = V.getAs <NonLoc>()) {
@@ -433,7 +526,7 @@ ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange(
433526 SValBuilder &SVB = Mgr.getSValBuilder ();
434527 BasicValueFactory &BVF = SVB.getBasicValueFactory ();
435528 ConstraintManager &CM = Mgr.getConstraintManager ();
436- QualType T = getArgType (Summary, getArgNo ());
529+ QualType T = Summary. getArgType (getArgNo ());
437530 SVal V = getArgSVal (Call, getArgNo ());
438531
439532 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
@@ -489,13 +582,13 @@ ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
489582 ProgramStateManager &Mgr = State->getStateManager ();
490583 SValBuilder &SVB = Mgr.getSValBuilder ();
491584 QualType CondT = SVB.getConditionType ();
492- QualType T = getArgType (Summary, getArgNo ());
585+ QualType T = Summary. getArgType (getArgNo ());
493586 SVal V = getArgSVal (Call, getArgNo ());
494587
495588 BinaryOperator::Opcode Op = getOpcode ();
496589 ArgNo OtherArg = getOtherArgNo ();
497590 SVal OtherV = getArgSVal (Call, OtherArg);
498- QualType OtherT = getArgType (Summary, OtherArg);
591+ QualType OtherT = Summary. getArgType (OtherArg);
499592 // Note: we avoid integral promotion for comparison.
500593 OtherV = SVB.evalCast (OtherV, T, OtherT);
501594 if (auto CompV = SVB.evalBinOp (State, Op, V, OtherV, CondT)
@@ -514,9 +607,10 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
514607 ProgramStateRef State = C.getState ();
515608
516609 ProgramStateRef NewState = State;
517- for (const ValueConstraintPtr& VC : Summary.ArgConstraints ) {
518- ProgramStateRef SuccessSt = VC->apply (NewState, Call, Summary, C);
519- ProgramStateRef FailureSt = VC->negate ()->apply (NewState, Call, Summary, C);
610+ for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints ()) {
611+ ProgramStateRef SuccessSt = Constraint->apply (NewState, Call, Summary, C);
612+ ProgramStateRef FailureSt =
613+ Constraint->negate ()->apply (NewState, Call, Summary, C);
520614 // The argument constraint is not satisfied.
521615 if (FailureSt && !SuccessSt) {
522616 if (ExplodedNode *N = C.generateErrorNode (NewState))
@@ -546,10 +640,10 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
546640 ProgramStateRef State = C.getState ();
547641
548642 // Apply case/branch specifications.
549- for (const auto &VRS : Summary.CaseConstraints ) {
643+ for (const ConstraintSet &Case : Summary.getCaseConstraints () ) {
550644 ProgramStateRef NewState = State;
551- for (const auto &VR: VRS ) {
552- NewState = VR ->apply (NewState, Call, Summary, C);
645+ for (const ValueConstraintPtr &Constraint : Case ) {
646+ NewState = Constraint ->apply (NewState, Call, Summary, C);
553647 if (!NewState)
554648 break ;
555649 }
@@ -566,7 +660,7 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
566660 return false ;
567661
568662 const Summary &Summary = *FoundSummary;
569- switch (Summary.InvalidationKd ) {
663+ switch (Summary.getInvalidationKd () ) {
570664 case EvalCallAsPure: {
571665 ProgramStateRef State = C.getState ();
572666 const LocationContext *LC = C.getLocationContext ();
@@ -585,27 +679,23 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
585679 llvm_unreachable (" Unknown invalidation kind!" );
586680}
587681
588- bool StdLibraryFunctionsChecker::Summary::matchesSignature (
682+ bool StdLibraryFunctionsChecker::Signature::matches (
589683 const FunctionDecl *FD) const {
590684 // Check number of arguments:
591685 if (FD->param_size () != ArgTys.size ())
592686 return false ;
593687
594- // Check return type if relevant:
595- if (!RetTy.isNull () && RetTy != FD->getReturnType ().getCanonicalType ())
596- return false ;
688+ // Check return type.
689+ if (!isIrrelevant (RetTy))
690+ if (RetTy != FD->getReturnType ().getCanonicalType ())
691+ return false ;
597692
598- // Check argument types when relevant:
693+ // Check argument types.
599694 for (size_t I = 0 , E = ArgTys.size (); I != E; ++I) {
600- QualType FormalT = ArgTys[I];
601- // Null type marks irrelevant arguments.
602- if (FormalT.isNull ())
695+ QualType ArgTy = ArgTys[I];
696+ if (isIrrelevant (ArgTy))
603697 continue ;
604-
605- assertTypeSuitableForSummary (FormalT);
606-
607- QualType ActualT = FD->getParamDecl (I)->getType ().getCanonicalType ();
608- if (ActualT != FormalT)
698+ if (ArgTy != FD->getParamDecl (I)->getType ().getCanonicalType ())
609699 return false ;
610700 }
611701
@@ -651,8 +741,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
651741 // of function summary for common cases (eg. ssize_t could be int or long
652742 // or long long, so three summary variants would be enough).
653743 // Of course, function variants are also useful for C++ overloads.
654- const QualType
655- Irrelevant{}; // A placeholder, whenever we do not care about the type.
656744 const QualType IntTy = ACtx.IntTy ;
657745 const QualType LongTy = ACtx.LongTy ;
658746 const QualType LongLongTy = ACtx.LongLongTy ;
@@ -702,14 +790,14 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
702790 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
703791 // by the given Name, and in the global scope. The summary will be attached
704792 // to the found FunctionDecl only if the signatures match.
705- void operator ()(StringRef Name, const Summary & S) {
793+ void operator ()(StringRef Name, Summary S) {
706794 IdentifierInfo &II = ACtx.Idents .get (Name);
707795 auto LookupRes = ACtx.getTranslationUnitDecl ()->lookup (&II);
708796 if (LookupRes.size () == 0 )
709797 return ;
710798 for (Decl *D : LookupRes) {
711799 if (auto *FD = dyn_cast<FunctionDecl>(D)) {
712- if (S.matchesSignature (FD)) {
800+ if (S.matchesAndSet (FD)) {
713801 auto Res = Map.insert ({FD->getCanonicalDecl (), S});
714802 assert (Res.second && " Function already has a summary set!" );
715803 (void )Res;
0 commit comments