59 using namespace clang;
63 class StdLibraryFunctionsChecker :
public Checker<check::PostCall, eval::Call> {
67 struct FunctionSummaryTy;
71 enum InvalidationKindTy { NoEvalCall, EvalCallAsPure };
79 enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument };
83 typedef uint64_t RangeIntTy;
89 typedef std::vector<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy;
94 typedef uint32_t ArgNoTy;
100 ValueRangeKindTy
Kind;
101 IntRangeVectorTy Args;
104 ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
105 const IntRangeVectorTy &Args)
106 : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
108 ArgNoTy getArgNo()
const {
return ArgNo; }
112 assert(Kind == ComparesToArgument);
113 assert(Args.size() == 1);
117 "Only comparison ops are supported for ComparesToArgument");
121 ArgNoTy getOtherArgNo()
const {
122 assert(Kind == ComparesToArgument);
123 assert(Args.size() == 1);
124 return static_cast<ArgNoTy
>(Args[0].second);
127 const IntRangeVectorTy &getRanges()
const {
128 assert(Kind != ComparesToArgument);
137 const FunctionSummaryTy &Summary)
const;
140 const FunctionSummaryTy &Summary)
const;
143 const FunctionSummaryTy &Summary)
const;
147 const FunctionSummaryTy &Summary)
const {
150 return applyAsOutOfRange(State, Call, Summary);
152 return applyAsWithinRange(State, Call, Summary);
153 case ComparesToArgument:
154 return applyAsComparesToArgument(State, Call, Summary);
156 llvm_unreachable(
"Unknown ValueRange kind!");
161 typedef std::vector<ValueRange> ValueRangeSet;
167 struct FunctionSummaryTy {
168 const std::vector<QualType> ArgTypes;
170 const InvalidationKindTy InvalidationKind;
171 const std::vector<ValueRangeSet> Ranges;
174 static void assertTypeSuitableForSummary(
QualType T) {
176 "We should have had no significant void types in the spec");
178 "We should only have canonical types in the spec");
181 "We only support integral ranges in the spec");
185 QualType getArgType(ArgNoTy ArgNo)
const {
186 QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo];
187 assertTypeSuitableForSummary(T);
193 bool matchesCall(
const CallExpr *CE)
const;
201 typedef std::vector<FunctionSummaryTy> FunctionVariantsTy;
205 typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy;
206 mutable FunctionSummaryMapTy FunctionSummaryMap;
210 static QualType getArgType(
const FunctionSummaryTy &Summary, ArgNoTy ArgNo) {
211 return Summary.getArgType(ArgNo);
221 static SVal getArgSVal(
const CallEvent &Call, ArgNoTy ArgNo) {
230 Optional<FunctionSummaryTy> findFunctionSummary(
const FunctionDecl *FD,
238 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
240 const FunctionSummaryTy &Summary)
const {
246 QualType T = getArgType(Summary, getArgNo());
247 SVal V = getArgSVal(Call, getArgNo());
250 const IntRangeVectorTy &R = getRanges();
252 for (
size_t I = 0; I != E; ++I) {
253 const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
254 const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
266 StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
268 const FunctionSummaryTy &Summary)
const {
274 QualType T = getArgType(Summary, getArgNo());
275 SVal V = getArgSVal(Call, getArgNo());
281 const IntRangeVectorTy &R = getRanges();
287 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
288 if (Left != PlusInf) {
289 assert(MinusInf <= Left);
295 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
296 if (Right != MinusInf) {
297 assert(Right <= PlusInf);
303 for (
size_t I = 1; I != E; ++I) {
304 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
305 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
317 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
319 const FunctionSummaryTy &Summary)
const {
324 QualType T = getArgType(Summary, getArgNo());
325 SVal V = getArgSVal(Call, getArgNo());
328 ArgNoTy OtherArg = getOtherArgNo();
329 SVal OtherV = getArgSVal(Call, OtherArg);
330 QualType OtherT = getArgType(Call, OtherArg);
332 OtherV = SVB.
evalCast(OtherV, T, OtherT);
333 if (
auto CompV = SVB.
evalBinOp(State, Op, V, OtherV, CondT)
335 State = State->assume(*CompV,
true);
339 void StdLibraryFunctionsChecker::checkPostCall(
const CallEvent &Call,
349 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
354 const FunctionSummaryTy &Summary = *FoundSummary;
357 for (
const auto &VRS: Summary.Ranges) {
359 for (
const auto &VR: VRS) {
360 NewState = VR.apply(NewState, Call, Summary);
365 if (NewState && NewState != State)
370 bool StdLibraryFunctionsChecker::evalCall(
const CallEvent &Call,
372 const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.
getDecl());
376 const auto *CE = dyn_cast_or_null<CallExpr>(Call.
getOriginExpr());
380 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
384 const FunctionSummaryTy &Summary = *FoundSummary;
385 switch (Summary.InvalidationKind) {
386 case EvalCallAsPure: {
391 State = State->BindExpr(CE, LC, V);
400 llvm_unreachable(
"Unknown invalidation kind!");
403 bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
414 for (
size_t I = 0, E = ArgTypes.size(); I != E; ++I) {
420 assertTypeSuitableForSummary(FormalT);
422 QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I);
424 if (ActualT != FormalT)
431 Optional<StdLibraryFunctionsChecker::FunctionSummaryTy>
432 StdLibraryFunctionsChecker::findFunctionSummary(
const FunctionDecl *FD,
444 initFunctionSummaries(BVF);
449 StringRef Name = II->
getName();
453 auto FSMI = FunctionSummaryMap.find(Name);
454 if (FSMI == FunctionSummaryMap.end())
462 const FunctionVariantsTy &SpecVariants = FSMI->second;
463 for (
const FunctionSummaryTy &Spec : SpecVariants)
464 if (Spec.matchesCall(CE))
470 void StdLibraryFunctionsChecker::initFunctionSummaries(
472 if (!FunctionSummaryMap.empty())
490 RangeIntTy IntMax = BVF.
getMaxValue(IntTy).getLimitedValue();
491 RangeIntTy LongMax = BVF.
getMaxValue(LongTy).getLimitedValue();
492 RangeIntTy LongLongMax = BVF.
getMaxValue(LongLongTy).getLimitedValue();
535 #define SUMMARY_WITH_VARIANTS(identifier) {#identifier, { 536 #define END_SUMMARY_WITH_VARIANTS }}, 537 #define VARIANT(argument_types, return_type, invalidation_approach) \ 538 { argument_types, return_type, invalidation_approach, { 539 #define END_VARIANT } }, 540 #define SUMMARY(identifier, argument_types, return_type, \ 541 invalidation_approach) \ 542 { #identifier, { { argument_types, return_type, invalidation_approach, { 543 #define END_SUMMARY } } } }, 544 #define ARGUMENT_TYPES(...) { __VA_ARGS__ } 545 #define RETURN_TYPE(x) x 546 #define INVALIDATION_APPROACH(x) x 549 #define ARGUMENT_CONDITION(argument_number, condition_kind) \ 550 { argument_number, condition_kind, { 551 #define END_ARGUMENT_CONDITION }}, 552 #define RETURN_VALUE_CONDITION(condition_kind) \ 553 { Ret, condition_kind, { 554 #define END_RETURN_VALUE_CONDITION }}, 555 #define ARG_NO(x) x##U 556 #define RANGE(x, y) { x, y }, 557 #define SINGLE_VALUE(x) RANGE(x, x) 558 #define IS_LESS_THAN(arg) { BO_LE, arg } 560 FunctionSummaryMap = {
781 END_ARGUMENT_CONDITION 782 RETURN_VALUE_CONDITION(OutOfRange) 784 END_RETURN_VALUE_CONDITION 787 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 792 END_ARGUMENT_CONDITION 793 RETURN_VALUE_CONDITION(WithinRange) 795 END_RETURN_VALUE_CONDITION 798 SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 799 INVALIDATION_APPROACH(EvalCallAsPure)) 800 CASE // Space, '\f
', '\n
', '\r', '\t', '\v'. 801 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 804 END_ARGUMENT_CONDITION 805 RETURN_VALUE_CONDITION(OutOfRange) 807 END_RETURN_VALUE_CONDITION 809 CASE // The locale-specific range. 810 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 812 END_ARGUMENT_CONDITION 815 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 819 END_ARGUMENT_CONDITION 820 RETURN_VALUE_CONDITION(WithinRange) 822 END_RETURN_VALUE_CONDITION 825 SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy), 826 INVALIDATION_APPROACH(EvalCallAsPure)) 827 CASE // Is certainly uppercase. 828 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 830 END_ARGUMENT_CONDITION 831 RETURN_VALUE_CONDITION(OutOfRange) 833 END_RETURN_VALUE_CONDITION 835 CASE // The locale-specific range. 836 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 838 END_ARGUMENT_CONDITION 841 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 842 RANGE('A
', 'Z
') RANGE(128, 255) 843 END_ARGUMENT_CONDITION 844 RETURN_VALUE_CONDITION(WithinRange) 846 END_RETURN_VALUE_CONDITION 849 SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 850 INVALIDATION_APPROACH(EvalCallAsPure)) 852 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 856 END_ARGUMENT_CONDITION 857 RETURN_VALUE_CONDITION(OutOfRange) 859 END_RETURN_VALUE_CONDITION 862 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 866 END_ARGUMENT_CONDITION 867 RETURN_VALUE_CONDITION(WithinRange) 869 END_RETURN_VALUE_CONDITION 873 // The getc() family of functions that returns either a char or an EOF. 874 SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 875 INVALIDATION_APPROACH(NoEvalCall)) 876 CASE // FIXME: EOF is assumed to be defined as -1. 877 RETURN_VALUE_CONDITION(WithinRange) 879 END_RETURN_VALUE_CONDITION 882 SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 883 INVALIDATION_APPROACH(NoEvalCall)) 884 CASE // FIXME: EOF is assumed to be defined as -1. 885 RETURN_VALUE_CONDITION(WithinRange) 887 END_RETURN_VALUE_CONDITION 890 SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy), 891 INVALIDATION_APPROACH(NoEvalCall)) 892 CASE // FIXME: EOF is assumed to be defined as -1. 893 RETURN_VALUE_CONDITION(WithinRange) 895 END_RETURN_VALUE_CONDITION 899 // read()-like functions that never return more than buffer size. 900 // We are not sure how ssize_t is defined on every platform, so we provide 901 // three variants that should cover common cases. 902 SUMMARY_WITH_VARIANTS(read) 903 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 904 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 906 RETURN_VALUE_CONDITION(ComparesToArgument) 907 IS_LESS_THAN(ARG_NO(2)) 908 END_RETURN_VALUE_CONDITION 909 RETURN_VALUE_CONDITION(WithinRange) 911 END_RETURN_VALUE_CONDITION 914 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 915 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 917 RETURN_VALUE_CONDITION(ComparesToArgument) 918 IS_LESS_THAN(ARG_NO(2)) 919 END_RETURN_VALUE_CONDITION 920 RETURN_VALUE_CONDITION(WithinRange) 922 END_RETURN_VALUE_CONDITION 925 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 926 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 928 RETURN_VALUE_CONDITION(ComparesToArgument) 929 IS_LESS_THAN(ARG_NO(2)) 930 END_RETURN_VALUE_CONDITION 931 RETURN_VALUE_CONDITION(WithinRange) 932 RANGE(-1, LongLongMax) 933 END_RETURN_VALUE_CONDITION 936 END_SUMMARY_WITH_VARIANTS 937 SUMMARY_WITH_VARIANTS(write) 938 // Again, due to elusive nature of ssize_t, we have duplicate 939 // our summaries to cover different variants. 940 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 941 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 943 RETURN_VALUE_CONDITION(ComparesToArgument) 944 IS_LESS_THAN(ARG_NO(2)) 945 END_RETURN_VALUE_CONDITION 946 RETURN_VALUE_CONDITION(WithinRange) 948 END_RETURN_VALUE_CONDITION 951 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 952 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 954 RETURN_VALUE_CONDITION(ComparesToArgument) 955 IS_LESS_THAN(ARG_NO(2)) 956 END_RETURN_VALUE_CONDITION 957 RETURN_VALUE_CONDITION(WithinRange) 959 END_RETURN_VALUE_CONDITION 962 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 963 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 965 RETURN_VALUE_CONDITION(ComparesToArgument) 966 IS_LESS_THAN(ARG_NO(2)) 967 END_RETURN_VALUE_CONDITION 968 RETURN_VALUE_CONDITION(WithinRange) 969 RANGE(-1, LongLongMax) 970 END_RETURN_VALUE_CONDITION 973 END_SUMMARY_WITH_VARIANTS 975 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 976 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 978 RETURN_VALUE_CONDITION(ComparesToArgument) 979 IS_LESS_THAN(ARG_NO(2)) 980 END_RETURN_VALUE_CONDITION 984 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 985 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 987 RETURN_VALUE_CONDITION(ComparesToArgument) 988 IS_LESS_THAN(ARG_NO(2)) 989 END_RETURN_VALUE_CONDITION 993 // getline()-like functions either fail or read at least the delimiter. 994 SUMMARY_WITH_VARIANTS(getline) 995 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 996 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 998 RETURN_VALUE_CONDITION(WithinRange) 1001 END_RETURN_VALUE_CONDITION 1004 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 1005 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 1007 RETURN_VALUE_CONDITION(WithinRange) 1010 END_RETURN_VALUE_CONDITION 1013 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 1014 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 1016 RETURN_VALUE_CONDITION(WithinRange) 1018 RANGE(1, LongLongMax) 1019 END_RETURN_VALUE_CONDITION 1022 END_SUMMARY_WITH_VARIANTS 1023 SUMMARY_WITH_VARIANTS(getdelim) 1024 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1025 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 1027 RETURN_VALUE_CONDITION(WithinRange) 1030 END_RETURN_VALUE_CONDITION 1033 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1034 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 1036 RETURN_VALUE_CONDITION(WithinRange) 1039 END_RETURN_VALUE_CONDITION 1042 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1043 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 1045 RETURN_VALUE_CONDITION(WithinRange) 1047 RANGE(1, LongLongMax) 1048 END_RETURN_VALUE_CONDITION 1051 END_SUMMARY_WITH_VARIANTS 1055 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 1056 // If this checker grows large enough to support C++, Objective-C, or other 1057 // standard libraries, we could use multiple register...Checker() functions, 1058 // which would register various checkers with the help of the same Checker 1059 // class, turning on different function summaries. 1060 mgr.registerChecker<StdLibraryFunctionsChecker>(); 1063 bool ento::shouldRegisterStdCLibraryFunctionsChecker(const LangOptions &LO) {
Represents 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
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()
__DEVICE__ int max(int __a, int __b)
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.
#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(...)
constexpr XRayInstrMask None
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.
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
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>.