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 std::string Name = FD->getQualifiedNameAsString();
444 if (Name.empty() || !C.isCLibraryFunction(FD, Name))
447 auto FSMI = FunctionSummaryMap.find(Name);
448 if (FSMI == FunctionSummaryMap.end())
451 // Verify that function signature matches the spec in advance.
452 // Otherwise we might be modeling the wrong function.
453 // Strict checking is important because we will be conducting
454 // very integral-type-sensitive operations on arguments and
456 const FunctionVariantsTy &SpecVariants = FSMI->second;
457 for (const FunctionSummaryTy &Spec : SpecVariants)
458 if (Spec.matchesCall(CE))
464 void StdLibraryFunctionsChecker::initFunctionSummaries(
465 BasicValueFactory &BVF) const {
466 if (!FunctionSummaryMap.empty())
469 ASTContext &ACtx = BVF.getContext();
471 // These types are useful for writing specifications quickly,
472 // New specifications should probably introduce more types.
473 // Some types are hard to obtain from the AST, eg. "ssize_t".
474 // In such cases it should be possible to provide multiple variants
475 // of function summary for common cases (eg. ssize_t could be int or long
476 // or long long, so three summary variants would be enough).
477 // Of course, function variants are also useful for C++ overloads.
478 QualType Irrelevant; // A placeholder, whenever we do not care about the type.
479 QualType IntTy = ACtx.IntTy;
480 QualType LongTy = ACtx.LongTy;
481 QualType LongLongTy = ACtx.LongLongTy;
482 QualType SizeTy = ACtx.getSizeType();
484 RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
485 RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
486 RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
488 // We are finally ready to define specifications for all supported functions.
490 // The signature needs to have the correct number of arguments.
491 // However, we insert `Irrelevant' when the type is insignificant.
493 // Argument ranges should always cover all variants. If return value
494 // is completely unknown, omit it from the respective range set.
496 // All types in the spec need to be canonical.
498 // Every item in the list of range sets represents a particular
499 // execution path the analyzer would need to explore once
500 // the call is modeled - a new program state is constructed
501 // for every range set, and each range line in the range set
502 // corresponds to a specific constraint within this state.
504 // Upon comparing to another argument, the other argument is casted
505 // to the current argument's type. This avoids proper promotion but
506 // seems useful. For example, read() receives size_t argument,
507 // and its return value, which is of type ssize_t, cannot be greater
508 // than this argument. If we made a promotion, and the size argument
509 // is equal to, say, 10, then we'd impose a range of [0, 10] on the
510 // return value, however the correct range is [-1, 10].
512 // Please update the list of functions in the header after editing!
514 // The format is as follows:
518 // { argument types list, ... },
519 // return type, purity, { range set list:
521 // { argument index, within or out of, {{from, to}, ...} },
522 // { argument index, compares to argument, {{how, which}} },
529 #define SUMMARY_WITH_VARIANTS(identifier) {#identifier, {
530 #define END_SUMMARY_WITH_VARIANTS }},
531 #define VARIANT(argument_types, return_type, invalidation_approach) \
532 { argument_types, return_type, invalidation_approach, {
533 #define END_VARIANT } },
534 #define SUMMARY(identifier, argument_types, return_type, \
535 invalidation_approach) \
536 { #identifier, { { argument_types, return_type, invalidation_approach, {
537 #define END_SUMMARY } } } },
538 #define ARGUMENT_TYPES(...) { __VA_ARGS__ }
539 #define RETURN_TYPE(x) x
540 #define INVALIDATION_APPROACH(x) x
543 #define ARGUMENT_CONDITION(argument_number, condition_kind) \
544 { argument_number, condition_kind, {
545 #define END_ARGUMENT_CONDITION }},
546 #define RETURN_VALUE_CONDITION(condition_kind) \
547 { Ret, condition_kind, {
548 #define END_RETURN_VALUE_CONDITION }},
549 #define ARG_NO(x) x##U
550 #define RANGE(x, y) { x, y },
551 #define SINGLE_VALUE(x) RANGE(x, x)
552 #define IS_LESS_THAN(arg) { BO_LE, arg }
554 FunctionSummaryMap = {
555 // The isascii() family of functions.
556 SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
557 INVALIDATION_APPROACH(EvalCallAsPure))
558 CASE // Boils down to isupper() or islower() or isdigit()
559 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
563 END_ARGUMENT_CONDITION
564 RETURN_VALUE_CONDITION(OutOfRange)
566 END_RETURN_VALUE_CONDITION
568 CASE // The locale-specific range.
569 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
571 END_ARGUMENT_CONDITION
572 // No post-condition. We are completely unaware of
573 // locale-specific return values.
576 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
581 END_ARGUMENT_CONDITION
582 RETURN_VALUE_CONDITION(WithinRange)
584 END_RETURN_VALUE_CONDITION
587 SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
588 INVALIDATION_APPROACH(EvalCallAsPure))
589 CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
590 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
593 END_ARGUMENT_CONDITION
594 RETURN_VALUE_CONDITION(OutOfRange)
596 END_RETURN_VALUE_CONDITION
598 CASE // The locale-specific range.
599 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
601 END_ARGUMENT_CONDITION
604 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
608 END_ARGUMENT_CONDITION
609 RETURN_VALUE_CONDITION(WithinRange)
611 END_RETURN_VALUE_CONDITION
614 SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
615 INVALIDATION_APPROACH(EvalCallAsPure))
617 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
619 END_ARGUMENT_CONDITION
620 RETURN_VALUE_CONDITION(OutOfRange)
622 END_RETURN_VALUE_CONDITION
625 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
627 END_ARGUMENT_CONDITION
628 RETURN_VALUE_CONDITION(WithinRange)
630 END_RETURN_VALUE_CONDITION
633 SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
634 INVALIDATION_APPROACH(EvalCallAsPure))
636 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
639 END_ARGUMENT_CONDITION
640 RETURN_VALUE_CONDITION(OutOfRange)
642 END_RETURN_VALUE_CONDITION
645 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
648 END_ARGUMENT_CONDITION
649 RETURN_VALUE_CONDITION(WithinRange)
651 END_RETURN_VALUE_CONDITION
654 SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
655 INVALIDATION_APPROACH(EvalCallAsPure))
657 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
660 END_ARGUMENT_CONDITION
661 RETURN_VALUE_CONDITION(OutOfRange)
663 END_RETURN_VALUE_CONDITION
666 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
669 END_ARGUMENT_CONDITION
670 RETURN_VALUE_CONDITION(WithinRange)
672 END_RETURN_VALUE_CONDITION
675 SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
676 INVALIDATION_APPROACH(EvalCallAsPure))
678 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
680 END_ARGUMENT_CONDITION
681 RETURN_VALUE_CONDITION(OutOfRange)
683 END_RETURN_VALUE_CONDITION
686 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
688 END_ARGUMENT_CONDITION
689 RETURN_VALUE_CONDITION(WithinRange)
691 END_RETURN_VALUE_CONDITION
694 SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
695 INVALIDATION_APPROACH(EvalCallAsPure))
697 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
699 END_ARGUMENT_CONDITION
700 RETURN_VALUE_CONDITION(OutOfRange)
702 END_RETURN_VALUE_CONDITION
705 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
707 END_ARGUMENT_CONDITION
708 RETURN_VALUE_CONDITION(WithinRange)
710 END_RETURN_VALUE_CONDITION
713 SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
714 INVALIDATION_APPROACH(EvalCallAsPure))
715 CASE // Is certainly lowercase.
716 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
718 END_ARGUMENT_CONDITION
719 RETURN_VALUE_CONDITION(OutOfRange)
721 END_RETURN_VALUE_CONDITION
723 CASE // Is ascii but not lowercase.
724 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
726 END_ARGUMENT_CONDITION
727 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
729 END_ARGUMENT_CONDITION
730 RETURN_VALUE_CONDITION(WithinRange)
732 END_RETURN_VALUE_CONDITION
734 CASE // The locale-specific range.
735 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
737 END_ARGUMENT_CONDITION
739 CASE // Is not an unsigned char.
740 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
742 END_ARGUMENT_CONDITION
743 RETURN_VALUE_CONDITION(WithinRange)
745 END_RETURN_VALUE_CONDITION
748 SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
749 INVALIDATION_APPROACH(EvalCallAsPure))
751 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
753 END_ARGUMENT_CONDITION
754 RETURN_VALUE_CONDITION(OutOfRange)
756 END_RETURN_VALUE_CONDITION
759 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
761 END_ARGUMENT_CONDITION
762 RETURN_VALUE_CONDITION(WithinRange)
764 END_RETURN_VALUE_CONDITION
767 SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
768 INVALIDATION_APPROACH(EvalCallAsPure))
770 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
775 END_ARGUMENT_CONDITION
776 RETURN_VALUE_CONDITION(OutOfRange)
778 END_RETURN_VALUE_CONDITION
781 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
786 END_ARGUMENT_CONDITION
787 RETURN_VALUE_CONDITION(WithinRange)
789 END_RETURN_VALUE_CONDITION
792 SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
793 INVALIDATION_APPROACH(EvalCallAsPure))
794 CASE // Space, '\f', '\n', '\r', '\t', '\v'.
795 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
798 END_ARGUMENT_CONDITION
799 RETURN_VALUE_CONDITION(OutOfRange)
801 END_RETURN_VALUE_CONDITION
803 CASE // The locale-specific range.
804 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
806 END_ARGUMENT_CONDITION
809 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
813 END_ARGUMENT_CONDITION
814 RETURN_VALUE_CONDITION(WithinRange)
816 END_RETURN_VALUE_CONDITION
819 SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy),
820 INVALIDATION_APPROACH(EvalCallAsPure))
821 CASE // Is certainly uppercase.
822 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
824 END_ARGUMENT_CONDITION
825 RETURN_VALUE_CONDITION(OutOfRange)
827 END_RETURN_VALUE_CONDITION
829 CASE // The locale-specific range.
830 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
832 END_ARGUMENT_CONDITION
835 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
836 RANGE('A', 'Z') RANGE(128, 255)
837 END_ARGUMENT_CONDITION
838 RETURN_VALUE_CONDITION(WithinRange)
840 END_RETURN_VALUE_CONDITION
843 SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
844 INVALIDATION_APPROACH(EvalCallAsPure))
846 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
850 END_ARGUMENT_CONDITION
851 RETURN_VALUE_CONDITION(OutOfRange)
853 END_RETURN_VALUE_CONDITION
856 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
860 END_ARGUMENT_CONDITION
861 RETURN_VALUE_CONDITION(WithinRange)
863 END_RETURN_VALUE_CONDITION
867 // The getc() family of functions that returns either a char or an EOF.
868 SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
869 INVALIDATION_APPROACH(NoEvalCall))
870 CASE // FIXME: EOF is assumed to be defined as -1.
871 RETURN_VALUE_CONDITION(WithinRange)
873 END_RETURN_VALUE_CONDITION
876 SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
877 INVALIDATION_APPROACH(NoEvalCall))
878 CASE // FIXME: EOF is assumed to be defined as -1.
879 RETURN_VALUE_CONDITION(WithinRange)
881 END_RETURN_VALUE_CONDITION
884 SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy),
885 INVALIDATION_APPROACH(NoEvalCall))
886 CASE // FIXME: EOF is assumed to be defined as -1.
887 RETURN_VALUE_CONDITION(WithinRange)
889 END_RETURN_VALUE_CONDITION
893 // read()-like functions that never return more than buffer size.
894 // We are not sure how ssize_t is defined on every platform, so we provide
895 // three variants that should cover common cases.
896 SUMMARY_WITH_VARIANTS(read)
897 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
898 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
900 RETURN_VALUE_CONDITION(ComparesToArgument)
901 IS_LESS_THAN(ARG_NO(2))
902 END_RETURN_VALUE_CONDITION
903 RETURN_VALUE_CONDITION(WithinRange)
905 END_RETURN_VALUE_CONDITION
908 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
909 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
911 RETURN_VALUE_CONDITION(ComparesToArgument)
912 IS_LESS_THAN(ARG_NO(2))
913 END_RETURN_VALUE_CONDITION
914 RETURN_VALUE_CONDITION(WithinRange)
916 END_RETURN_VALUE_CONDITION
919 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
920 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
922 RETURN_VALUE_CONDITION(ComparesToArgument)
923 IS_LESS_THAN(ARG_NO(2))
924 END_RETURN_VALUE_CONDITION
925 RETURN_VALUE_CONDITION(WithinRange)
926 RANGE(-1, LongLongMax)
927 END_RETURN_VALUE_CONDITION
930 END_SUMMARY_WITH_VARIANTS
931 SUMMARY_WITH_VARIANTS(write)
932 // Again, due to elusive nature of ssize_t, we have duplicate
933 // our summaries to cover different variants.
934 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
935 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
937 RETURN_VALUE_CONDITION(ComparesToArgument)
938 IS_LESS_THAN(ARG_NO(2))
939 END_RETURN_VALUE_CONDITION
940 RETURN_VALUE_CONDITION(WithinRange)
942 END_RETURN_VALUE_CONDITION
945 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
946 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
948 RETURN_VALUE_CONDITION(ComparesToArgument)
949 IS_LESS_THAN(ARG_NO(2))
950 END_RETURN_VALUE_CONDITION
951 RETURN_VALUE_CONDITION(WithinRange)
953 END_RETURN_VALUE_CONDITION
956 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
957 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
959 RETURN_VALUE_CONDITION(ComparesToArgument)
960 IS_LESS_THAN(ARG_NO(2))
961 END_RETURN_VALUE_CONDITION
962 RETURN_VALUE_CONDITION(WithinRange)
963 RANGE(-1, LongLongMax)
964 END_RETURN_VALUE_CONDITION
967 END_SUMMARY_WITH_VARIANTS
969 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
970 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
972 RETURN_VALUE_CONDITION(ComparesToArgument)
973 IS_LESS_THAN(ARG_NO(2))
974 END_RETURN_VALUE_CONDITION
978 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
979 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
981 RETURN_VALUE_CONDITION(ComparesToArgument)
982 IS_LESS_THAN(ARG_NO(2))
983 END_RETURN_VALUE_CONDITION
987 // getline()-like functions either fail or read at least the delimiter.
988 SUMMARY_WITH_VARIANTS(getline)
989 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
990 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
992 RETURN_VALUE_CONDITION(WithinRange)
995 END_RETURN_VALUE_CONDITION
998 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
999 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1001 RETURN_VALUE_CONDITION(WithinRange)
1004 END_RETURN_VALUE_CONDITION
1007 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
1008 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1010 RETURN_VALUE_CONDITION(WithinRange)
1012 RANGE(1, LongLongMax)
1013 END_RETURN_VALUE_CONDITION
1016 END_SUMMARY_WITH_VARIANTS
1017 SUMMARY_WITH_VARIANTS(getdelim)
1018 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1019 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
1021 RETURN_VALUE_CONDITION(WithinRange)
1024 END_RETURN_VALUE_CONDITION
1027 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1028 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1030 RETURN_VALUE_CONDITION(WithinRange)
1033 END_RETURN_VALUE_CONDITION
1036 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1037 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1039 RETURN_VALUE_CONDITION(WithinRange)
1041 RANGE(1, LongLongMax)
1042 END_RETURN_VALUE_CONDITION
1045 END_SUMMARY_WITH_VARIANTS
1049 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
1050 // If this checker grows large enough to support C++, Objective-C, or other
1051 // standard libraries, we could use multiple register...Checker() functions,
1052 // which would register various checkers with the help of the same Checker
1053 // class, turning on different function summaries.
1054 mgr.registerChecker<StdLibraryFunctionsChecker>();