1 //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This checker improves modeling of a few simple library functions.
10 // It does not generate warnings.
12 // This checker provides a specification format - `FunctionSummaryTy' - and
13 // contains descriptions of some library functions in this format. Each
14 // specification contains a list of branches for splitting the program state
15 // upon call, and range constraints on argument and return-value symbols that
16 // are satisfied on each branch. This spec can be expanded to include more
17 // items, like external effects of the function.
19 // The main difference between this approach and the body farms technique is
20 // in more explicit control over how many branches are produced. For example,
21 // consider standard C function `ispunct(int x)', which returns a non-zero value
22 // iff `x' is a punctuation character, that is, when `x' is in range
23 // ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~'].
24 // `FunctionSummaryTy' provides only two branches for this function. However,
25 // any attempt to describe this range with if-statements in the body farm
26 // would result in many more branches. Because each branch needs to be analyzed
27 // independently, this significantly reduces performance. Additionally,
28 // once we consider a branch on which `x' is in range, say, ['!', '/'],
29 // we assume that such branch is an important separate path through the program,
30 // which may lead to false positives because considering this particular path
31 // was not consciously intended, and therefore it might have been unreachable.
33 // This checker uses eval::Call for modeling "pure" functions, for which
34 // their `FunctionSummaryTy' is a precise model. This avoids unnecessary
35 // invalidation passes. Conflicts with other checkers are unlikely because
36 // if the function has no other effects, other checkers would probably never
37 // want to improve upon the modeling done by this checker.
39 // Non-"pure" functions, for which only partial improvement over the default
40 // behavior is expected, are modeled via check::PostCall, non-intrusively.
42 // The following standard C functions are currently supported:
44 // fgetc getline isdigit isupper
45 // fread isalnum isgraph isxdigit
46 // fwrite isalpha islower read
47 // getc isascii isprint write
48 // getchar isblank ispunct
49 // getdelim iscntrl isspace
51 //===----------------------------------------------------------------------===//
53 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
54 #include "clang/StaticAnalyzer/Core/Checker.h"
55 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
56 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
57 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
59 using namespace clang;
60 using namespace clang::ento;
63 class StdLibraryFunctionsChecker : public Checker<check::PostCall, eval::Call> {
64 /// Below is a series of typedefs necessary to define function specs.
65 /// We avoid nesting types here because each additional qualifier
66 /// would need to be repeated in every function spec.
67 struct FunctionSummaryTy;
69 /// Specify how much the analyzer engine should entrust modeling this function
70 /// to us. If he doesn't, he performs additional invalidations.
71 enum InvalidationKindTy { NoEvalCall, EvalCallAsPure };
73 /// A pair of ValueRangeKindTy and IntRangeVectorTy would describe a range
74 /// imposed on a particular argument or return value symbol.
76 /// Given a range, should the argument stay inside or outside this range?
77 /// The special `ComparesToArgument' value indicates that we should
78 /// impose a constraint that involves other argument or return value symbols.
79 enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument };
81 // The universal integral type to use in value range descriptions.
82 // Unsigned to make sure overflows are well-defined.
83 typedef uint64_t RangeIntTy;
85 /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
86 /// a non-negative integer, which less than 5 and not equal to 2. For
87 /// `ComparesToArgument', holds information about how exactly to compare to
89 typedef std::vector<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy;
91 /// A reference to an argument or return value by its number.
92 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
93 /// obviously uint32_t should be enough for all practical purposes.
94 typedef uint32_t ArgNoTy;
95 static const ArgNoTy Ret = std::numeric_limits<ArgNoTy>::max();
97 /// Incapsulates a single range on a single symbol within a branch.
99 ArgNoTy ArgNo; // Argument to which we apply the range.
100 ValueRangeKindTy Kind; // Kind of range definition.
101 IntRangeVectorTy Args; // Polymorphic arguments.
104 ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
105 const IntRangeVectorTy &Args)
106 : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
108 ArgNoTy getArgNo() const { return ArgNo; }
109 ValueRangeKindTy getKind() const { return Kind; }
111 BinaryOperator::Opcode getOpcode() const {
112 assert(Kind == ComparesToArgument);
113 assert(Args.size() == 1);
114 BinaryOperator::Opcode Op =
115 static_cast<BinaryOperator::Opcode>(Args[0].first);
116 assert(BinaryOperator::isComparisonOp(Op) &&
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);
132 // We avoid creating a virtual apply() method because
133 // it makes initializer lists harder to write.
136 applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call,
137 const FunctionSummaryTy &Summary) const;
139 applyAsWithinRange(ProgramStateRef State, const CallEvent &Call,
140 const FunctionSummaryTy &Summary) const;
142 applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call,
143 const FunctionSummaryTy &Summary) const;
146 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
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!");
160 /// The complete list of ranges that defines a single branch.
161 typedef std::vector<ValueRange> ValueRangeSet;
163 /// Includes information about function prototype (which is necessary to
164 /// ensure we're modeling the right function and casting values properly),
165 /// approach to invalidation, and a list of branches - essentially, a list
166 /// of list of ranges - essentially, a list of lists of lists of segments.
167 struct FunctionSummaryTy {
168 const std::vector<QualType> ArgTypes;
169 const QualType RetType;
170 const InvalidationKindTy InvalidationKind;
171 const std::vector<ValueRangeSet> Ranges;
174 static void assertTypeSuitableForSummary(QualType T) {
175 assert(!T->isVoidType() &&
176 "We should have had no significant void types in the spec");
177 assert(T.isCanonical() &&
178 "We should only have canonical types in the spec");
179 // FIXME: lift this assert (but not the ones above!)
180 assert(T->isIntegralOrEnumerationType() &&
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);
191 /// Try our best to figure out if the call expression is the call of
192 /// *the* library function to which this specification applies.
193 bool matchesCall(const CallExpr *CE) const;
196 // The same function (as in, function identifier) may have different
197 // summaries assigned to it, with different argument and return value types.
198 // We call these "variants" of the function. This can be useful for handling
199 // C++ function overloads, and also it can be used when the same function
200 // may have different definitions on different platforms.
201 typedef std::vector<FunctionSummaryTy> FunctionVariantsTy;
203 // The map of all functions supported by the checker. It is initialized
204 // lazily, and it doesn't change after initialization.
205 typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy;
206 mutable FunctionSummaryMapTy FunctionSummaryMap;
208 // Auxiliary functions to support ArgNoTy within all structures
209 // in a unified manner.
210 static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) {
211 return Summary.getArgType(ArgNo);
213 static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) {
214 return ArgNo == Ret ? Call.getResultType().getCanonicalType()
215 : Call.getArgExpr(ArgNo)->getType().getCanonicalType();
217 static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) {
218 return ArgNo == Ret ? CE->getType().getCanonicalType()
219 : CE->getArg(ArgNo)->getType().getCanonicalType();
221 static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) {
222 return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo);
226 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
227 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
230 Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD,
232 CheckerContext &C) const;
234 void initFunctionSummaries(BasicValueFactory &BVF) const;
236 } // end of anonymous namespace
238 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
239 ProgramStateRef State, const CallEvent &Call,
240 const FunctionSummaryTy &Summary) const {
242 ProgramStateManager &Mgr = State->getStateManager();
243 SValBuilder &SVB = Mgr.getSValBuilder();
244 BasicValueFactory &BVF = SVB.getBasicValueFactory();
245 ConstraintManager &CM = Mgr.getConstraintManager();
246 QualType T = getArgType(Summary, getArgNo());
247 SVal V = getArgSVal(Call, getArgNo());
249 if (auto N = V.getAs<NonLoc>()) {
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);
256 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
266 StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
267 ProgramStateRef State, const CallEvent &Call,
268 const FunctionSummaryTy &Summary) const {
270 ProgramStateManager &Mgr = State->getStateManager();
271 SValBuilder &SVB = Mgr.getSValBuilder();
272 BasicValueFactory &BVF = SVB.getBasicValueFactory();
273 ConstraintManager &CM = Mgr.getConstraintManager();
274 QualType T = getArgType(Summary, getArgNo());
275 SVal V = getArgSVal(Call, getArgNo());
277 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
278 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
279 // and then cut away all holes in R one by one.
280 if (auto N = V.getAs<NonLoc>()) {
281 const IntRangeVectorTy &R = getRanges();
284 const llvm::APSInt &MinusInf = BVF.getMinValue(T);
285 const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
287 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
288 if (Left != PlusInf) {
289 assert(MinusInf <= Left);
290 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
295 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
296 if (Right != MinusInf) {
297 assert(Right <= PlusInf);
298 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
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);
307 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
317 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
318 ProgramStateRef State, const CallEvent &Call,
319 const FunctionSummaryTy &Summary) const {
321 ProgramStateManager &Mgr = State->getStateManager();
322 SValBuilder &SVB = Mgr.getSValBuilder();
323 QualType CondT = SVB.getConditionType();
324 QualType T = getArgType(Summary, getArgNo());
325 SVal V = getArgSVal(Call, getArgNo());
327 BinaryOperator::Opcode Op = getOpcode();
328 ArgNoTy OtherArg = getOtherArgNo();
329 SVal OtherV = getArgSVal(Call, OtherArg);
330 QualType OtherT = getArgType(Call, OtherArg);
331 // Note: we avoid integral promotion for comparison.
332 OtherV = SVB.evalCast(OtherV, T, OtherT);
333 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
334 .getAs<DefinedOrUnknownSVal>())
335 State = State->assume(*CompV, true);
339 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
340 CheckerContext &C) const {
341 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
345 const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
349 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
354 const FunctionSummaryTy &Summary = *FoundSummary;
355 ProgramStateRef State = C.getState();
357 for (const auto &VRS: Summary.Ranges) {
358 ProgramStateRef NewState = State;
359 for (const auto &VR: VRS) {
360 NewState = VR.apply(NewState, Call, Summary);
365 if (NewState && NewState != State)
366 C.addTransition(NewState);
370 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
371 CheckerContext &C) const {
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: {
387 ProgramStateRef State = C.getState();
388 const LocationContext *LC = C.getLocationContext();
389 SVal V = C.getSValBuilder().conjureSymbolVal(
390 CE, LC, CE->getType().getCanonicalType(), C.blockCount());
391 State = State->BindExpr(CE, LC, V);
392 C.addTransition(State);
396 // Summary tells us to avoid performing eval::Call. The function is possibly
397 // evaluated by another checker, or evaluated conservatively.
400 llvm_unreachable("Unknown invalidation kind!");
403 bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
404 const CallExpr *CE) const {
405 // Check number of arguments:
406 if (CE->getNumArgs() != ArgTypes.size())
409 // Check return type if relevant:
410 if (!RetType.isNull() && RetType != CE->getType().getCanonicalType())
413 // Check argument types when relevant:
414 for (size_t I = 0, E = ArgTypes.size(); I != E; ++I) {
415 QualType FormalT = ArgTypes[I];
416 // Null type marks irrelevant arguments.
417 if (FormalT.isNull())
420 assertTypeSuitableForSummary(FormalT);
422 QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I);
423 assert(ActualT.isCanonical());
424 if (ActualT != FormalT)
431 Optional<StdLibraryFunctionsChecker::FunctionSummaryTy>
432 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
434 CheckerContext &C) const {
435 // Note: we cannot always obtain FD from CE
436 // (eg. virtual call, or call by pointer).
442 SValBuilder &SVB = C.getSValBuilder();
443 BasicValueFactory &BVF = SVB.getBasicValueFactory();
444 initFunctionSummaries(BVF);
446 IdentifierInfo *II = FD->getIdentifier();
449 StringRef Name = II->getName();
450 if (Name.empty() || !C.isCLibraryFunction(FD, Name))
453 auto FSMI = FunctionSummaryMap.find(Name);
454 if (FSMI == FunctionSummaryMap.end())
457 // Verify that function signature matches the spec in advance.
458 // Otherwise we might be modeling the wrong function.
459 // Strict checking is important because we will be conducting
460 // very integral-type-sensitive operations on arguments and
462 const FunctionVariantsTy &SpecVariants = FSMI->second;
463 for (const FunctionSummaryTy &Spec : SpecVariants)
464 if (Spec.matchesCall(CE))
470 void StdLibraryFunctionsChecker::initFunctionSummaries(
471 BasicValueFactory &BVF) const {
472 if (!FunctionSummaryMap.empty())
475 ASTContext &ACtx = BVF.getContext();
477 // These types are useful for writing specifications quickly,
478 // New specifications should probably introduce more types.
479 // Some types are hard to obtain from the AST, eg. "ssize_t".
480 // In such cases it should be possible to provide multiple variants
481 // of function summary for common cases (eg. ssize_t could be int or long
482 // or long long, so three summary variants would be enough).
483 // Of course, function variants are also useful for C++ overloads.
484 QualType Irrelevant; // A placeholder, whenever we do not care about the type.
485 QualType IntTy = ACtx.IntTy;
486 QualType LongTy = ACtx.LongTy;
487 QualType LongLongTy = ACtx.LongLongTy;
488 QualType SizeTy = ACtx.getSizeType();
490 RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
491 RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
492 RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
494 // We are finally ready to define specifications for all supported functions.
496 // The signature needs to have the correct number of arguments.
497 // However, we insert `Irrelevant' when the type is insignificant.
499 // Argument ranges should always cover all variants. If return value
500 // is completely unknown, omit it from the respective range set.
502 // All types in the spec need to be canonical.
504 // Every item in the list of range sets represents a particular
505 // execution path the analyzer would need to explore once
506 // the call is modeled - a new program state is constructed
507 // for every range set, and each range line in the range set
508 // corresponds to a specific constraint within this state.
510 // Upon comparing to another argument, the other argument is casted
511 // to the current argument's type. This avoids proper promotion but
512 // seems useful. For example, read() receives size_t argument,
513 // and its return value, which is of type ssize_t, cannot be greater
514 // than this argument. If we made a promotion, and the size argument
515 // is equal to, say, 10, then we'd impose a range of [0, 10] on the
516 // return value, however the correct range is [-1, 10].
518 // Please update the list of functions in the header after editing!
520 // The format is as follows:
524 // { argument types list, ... },
525 // return type, purity, { range set list:
527 // { argument index, within or out of, {{from, to}, ...} },
528 // { argument index, compares to argument, {{how, which}} },
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 = {
561 // The isascii() family of functions.
562 SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
563 INVALIDATION_APPROACH(EvalCallAsPure))
564 CASE // Boils down to isupper() or islower() or isdigit()
565 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
569 END_ARGUMENT_CONDITION
570 RETURN_VALUE_CONDITION(OutOfRange)
572 END_RETURN_VALUE_CONDITION
574 CASE // The locale-specific range.
575 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
577 END_ARGUMENT_CONDITION
578 // No post-condition. We are completely unaware of
579 // locale-specific return values.
582 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
587 END_ARGUMENT_CONDITION
588 RETURN_VALUE_CONDITION(WithinRange)
590 END_RETURN_VALUE_CONDITION
593 SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
594 INVALIDATION_APPROACH(EvalCallAsPure))
595 CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
596 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
599 END_ARGUMENT_CONDITION
600 RETURN_VALUE_CONDITION(OutOfRange)
602 END_RETURN_VALUE_CONDITION
604 CASE // The locale-specific range.
605 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
607 END_ARGUMENT_CONDITION
610 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
614 END_ARGUMENT_CONDITION
615 RETURN_VALUE_CONDITION(WithinRange)
617 END_RETURN_VALUE_CONDITION
620 SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
621 INVALIDATION_APPROACH(EvalCallAsPure))
623 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
625 END_ARGUMENT_CONDITION
626 RETURN_VALUE_CONDITION(OutOfRange)
628 END_RETURN_VALUE_CONDITION
631 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
633 END_ARGUMENT_CONDITION
634 RETURN_VALUE_CONDITION(WithinRange)
636 END_RETURN_VALUE_CONDITION
639 SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
640 INVALIDATION_APPROACH(EvalCallAsPure))
642 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
645 END_ARGUMENT_CONDITION
646 RETURN_VALUE_CONDITION(OutOfRange)
648 END_RETURN_VALUE_CONDITION
651 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
654 END_ARGUMENT_CONDITION
655 RETURN_VALUE_CONDITION(WithinRange)
657 END_RETURN_VALUE_CONDITION
660 SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
661 INVALIDATION_APPROACH(EvalCallAsPure))
663 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
666 END_ARGUMENT_CONDITION
667 RETURN_VALUE_CONDITION(OutOfRange)
669 END_RETURN_VALUE_CONDITION
672 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
675 END_ARGUMENT_CONDITION
676 RETURN_VALUE_CONDITION(WithinRange)
678 END_RETURN_VALUE_CONDITION
681 SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
682 INVALIDATION_APPROACH(EvalCallAsPure))
684 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
686 END_ARGUMENT_CONDITION
687 RETURN_VALUE_CONDITION(OutOfRange)
689 END_RETURN_VALUE_CONDITION
692 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
694 END_ARGUMENT_CONDITION
695 RETURN_VALUE_CONDITION(WithinRange)
697 END_RETURN_VALUE_CONDITION
700 SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
701 INVALIDATION_APPROACH(EvalCallAsPure))
703 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
705 END_ARGUMENT_CONDITION
706 RETURN_VALUE_CONDITION(OutOfRange)
708 END_RETURN_VALUE_CONDITION
711 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
713 END_ARGUMENT_CONDITION
714 RETURN_VALUE_CONDITION(WithinRange)
716 END_RETURN_VALUE_CONDITION
719 SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
720 INVALIDATION_APPROACH(EvalCallAsPure))
721 CASE // Is certainly lowercase.
722 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
724 END_ARGUMENT_CONDITION
725 RETURN_VALUE_CONDITION(OutOfRange)
727 END_RETURN_VALUE_CONDITION
729 CASE // Is ascii but not lowercase.
730 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
732 END_ARGUMENT_CONDITION
733 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
735 END_ARGUMENT_CONDITION
736 RETURN_VALUE_CONDITION(WithinRange)
738 END_RETURN_VALUE_CONDITION
740 CASE // The locale-specific range.
741 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
743 END_ARGUMENT_CONDITION
745 CASE // Is not an unsigned char.
746 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
748 END_ARGUMENT_CONDITION
749 RETURN_VALUE_CONDITION(WithinRange)
751 END_RETURN_VALUE_CONDITION
754 SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
755 INVALIDATION_APPROACH(EvalCallAsPure))
757 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
759 END_ARGUMENT_CONDITION
760 RETURN_VALUE_CONDITION(OutOfRange)
762 END_RETURN_VALUE_CONDITION
765 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
767 END_ARGUMENT_CONDITION
768 RETURN_VALUE_CONDITION(WithinRange)
770 END_RETURN_VALUE_CONDITION
773 SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
774 INVALIDATION_APPROACH(EvalCallAsPure))
776 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
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) {