1 //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This checker improves modeling of a few simple library functions.
11 // It does not generate warnings.
13 // This checker provides a specification format - `FunctionSummaryTy' - and
14 // contains descriptions of some library functions in this format. Each
15 // specification contains a list of branches for splitting the program state
16 // upon call, and range constraints on argument and return-value symbols that
17 // are satisfied on each branch. This spec can be expanded to include more
18 // items, like external effects of the function.
20 // The main difference between this approach and the body farms technique is
21 // in more explicit control over how many branches are produced. For example,
22 // consider standard C function `ispunct(int x)', which returns a non-zero value
23 // iff `x' is a punctuation character, that is, when `x' is in range
24 // ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~'].
25 // `FunctionSummaryTy' provides only two branches for this function. However,
26 // any attempt to describe this range with if-statements in the body farm
27 // would result in many more branches. Because each branch needs to be analyzed
28 // independently, this significantly reduces performance. Additionally,
29 // once we consider a branch on which `x' is in range, say, ['!', '/'],
30 // we assume that such branch is an important separate path through the program,
31 // which may lead to false positives because considering this particular path
32 // was not consciously intended, and therefore it might have been unreachable.
34 // This checker uses eval::Call for modeling "pure" functions, for which
35 // their `FunctionSummaryTy' is a precise model. This avoids unnecessary
36 // invalidation passes. Conflicts with other checkers are unlikely because
37 // if the function has no other effects, other checkers would probably never
38 // want to improve upon the modeling done by this checker.
40 // Non-"pure" functions, for which only partial improvement over the default
41 // behavior is expected, are modeled via check::PostCall, non-intrusively.
43 // The following standard C functions are currently supported:
45 // fgetc getline isdigit isupper
46 // fread isalnum isgraph isxdigit
47 // fwrite isalpha islower read
48 // getc isascii isprint write
49 // getchar isblank ispunct
50 // getdelim iscntrl isspace
52 //===----------------------------------------------------------------------===//
54 #include "ClangSACheckers.h"
55 #include "clang/StaticAnalyzer/Core/Checker.h"
56 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
57 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
58 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
60 using namespace clang;
61 using namespace clang::ento;
64 class StdLibraryFunctionsChecker : public Checker<check::PostCall, eval::Call> {
65 /// Below is a series of typedefs necessary to define function specs.
66 /// We avoid nesting types here because each additional qualifier
67 /// would need to be repeated in every function spec.
68 struct FunctionSummaryTy;
70 /// Specify how much the analyzer engine should entrust modeling this function
71 /// to us. If he doesn't, he performs additional invalidations.
72 enum InvalidationKindTy { NoEvalCall, EvalCallAsPure };
74 /// A pair of ValueRangeKindTy and IntRangeVectorTy would describe a range
75 /// imposed on a particular argument or return value symbol.
77 /// Given a range, should the argument stay inside or outside this range?
78 /// The special `ComparesToArgument' value indicates that we should
79 /// impose a constraint that involves other argument or return value symbols.
80 enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument };
82 // The universal integral type to use in value range descriptions.
83 // Unsigned to make sure overflows are well-defined.
84 typedef uint64_t RangeIntTy;
86 /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
87 /// a non-negative integer, which less than 5 and not equal to 2. For
88 /// `ComparesToArgument', holds information about how exactly to compare to
90 typedef std::vector<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy;
92 /// A reference to an argument or return value by its number.
93 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
94 /// obviously uint32_t should be enough for all practical purposes.
95 typedef uint32_t ArgNoTy;
96 static const ArgNoTy Ret = std::numeric_limits<ArgNoTy>::max();
98 /// Incapsulates a single range on a single symbol within a branch.
100 ArgNoTy ArgNo; // Argument to which we apply the range.
101 ValueRangeKindTy Kind; // Kind of range definition.
102 IntRangeVectorTy Args; // Polymorphic arguments.
105 ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
106 const IntRangeVectorTy &Args)
107 : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
109 ArgNoTy getArgNo() const { return ArgNo; }
110 ValueRangeKindTy getKind() const { return Kind; }
112 BinaryOperator::Opcode getOpcode() const {
113 assert(Kind == ComparesToArgument);
114 assert(Args.size() == 1);
115 BinaryOperator::Opcode Op =
116 static_cast<BinaryOperator::Opcode>(Args[0].first);
117 assert(BinaryOperator::isComparisonOp(Op) &&
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);
133 // We avoid creating a virtual apply() method because
134 // it makes initializer lists harder to write.
137 applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call,
138 const FunctionSummaryTy &Summary) const;
140 applyAsWithinRange(ProgramStateRef State, const CallEvent &Call,
141 const FunctionSummaryTy &Summary) const;
143 applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call,
144 const FunctionSummaryTy &Summary) const;
147 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
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!");
161 /// The complete list of ranges that defines a single branch.
162 typedef std::vector<ValueRange> ValueRangeSet;
164 /// Includes information about function prototype (which is necessary to
165 /// ensure we're modeling the right function and casting values properly),
166 /// approach to invalidation, and a list of branches - essentially, a list
167 /// of list of ranges - essentially, a list of lists of lists of segments.
168 struct FunctionSummaryTy {
169 const std::vector<QualType> ArgTypes;
170 const QualType RetType;
171 const InvalidationKindTy InvalidationKind;
172 const std::vector<ValueRangeSet> Ranges;
175 static void assertTypeSuitableForSummary(QualType T) {
176 assert(!T->isVoidType() &&
177 "We should have had no significant void types in the spec");
178 assert(T.isCanonical() &&
179 "We should only have canonical types in the spec");
180 // FIXME: lift this assert (but not the ones above!)
181 assert(T->isIntegralOrEnumerationType() &&
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);
192 /// Try our best to figure out if the call expression is the call of
193 /// *the* library function to which this specification applies.
194 bool matchesCall(const CallExpr *CE) const;
197 // The same function (as in, function identifier) may have different
198 // summaries assigned to it, with different argument and return value types.
199 // We call these "variants" of the function. This can be useful for handling
200 // C++ function overloads, and also it can be used when the same function
201 // may have different definitions on different platforms.
202 typedef std::vector<FunctionSummaryTy> FunctionVariantsTy;
204 // The map of all functions supported by the checker. It is initialized
205 // lazily, and it doesn't change after initialization.
206 typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy;
207 mutable FunctionSummaryMapTy FunctionSummaryMap;
209 // Auxiliary functions to support ArgNoTy within all structures
210 // in a unified manner.
211 static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) {
212 return Summary.getArgType(ArgNo);
214 static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) {
215 return ArgNo == Ret ? Call.getResultType().getCanonicalType()
216 : Call.getArgExpr(ArgNo)->getType().getCanonicalType();
218 static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) {
219 return ArgNo == Ret ? CE->getType().getCanonicalType()
220 : CE->getArg(ArgNo)->getType().getCanonicalType();
222 static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) {
223 return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo);
227 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
228 bool evalCall(const CallExpr *CE, CheckerContext &C) const;
231 Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD,
233 CheckerContext &C) const;
235 void initFunctionSummaries(BasicValueFactory &BVF) const;
237 } // end of anonymous namespace
239 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
240 ProgramStateRef State, const CallEvent &Call,
241 const FunctionSummaryTy &Summary) const {
243 ProgramStateManager &Mgr = State->getStateManager();
244 SValBuilder &SVB = Mgr.getSValBuilder();
245 BasicValueFactory &BVF = SVB.getBasicValueFactory();
246 ConstraintManager &CM = Mgr.getConstraintManager();
247 QualType T = getArgType(Summary, getArgNo());
248 SVal V = getArgSVal(Call, getArgNo());
250 if (auto N = V.getAs<NonLoc>()) {
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);
257 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
267 StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
268 ProgramStateRef State, const CallEvent &Call,
269 const FunctionSummaryTy &Summary) const {
271 ProgramStateManager &Mgr = State->getStateManager();
272 SValBuilder &SVB = Mgr.getSValBuilder();
273 BasicValueFactory &BVF = SVB.getBasicValueFactory();
274 ConstraintManager &CM = Mgr.getConstraintManager();
275 QualType T = getArgType(Summary, getArgNo());
276 SVal V = getArgSVal(Call, getArgNo());
278 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
279 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
280 // and then cut away all holes in R one by one.
281 if (auto N = V.getAs<NonLoc>()) {
282 const IntRangeVectorTy &R = getRanges();
285 const llvm::APSInt &MinusInf = BVF.getMinValue(T);
286 const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
288 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
289 if (Left != PlusInf) {
290 assert(MinusInf <= Left);
291 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
296 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
297 if (Right != MinusInf) {
298 assert(Right <= PlusInf);
299 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
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);
308 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
318 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
319 ProgramStateRef State, const CallEvent &Call,
320 const FunctionSummaryTy &Summary) const {
322 ProgramStateManager &Mgr = State->getStateManager();
323 SValBuilder &SVB = Mgr.getSValBuilder();
324 QualType CondT = SVB.getConditionType();
325 QualType T = getArgType(Summary, getArgNo());
326 SVal V = getArgSVal(Call, getArgNo());
328 BinaryOperator::Opcode Op = getOpcode();
329 ArgNoTy OtherArg = getOtherArgNo();
330 SVal OtherV = getArgSVal(Call, OtherArg);
331 QualType OtherT = getArgType(Call, OtherArg);
332 // Note: we avoid integral promotion for comparison.
333 OtherV = SVB.evalCast(OtherV, T, OtherT);
334 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
335 .getAs<DefinedOrUnknownSVal>())
336 State = State->assume(*CompV, true);
340 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
341 CheckerContext &C) const {
342 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
346 const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
350 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
355 const FunctionSummaryTy &Summary = *FoundSummary;
356 ProgramStateRef State = C.getState();
358 for (const auto &VRS: Summary.Ranges) {
359 ProgramStateRef NewState = State;
360 for (const auto &VR: VRS) {
361 NewState = VR.apply(NewState, Call, Summary);
366 if (NewState && NewState != State)
367 C.addTransition(NewState);
371 bool StdLibraryFunctionsChecker::evalCall(const CallExpr *CE,
372 CheckerContext &C) const {
373 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl());
377 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
381 const FunctionSummaryTy &Summary = *FoundSummary;
382 switch (Summary.InvalidationKind) {
383 case EvalCallAsPure: {
384 ProgramStateRef State = C.getState();
385 const LocationContext *LC = C.getLocationContext();
386 SVal V = C.getSValBuilder().conjureSymbolVal(
387 CE, LC, CE->getType().getCanonicalType(), C.blockCount());
388 State = State->BindExpr(CE, LC, V);
389 C.addTransition(State);
393 // Summary tells us to avoid performing eval::Call. The function is possibly
394 // evaluated by another checker, or evaluated conservatively.
397 llvm_unreachable("Unknown invalidation kind!");
400 bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
401 const CallExpr *CE) const {
402 // Check number of arguments:
403 if (CE->getNumArgs() != ArgTypes.size())
406 // Check return type if relevant:
407 if (!RetType.isNull() && RetType != CE->getType().getCanonicalType())
410 // Check argument types when relevant:
411 for (size_t I = 0, E = ArgTypes.size(); I != E; ++I) {
412 QualType FormalT = ArgTypes[I];
413 // Null type marks irrelevant arguments.
414 if (FormalT.isNull())
417 assertTypeSuitableForSummary(FormalT);
419 QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I);
420 assert(ActualT.isCanonical());
421 if (ActualT != FormalT)
428 Optional<StdLibraryFunctionsChecker::FunctionSummaryTy>
429 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
431 CheckerContext &C) const {
432 // Note: we cannot always obtain FD from CE
433 // (eg. virtual call, or call by pointer).
439 SValBuilder &SVB = C.getSValBuilder();
440 BasicValueFactory &BVF = SVB.getBasicValueFactory();
441 initFunctionSummaries(BVF);
443 IdentifierInfo *II = FD->getIdentifier();
446 StringRef Name = II->getName();
447 if (Name.empty() || !C.isCLibraryFunction(FD, Name))
450 auto FSMI = FunctionSummaryMap.find(Name);
451 if (FSMI == FunctionSummaryMap.end())
454 // Verify that function signature matches the spec in advance.
455 // Otherwise we might be modeling the wrong function.
456 // Strict checking is important because we will be conducting
457 // very integral-type-sensitive operations on arguments and
459 const FunctionVariantsTy &SpecVariants = FSMI->second;
460 for (const FunctionSummaryTy &Spec : SpecVariants)
461 if (Spec.matchesCall(CE))
467 void StdLibraryFunctionsChecker::initFunctionSummaries(
468 BasicValueFactory &BVF) const {
469 if (!FunctionSummaryMap.empty())
472 ASTContext &ACtx = BVF.getContext();
474 // These types are useful for writing specifications quickly,
475 // New specifications should probably introduce more types.
476 // Some types are hard to obtain from the AST, eg. "ssize_t".
477 // In such cases it should be possible to provide multiple variants
478 // of function summary for common cases (eg. ssize_t could be int or long
479 // or long long, so three summary variants would be enough).
480 // Of course, function variants are also useful for C++ overloads.
481 QualType Irrelevant; // A placeholder, whenever we do not care about the type.
482 QualType IntTy = ACtx.IntTy;
483 QualType LongTy = ACtx.LongTy;
484 QualType LongLongTy = ACtx.LongLongTy;
485 QualType SizeTy = ACtx.getSizeType();
487 RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
488 RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
489 RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
491 // We are finally ready to define specifications for all supported functions.
493 // The signature needs to have the correct number of arguments.
494 // However, we insert `Irrelevant' when the type is insignificant.
496 // Argument ranges should always cover all variants. If return value
497 // is completely unknown, omit it from the respective range set.
499 // All types in the spec need to be canonical.
501 // Every item in the list of range sets represents a particular
502 // execution path the analyzer would need to explore once
503 // the call is modeled - a new program state is constructed
504 // for every range set, and each range line in the range set
505 // corresponds to a specific constraint within this state.
507 // Upon comparing to another argument, the other argument is casted
508 // to the current argument's type. This avoids proper promotion but
509 // seems useful. For example, read() receives size_t argument,
510 // and its return value, which is of type ssize_t, cannot be greater
511 // than this argument. If we made a promotion, and the size argument
512 // is equal to, say, 10, then we'd impose a range of [0, 10] on the
513 // return value, however the correct range is [-1, 10].
515 // Please update the list of functions in the header after editing!
517 // The format is as follows:
521 // { argument types list, ... },
522 // return type, purity, { range set list:
524 // { argument index, within or out of, {{from, to}, ...} },
525 // { argument index, compares to argument, {{how, which}} },
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 = {
558 // The isascii() family of functions.
559 SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
560 INVALIDATION_APPROACH(EvalCallAsPure))
561 CASE // Boils down to isupper() or islower() or isdigit()
562 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
566 END_ARGUMENT_CONDITION
567 RETURN_VALUE_CONDITION(OutOfRange)
569 END_RETURN_VALUE_CONDITION
571 CASE // The locale-specific range.
572 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
574 END_ARGUMENT_CONDITION
575 // No post-condition. We are completely unaware of
576 // locale-specific return values.
579 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
584 END_ARGUMENT_CONDITION
585 RETURN_VALUE_CONDITION(WithinRange)
587 END_RETURN_VALUE_CONDITION
590 SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
591 INVALIDATION_APPROACH(EvalCallAsPure))
592 CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
593 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
596 END_ARGUMENT_CONDITION
597 RETURN_VALUE_CONDITION(OutOfRange)
599 END_RETURN_VALUE_CONDITION
601 CASE // The locale-specific range.
602 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
604 END_ARGUMENT_CONDITION
607 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
611 END_ARGUMENT_CONDITION
612 RETURN_VALUE_CONDITION(WithinRange)
614 END_RETURN_VALUE_CONDITION
617 SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
618 INVALIDATION_APPROACH(EvalCallAsPure))
620 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
622 END_ARGUMENT_CONDITION
623 RETURN_VALUE_CONDITION(OutOfRange)
625 END_RETURN_VALUE_CONDITION
628 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
630 END_ARGUMENT_CONDITION
631 RETURN_VALUE_CONDITION(WithinRange)
633 END_RETURN_VALUE_CONDITION
636 SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
637 INVALIDATION_APPROACH(EvalCallAsPure))
639 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
642 END_ARGUMENT_CONDITION
643 RETURN_VALUE_CONDITION(OutOfRange)
645 END_RETURN_VALUE_CONDITION
648 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
651 END_ARGUMENT_CONDITION
652 RETURN_VALUE_CONDITION(WithinRange)
654 END_RETURN_VALUE_CONDITION
657 SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
658 INVALIDATION_APPROACH(EvalCallAsPure))
660 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
663 END_ARGUMENT_CONDITION
664 RETURN_VALUE_CONDITION(OutOfRange)
666 END_RETURN_VALUE_CONDITION
669 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
672 END_ARGUMENT_CONDITION
673 RETURN_VALUE_CONDITION(WithinRange)
675 END_RETURN_VALUE_CONDITION
678 SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
679 INVALIDATION_APPROACH(EvalCallAsPure))
681 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
683 END_ARGUMENT_CONDITION
684 RETURN_VALUE_CONDITION(OutOfRange)
686 END_RETURN_VALUE_CONDITION
689 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
691 END_ARGUMENT_CONDITION
692 RETURN_VALUE_CONDITION(WithinRange)
694 END_RETURN_VALUE_CONDITION
697 SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
698 INVALIDATION_APPROACH(EvalCallAsPure))
700 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
702 END_ARGUMENT_CONDITION
703 RETURN_VALUE_CONDITION(OutOfRange)
705 END_RETURN_VALUE_CONDITION
708 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
710 END_ARGUMENT_CONDITION
711 RETURN_VALUE_CONDITION(WithinRange)
713 END_RETURN_VALUE_CONDITION
716 SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
717 INVALIDATION_APPROACH(EvalCallAsPure))
718 CASE // Is certainly lowercase.
719 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
721 END_ARGUMENT_CONDITION
722 RETURN_VALUE_CONDITION(OutOfRange)
724 END_RETURN_VALUE_CONDITION
726 CASE // Is ascii but not lowercase.
727 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
729 END_ARGUMENT_CONDITION
730 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
732 END_ARGUMENT_CONDITION
733 RETURN_VALUE_CONDITION(WithinRange)
735 END_RETURN_VALUE_CONDITION
737 CASE // The locale-specific range.
738 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
740 END_ARGUMENT_CONDITION
742 CASE // Is not an unsigned char.
743 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
745 END_ARGUMENT_CONDITION
746 RETURN_VALUE_CONDITION(WithinRange)
748 END_RETURN_VALUE_CONDITION
751 SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
752 INVALIDATION_APPROACH(EvalCallAsPure))
754 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
756 END_ARGUMENT_CONDITION
757 RETURN_VALUE_CONDITION(OutOfRange)
759 END_RETURN_VALUE_CONDITION
762 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
764 END_ARGUMENT_CONDITION
765 RETURN_VALUE_CONDITION(WithinRange)
767 END_RETURN_VALUE_CONDITION
770 SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
771 INVALIDATION_APPROACH(EvalCallAsPure))
773 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
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>();