60 using namespace clang;
64 class StdLibraryFunctionsChecker :
public Checker<check::PostCall, eval::Call> {
68 struct FunctionSummaryTy;
72 enum InvalidationKindTy { NoEvalCall, EvalCallAsPure };
80 enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument };
84 typedef uint64_t RangeIntTy;
90 typedef std::vector<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy;
95 typedef uint32_t ArgNoTy;
101 ValueRangeKindTy
Kind;
102 IntRangeVectorTy Args;
105 ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
106 const IntRangeVectorTy &Args)
107 : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
109 ArgNoTy getArgNo()
const {
return ArgNo; }
113 assert(Kind == ComparesToArgument);
114 assert(Args.size() == 1);
118 "Only comparison ops are supported for ComparesToArgument");
122 ArgNoTy getOtherArgNo()
const {
123 assert(Kind == ComparesToArgument);
124 assert(Args.size() == 1);
125 return static_cast<ArgNoTy
>(Args[0].second);
128 const IntRangeVectorTy &getRanges()
const {
129 assert(Kind != ComparesToArgument);
138 const FunctionSummaryTy &Summary)
const;
141 const FunctionSummaryTy &Summary)
const;
144 const FunctionSummaryTy &Summary)
const;
148 const FunctionSummaryTy &Summary)
const {
151 return applyAsOutOfRange(State, Call, Summary);
153 return applyAsWithinRange(State, Call, Summary);
154 case ComparesToArgument:
155 return applyAsComparesToArgument(State, Call, Summary);
157 llvm_unreachable(
"Unknown ValueRange kind!");
162 typedef std::vector<ValueRange> ValueRangeSet;
168 struct FunctionSummaryTy {
169 const std::vector<QualType> ArgTypes;
171 const InvalidationKindTy InvalidationKind;
172 const std::vector<ValueRangeSet> Ranges;
175 static void assertTypeSuitableForSummary(
QualType T) {
177 "We should have had no significant void types in the spec");
179 "We should only have canonical types in the spec");
182 "We only support integral ranges in the spec");
186 QualType getArgType(ArgNoTy ArgNo)
const {
187 QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo];
188 assertTypeSuitableForSummary(T);
194 bool matchesCall(
const CallExpr *CE)
const;
202 typedef std::vector<FunctionSummaryTy> FunctionVariantsTy;
206 typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy;
207 mutable FunctionSummaryMapTy FunctionSummaryMap;
211 static QualType getArgType(
const FunctionSummaryTy &Summary, ArgNoTy ArgNo) {
212 return Summary.getArgType(ArgNo);
222 static SVal getArgSVal(
const CallEvent &Call, ArgNoTy ArgNo) {
239 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
241 const FunctionSummaryTy &Summary)
const {
247 QualType T = getArgType(Summary, getArgNo());
248 SVal V = getArgSVal(Call, getArgNo());
251 const IntRangeVectorTy &R = getRanges();
253 for (
size_t I = 0; I != E; ++I) {
254 const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
255 const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
267 StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
269 const FunctionSummaryTy &Summary)
const {
275 QualType T = getArgType(Summary, getArgNo());
276 SVal V = getArgSVal(Call, getArgNo());
282 const IntRangeVectorTy &R = getRanges();
288 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
289 if (Left != PlusInf) {
290 assert(MinusInf <= Left);
296 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
297 if (Right != MinusInf) {
298 assert(Right <= PlusInf);
304 for (
size_t I = 1; I != E; ++I) {
305 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
306 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
318 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
320 const FunctionSummaryTy &Summary)
const {
325 QualType T = getArgType(Summary, getArgNo());
326 SVal V = getArgSVal(Call, getArgNo());
329 ArgNoTy OtherArg = getOtherArgNo();
330 SVal OtherV = getArgSVal(Call, OtherArg);
331 QualType OtherT = getArgType(Call, OtherArg);
333 OtherV = SVB.
evalCast(OtherV, T, OtherT);
334 if (
auto CompV = SVB.
evalBinOp(State, Op, V, OtherV, CondT)
336 State = State->assume(*CompV,
true);
340 void StdLibraryFunctionsChecker::checkPostCall(
const CallEvent &Call,
355 const FunctionSummaryTy &Summary = *FoundSummary;
358 for (
const auto &VRS: Summary.Ranges) {
360 for (
const auto &VR: VRS) {
361 NewState = VR.apply(NewState, Call, Summary);
366 if (NewState && NewState != State)
371 bool StdLibraryFunctionsChecker::evalCall(
const CallExpr *CE,
381 const FunctionSummaryTy &Summary = *FoundSummary;
382 switch (Summary.InvalidationKind) {
383 case EvalCallAsPure: {
388 State = State->BindExpr(CE, LC, V);
397 llvm_unreachable(
"Unknown invalidation kind!");
400 bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
411 for (
size_t I = 0, E = ArgTypes.size(); I != E; ++I) {
417 assertTypeSuitableForSummary(FormalT);
419 QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I);
421 if (ActualT != FormalT)
429 StdLibraryFunctionsChecker::findFunctionSummary(
const FunctionDecl *FD,
441 initFunctionSummaries(BVF);
446 StringRef Name = II->
getName();
450 auto FSMI = FunctionSummaryMap.find(Name);
451 if (FSMI == FunctionSummaryMap.end())
459 const FunctionVariantsTy &SpecVariants = FSMI->second;
460 for (
const FunctionSummaryTy &Spec : SpecVariants)
461 if (Spec.matchesCall(CE))
467 void StdLibraryFunctionsChecker::initFunctionSummaries(
469 if (!FunctionSummaryMap.empty())
487 RangeIntTy IntMax = BVF.
getMaxValue(IntTy).getLimitedValue();
488 RangeIntTy LongMax = BVF.
getMaxValue(LongTy).getLimitedValue();
489 RangeIntTy LongLongMax = BVF.
getMaxValue(LongLongTy).getLimitedValue();
532 #define SUMMARY_WITH_VARIANTS(identifier) {#identifier, { 533 #define END_SUMMARY_WITH_VARIANTS }}, 534 #define VARIANT(argument_types, return_type, invalidation_approach) \ 535 { argument_types, return_type, invalidation_approach, { 536 #define END_VARIANT } }, 537 #define SUMMARY(identifier, argument_types, return_type, \ 538 invalidation_approach) \ 539 { #identifier, { { argument_types, return_type, invalidation_approach, { 540 #define END_SUMMARY } } } }, 541 #define ARGUMENT_TYPES(...) { __VA_ARGS__ } 542 #define RETURN_TYPE(x) x 543 #define INVALIDATION_APPROACH(x) x 546 #define ARGUMENT_CONDITION(argument_number, condition_kind) \ 547 { argument_number, condition_kind, { 548 #define END_ARGUMENT_CONDITION }}, 549 #define RETURN_VALUE_CONDITION(condition_kind) \ 550 { Ret, condition_kind, { 551 #define END_RETURN_VALUE_CONDITION }}, 552 #define ARG_NO(x) x##U 553 #define RANGE(x, y) { x, y }, 554 #define SINGLE_VALUE(x) RANGE(x, x) 555 #define IS_LESS_THAN(arg) { BO_LE, arg } 557 FunctionSummaryMap = {
778 END_ARGUMENT_CONDITION 779 RETURN_VALUE_CONDITION(OutOfRange) 781 END_RETURN_VALUE_CONDITION 784 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 789 END_ARGUMENT_CONDITION 790 RETURN_VALUE_CONDITION(WithinRange) 792 END_RETURN_VALUE_CONDITION 795 SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 796 INVALIDATION_APPROACH(EvalCallAsPure)) 797 CASE // Space, '\f
', '\n
', '\r
', '\t
', '\v'. 798 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 801 END_ARGUMENT_CONDITION 802 RETURN_VALUE_CONDITION(OutOfRange) 804 END_RETURN_VALUE_CONDITION 806 CASE // The locale-specific range. 807 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 809 END_ARGUMENT_CONDITION 812 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 816 END_ARGUMENT_CONDITION 817 RETURN_VALUE_CONDITION(WithinRange) 819 END_RETURN_VALUE_CONDITION 822 SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy), 823 INVALIDATION_APPROACH(EvalCallAsPure)) 824 CASE // Is certainly uppercase. 825 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 827 END_ARGUMENT_CONDITION 828 RETURN_VALUE_CONDITION(OutOfRange) 830 END_RETURN_VALUE_CONDITION 832 CASE // The locale-specific range. 833 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 835 END_ARGUMENT_CONDITION 838 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 839 RANGE('A
', 'Z
') RANGE(128, 255) 840 END_ARGUMENT_CONDITION 841 RETURN_VALUE_CONDITION(WithinRange) 843 END_RETURN_VALUE_CONDITION 846 SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 847 INVALIDATION_APPROACH(EvalCallAsPure)) 849 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 853 END_ARGUMENT_CONDITION 854 RETURN_VALUE_CONDITION(OutOfRange) 856 END_RETURN_VALUE_CONDITION 859 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 863 END_ARGUMENT_CONDITION 864 RETURN_VALUE_CONDITION(WithinRange) 866 END_RETURN_VALUE_CONDITION 870 // The getc() family of functions that returns either a char or an EOF. 871 SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 872 INVALIDATION_APPROACH(NoEvalCall)) 873 CASE // FIXME: EOF is assumed to be defined as -1. 874 RETURN_VALUE_CONDITION(WithinRange) 876 END_RETURN_VALUE_CONDITION 879 SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 880 INVALIDATION_APPROACH(NoEvalCall)) 881 CASE // FIXME: EOF is assumed to be defined as -1. 882 RETURN_VALUE_CONDITION(WithinRange) 884 END_RETURN_VALUE_CONDITION 887 SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy), 888 INVALIDATION_APPROACH(NoEvalCall)) 889 CASE // FIXME: EOF is assumed to be defined as -1. 890 RETURN_VALUE_CONDITION(WithinRange) 892 END_RETURN_VALUE_CONDITION 896 // read()-like functions that never return more than buffer size. 897 // We are not sure how ssize_t is defined on every platform, so we provide 898 // three variants that should cover common cases. 899 SUMMARY_WITH_VARIANTS(read) 900 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 901 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 903 RETURN_VALUE_CONDITION(ComparesToArgument) 904 IS_LESS_THAN(ARG_NO(2)) 905 END_RETURN_VALUE_CONDITION 906 RETURN_VALUE_CONDITION(WithinRange) 908 END_RETURN_VALUE_CONDITION 911 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 912 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 914 RETURN_VALUE_CONDITION(ComparesToArgument) 915 IS_LESS_THAN(ARG_NO(2)) 916 END_RETURN_VALUE_CONDITION 917 RETURN_VALUE_CONDITION(WithinRange) 919 END_RETURN_VALUE_CONDITION 922 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 923 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 925 RETURN_VALUE_CONDITION(ComparesToArgument) 926 IS_LESS_THAN(ARG_NO(2)) 927 END_RETURN_VALUE_CONDITION 928 RETURN_VALUE_CONDITION(WithinRange) 929 RANGE(-1, LongLongMax) 930 END_RETURN_VALUE_CONDITION 933 END_SUMMARY_WITH_VARIANTS 934 SUMMARY_WITH_VARIANTS(write) 935 // Again, due to elusive nature of ssize_t, we have duplicate 936 // our summaries to cover different variants. 937 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 938 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 940 RETURN_VALUE_CONDITION(ComparesToArgument) 941 IS_LESS_THAN(ARG_NO(2)) 942 END_RETURN_VALUE_CONDITION 943 RETURN_VALUE_CONDITION(WithinRange) 945 END_RETURN_VALUE_CONDITION 948 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 949 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 951 RETURN_VALUE_CONDITION(ComparesToArgument) 952 IS_LESS_THAN(ARG_NO(2)) 953 END_RETURN_VALUE_CONDITION 954 RETURN_VALUE_CONDITION(WithinRange) 956 END_RETURN_VALUE_CONDITION 959 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 960 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 962 RETURN_VALUE_CONDITION(ComparesToArgument) 963 IS_LESS_THAN(ARG_NO(2)) 964 END_RETURN_VALUE_CONDITION 965 RETURN_VALUE_CONDITION(WithinRange) 966 RANGE(-1, LongLongMax) 967 END_RETURN_VALUE_CONDITION 970 END_SUMMARY_WITH_VARIANTS 972 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 973 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 975 RETURN_VALUE_CONDITION(ComparesToArgument) 976 IS_LESS_THAN(ARG_NO(2)) 977 END_RETURN_VALUE_CONDITION 981 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 982 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 984 RETURN_VALUE_CONDITION(ComparesToArgument) 985 IS_LESS_THAN(ARG_NO(2)) 986 END_RETURN_VALUE_CONDITION 990 // getline()-like functions either fail or read at least the delimiter. 991 SUMMARY_WITH_VARIANTS(getline) 992 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 993 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 995 RETURN_VALUE_CONDITION(WithinRange) 998 END_RETURN_VALUE_CONDITION 1001 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 1002 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 1004 RETURN_VALUE_CONDITION(WithinRange) 1007 END_RETURN_VALUE_CONDITION 1010 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 1011 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 1013 RETURN_VALUE_CONDITION(WithinRange) 1015 RANGE(1, LongLongMax) 1016 END_RETURN_VALUE_CONDITION 1019 END_SUMMARY_WITH_VARIANTS 1020 SUMMARY_WITH_VARIANTS(getdelim) 1021 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1022 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 1024 RETURN_VALUE_CONDITION(WithinRange) 1027 END_RETURN_VALUE_CONDITION 1030 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1031 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 1033 RETURN_VALUE_CONDITION(WithinRange) 1036 END_RETURN_VALUE_CONDITION 1039 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1040 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 1042 RETURN_VALUE_CONDITION(WithinRange) 1044 RANGE(1, LongLongMax) 1045 END_RETURN_VALUE_CONDITION 1048 END_SUMMARY_WITH_VARIANTS 1052 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 1053 // If this checker grows large enough to support C++, Objective-C, or other 1054 // standard libraries, we could use multiple register...Checker() functions, 1055 // which would register various checkers with the help of the same Checker 1056 // class, turning on different function summaries. 1057 mgr.registerChecker<StdLibraryFunctionsChecker>();
An instance of this class is created to represent a function declaration or definition.
A (possibly-)qualified type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
SVal evalCast(SVal val, QualType castTy, QualType originalType)
const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
SValBuilder & getSValBuilder()
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
#define END_RETURN_VALUE_CONDITION
#define SUMMARY(identifier, argument_types, return_type, invalidation_approach)
SVal getReturnValue() const
Returns the return value of the call.
const FunctionProtoType * T
#define RETURN_VALUE_CONDITION(condition_kind)
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name=StringRef())
Returns true if the callee is an externally-visible function in the top-level namespace, such as malloc.
ASTContext & getContext() const
QualType getConditionType() const
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
virtual ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, const llvm::APSInt &To, bool InBound)=0
bool isComparisonOp() const
QualType getCanonicalType() const
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
#define ARGUMENT_CONDITION(argument_number, condition_kind)
#define ARGUMENT_TYPES(...)
unsigned blockCount() const
Returns the number of times the current block has been visited along the analyzed path...
StringRef getName() const
Return the actual identifier string.
Dataflow Directional Tag Classes.
BinaryOperator::Opcode getOpcode(const SymExpr *SE)
Represents an abstract call to a function or method along a particular path.
const llvm::APSInt & getMinValue(const llvm::APSInt &v)
ConstraintManager & getConstraintManager()
BasicValueFactory & getBasicValueFactory()
const ProgramStateRef & getState() const
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
QualType getResultType() const
Returns the result type, adjusted for references.
SValBuilder & getSValBuilder()
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
const llvm::APSInt & getMaxValue(const llvm::APSInt &v)
static Decl::Kind getKind(const Decl *D)
#define INVALIDATION_APPROACH(x)
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
#define END_ARGUMENT_CONDITION
const LocationContext * getLocationContext() const
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.