]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
MFV r319951: 8311 ZFS_READONLY is a little too strict
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / StdLibraryFunctionsChecker.cpp
1 //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This checker improves modeling of a few simple library functions.
11 // It does not generate warnings.
12 //
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.
19 //
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.
33 //
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.
39 //
40 // Non-"pure" functions, for which only partial improvement over the default
41 // behavior is expected, are modeled via check::PostCall, non-intrusively.
42 //
43 // The following standard C functions are currently supported:
44 //
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
51 //
52 //===----------------------------------------------------------------------===//
53
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"
59
60 using namespace clang;
61 using namespace clang::ento;
62
63 namespace {
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;
69
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 };
73
74   /// A pair of ValueRangeKindTy and IntRangeVectorTy would describe a range
75   /// imposed on a particular argument or return value symbol.
76   ///
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 };
81
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;
85
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
89   /// the argument.
90   typedef std::vector<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy;
91
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();
97
98   /// Incapsulates a single range on a single symbol within a branch.
99   class ValueRange {
100     ArgNoTy ArgNo; // Argument to which we apply the range.
101     ValueRangeKindTy Kind; // Kind of range definition.
102     IntRangeVectorTy Args; // Polymorphic arguments.
103
104   public:
105     ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
106                const IntRangeVectorTy &Args)
107         : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
108
109     ArgNoTy getArgNo() const { return ArgNo; }
110     ValueRangeKindTy getKind() const { return Kind; }
111
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");
119       return Op;
120     }
121
122     ArgNoTy getOtherArgNo() const {
123       assert(Kind == ComparesToArgument);
124       assert(Args.size() == 1);
125       return static_cast<ArgNoTy>(Args[0].second);
126     }
127
128     const IntRangeVectorTy &getRanges() const {
129       assert(Kind != ComparesToArgument);
130       return Args;
131     }
132
133     // We avoid creating a virtual apply() method because
134     // it makes initializer lists harder to write.
135   private:
136     ProgramStateRef
137     applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call,
138                       const FunctionSummaryTy &Summary) const;
139     ProgramStateRef
140     applyAsWithinRange(ProgramStateRef State, const CallEvent &Call,
141                        const FunctionSummaryTy &Summary) const;
142     ProgramStateRef
143     applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call,
144                               const FunctionSummaryTy &Summary) const;
145
146   public:
147     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
148                           const FunctionSummaryTy &Summary) const {
149       switch (Kind) {
150       case OutOfRange:
151         return applyAsOutOfRange(State, Call, Summary);
152       case WithinRange:
153         return applyAsWithinRange(State, Call, Summary);
154       case ComparesToArgument:
155         return applyAsComparesToArgument(State, Call, Summary);
156       }
157       llvm_unreachable("Unknown ValueRange kind!");
158     }
159   };
160
161   /// The complete list of ranges that defines a single branch.
162   typedef std::vector<ValueRange> ValueRangeSet;
163
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;
173
174   private:
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");
183     }
184
185   public:
186     QualType getArgType(ArgNoTy ArgNo) const {
187       QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo];
188       assertTypeSuitableForSummary(T);
189       return T;
190     }
191
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;
195   };
196
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;
203
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;
208
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);
213   }
214   static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) {
215     return ArgNo == Ret ? Call.getResultType().getCanonicalType()
216                         : Call.getArgExpr(ArgNo)->getType().getCanonicalType();
217   }
218   static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) {
219     return ArgNo == Ret ? CE->getType().getCanonicalType()
220                         : CE->getArg(ArgNo)->getType().getCanonicalType();
221   }
222   static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) {
223     return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo);
224   }
225
226 public:
227   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
228   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
229
230 private:
231   Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD,
232                                           const CallExpr *CE,
233                                           CheckerContext &C) const;
234
235   void initFunctionSummaries(BasicValueFactory &BVF) const;
236 };
237 } // end of anonymous namespace
238
239 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
240     ProgramStateRef State, const CallEvent &Call,
241     const FunctionSummaryTy &Summary) const {
242
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());
249
250   if (auto N = V.getAs<NonLoc>()) {
251     const IntRangeVectorTy &R = getRanges();
252     size_t E = R.size();
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);
256       assert(Min <= Max);
257       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
258       if (!State)
259         break;
260     }
261   }
262
263   return State;
264 }
265
266 ProgramStateRef
267 StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
268     ProgramStateRef State, const CallEvent &Call,
269     const FunctionSummaryTy &Summary) const {
270
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());
277
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();
283     size_t E = R.size();
284
285     const llvm::APSInt &MinusInf = BVF.getMinValue(T);
286     const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
287
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);
292       if (!State)
293         return nullptr;
294     }
295
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);
300       if (!State)
301         return nullptr;
302     }
303
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);
307       assert(Min <= Max);
308       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
309       if (!State)
310         return nullptr;
311     }
312   }
313
314   return State;
315 }
316
317 ProgramStateRef
318 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
319     ProgramStateRef State, const CallEvent &Call,
320     const FunctionSummaryTy &Summary) const {
321
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());
327
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);
337   return State;
338 }
339
340 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
341                                                CheckerContext &C) const {
342   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
343   if (!FD)
344     return;
345
346   const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
347   if (!CE)
348     return;
349
350   Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
351   if (!FoundSummary)
352     return;
353
354   // Now apply ranges.
355   const FunctionSummaryTy &Summary = *FoundSummary;
356   ProgramStateRef State = C.getState();
357
358   for (const auto &VRS: Summary.Ranges) {
359     ProgramStateRef NewState = State;
360     for (const auto &VR: VRS) {
361       NewState = VR.apply(NewState, Call, Summary);
362       if (!NewState)
363         break;
364     }
365
366     if (NewState && NewState != State)
367       C.addTransition(NewState);
368   }
369 }
370
371 bool StdLibraryFunctionsChecker::evalCall(const CallExpr *CE,
372                                           CheckerContext &C) const {
373   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl());
374   if (!FD)
375     return false;
376
377   Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
378   if (!FoundSummary)
379     return false;
380
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);
390     return true;
391   }
392   case NoEvalCall:
393     // Summary tells us to avoid performing eval::Call. The function is possibly
394     // evaluated by another checker, or evaluated conservatively.
395     return false;
396   }
397   llvm_unreachable("Unknown invalidation kind!");
398 }
399
400 bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
401     const CallExpr *CE) const {
402   // Check number of arguments:
403   if (CE->getNumArgs() != ArgTypes.size())
404     return false;
405
406   // Check return type if relevant:
407   if (!RetType.isNull() && RetType != CE->getType().getCanonicalType())
408     return false;
409
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())
415       continue;
416
417     assertTypeSuitableForSummary(FormalT);
418
419     QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I);
420     assert(ActualT.isCanonical());
421     if (ActualT != FormalT)
422       return false;
423   }
424
425   return true;
426 }
427
428 Optional<StdLibraryFunctionsChecker::FunctionSummaryTy>
429 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
430                                                 const CallExpr *CE,
431                                                 CheckerContext &C) const {
432   // Note: we cannot always obtain FD from CE
433   // (eg. virtual call, or call by pointer).
434   assert(CE);
435
436   if (!FD)
437     return None;
438
439   SValBuilder &SVB = C.getSValBuilder();
440   BasicValueFactory &BVF = SVB.getBasicValueFactory();
441   initFunctionSummaries(BVF);
442
443   std::string Name = FD->getQualifiedNameAsString();
444   if (Name.empty() || !C.isCLibraryFunction(FD, Name))
445     return None;
446
447   auto FSMI = FunctionSummaryMap.find(Name);
448   if (FSMI == FunctionSummaryMap.end())
449     return None;
450
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
455   // return values.
456   const FunctionVariantsTy &SpecVariants = FSMI->second;
457   for (const FunctionSummaryTy &Spec : SpecVariants)
458     if (Spec.matchesCall(CE))
459       return Spec;
460
461   return None;
462 }
463
464 void StdLibraryFunctionsChecker::initFunctionSummaries(
465     BasicValueFactory &BVF) const {
466   if (!FunctionSummaryMap.empty())
467     return;
468
469   ASTContext &ACtx = BVF.getContext();
470
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();
483
484   RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
485   RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
486   RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
487
488   // We are finally ready to define specifications for all supported functions.
489   //
490   // The signature needs to have the correct number of arguments.
491   // However, we insert `Irrelevant' when the type is insignificant.
492   //
493   // Argument ranges should always cover all variants. If return value
494   // is completely unknown, omit it from the respective range set.
495   //
496   // All types in the spec need to be canonical.
497   //
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.
503   //
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].
511   //
512   // Please update the list of functions in the header after editing!
513   //
514   // The format is as follows:
515   //
516   //{ "function name",
517   //  { spec:
518   //    { argument types list, ... },
519   //    return type, purity, { range set list:
520   //      { range list:
521   //        { argument index, within or out of, {{from, to}, ...} },
522   //        { argument index, compares to argument, {{how, which}} },
523   //        ...
524   //      }
525   //    }
526   //  }
527   //}
528
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
541 #define CASE {
542 #define END_CASE },
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 }
553
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)
560           RANGE('0', '9')
561           RANGE('A', 'Z')
562           RANGE('a', 'z')
563         END_ARGUMENT_CONDITION
564         RETURN_VALUE_CONDITION(OutOfRange)
565           SINGLE_VALUE(0)
566         END_RETURN_VALUE_CONDITION
567       END_CASE
568       CASE // The locale-specific range.
569         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
570           RANGE(128, 255)
571         END_ARGUMENT_CONDITION
572         // No post-condition. We are completely unaware of
573         // locale-specific return values.
574       END_CASE
575       CASE
576         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
577           RANGE('0', '9')
578           RANGE('A', 'Z')
579           RANGE('a', 'z')
580           RANGE(128, 255)
581         END_ARGUMENT_CONDITION
582         RETURN_VALUE_CONDITION(WithinRange)
583           SINGLE_VALUE(0)
584         END_RETURN_VALUE_CONDITION
585       END_CASE
586     END_SUMMARY
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)
591           RANGE('A', 'Z')
592           RANGE('a', 'z')
593         END_ARGUMENT_CONDITION
594         RETURN_VALUE_CONDITION(OutOfRange)
595           SINGLE_VALUE(0)
596         END_RETURN_VALUE_CONDITION
597       END_CASE
598       CASE // The locale-specific range.
599         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
600           RANGE(128, 255)
601         END_ARGUMENT_CONDITION
602       END_CASE
603       CASE // Other.
604         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
605           RANGE('A', 'Z')
606           RANGE('a', 'z')
607           RANGE(128, 255)
608         END_ARGUMENT_CONDITION
609         RETURN_VALUE_CONDITION(WithinRange)
610           SINGLE_VALUE(0)
611         END_RETURN_VALUE_CONDITION
612       END_CASE
613     END_SUMMARY
614     SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
615             INVALIDATION_APPROACH(EvalCallAsPure))
616       CASE // Is ASCII.
617         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
618           RANGE(0, 127)
619         END_ARGUMENT_CONDITION
620         RETURN_VALUE_CONDITION(OutOfRange)
621           SINGLE_VALUE(0)
622         END_RETURN_VALUE_CONDITION
623       END_CASE
624       CASE
625         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
626           RANGE(0, 127)
627         END_ARGUMENT_CONDITION
628         RETURN_VALUE_CONDITION(WithinRange)
629           SINGLE_VALUE(0)
630         END_RETURN_VALUE_CONDITION
631       END_CASE
632     END_SUMMARY
633     SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
634             INVALIDATION_APPROACH(EvalCallAsPure))
635       CASE
636         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
637           SINGLE_VALUE('\t')
638           SINGLE_VALUE(' ')
639         END_ARGUMENT_CONDITION
640         RETURN_VALUE_CONDITION(OutOfRange)
641           SINGLE_VALUE(0)
642         END_RETURN_VALUE_CONDITION
643       END_CASE
644       CASE
645         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
646           SINGLE_VALUE('\t')
647           SINGLE_VALUE(' ')
648         END_ARGUMENT_CONDITION
649         RETURN_VALUE_CONDITION(WithinRange)
650           SINGLE_VALUE(0)
651         END_RETURN_VALUE_CONDITION
652       END_CASE
653     END_SUMMARY
654     SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
655             INVALIDATION_APPROACH(EvalCallAsPure))
656       CASE // 0..31 or 127
657         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
658           RANGE(0, 32)
659           SINGLE_VALUE(127)
660         END_ARGUMENT_CONDITION
661         RETURN_VALUE_CONDITION(OutOfRange)
662           SINGLE_VALUE(0)
663         END_RETURN_VALUE_CONDITION
664       END_CASE
665       CASE
666         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
667           RANGE(0, 32)
668           SINGLE_VALUE(127)
669         END_ARGUMENT_CONDITION
670         RETURN_VALUE_CONDITION(WithinRange)
671           SINGLE_VALUE(0)
672         END_RETURN_VALUE_CONDITION
673       END_CASE
674     END_SUMMARY
675     SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
676             INVALIDATION_APPROACH(EvalCallAsPure))
677       CASE // Is a digit.
678         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
679           RANGE('0', '9')
680         END_ARGUMENT_CONDITION
681         RETURN_VALUE_CONDITION(OutOfRange)
682           SINGLE_VALUE(0)
683         END_RETURN_VALUE_CONDITION
684       END_CASE
685       CASE
686         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
687           RANGE('0', '9')
688         END_ARGUMENT_CONDITION
689         RETURN_VALUE_CONDITION(WithinRange)
690           SINGLE_VALUE(0)
691         END_RETURN_VALUE_CONDITION
692       END_CASE
693     END_SUMMARY
694     SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
695             INVALIDATION_APPROACH(EvalCallAsPure))
696       CASE
697         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
698           RANGE(33, 126)
699         END_ARGUMENT_CONDITION
700         RETURN_VALUE_CONDITION(OutOfRange)
701           SINGLE_VALUE(0)
702         END_RETURN_VALUE_CONDITION
703       END_CASE
704       CASE
705         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
706           RANGE(33, 126)
707         END_ARGUMENT_CONDITION
708         RETURN_VALUE_CONDITION(WithinRange)
709           SINGLE_VALUE(0)
710         END_RETURN_VALUE_CONDITION
711       END_CASE
712     END_SUMMARY
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)
717           RANGE('a', 'z')
718         END_ARGUMENT_CONDITION
719         RETURN_VALUE_CONDITION(OutOfRange)
720           SINGLE_VALUE(0)
721         END_RETURN_VALUE_CONDITION
722       END_CASE
723       CASE // Is ascii but not lowercase.
724         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
725           RANGE(0, 127)
726         END_ARGUMENT_CONDITION
727         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
728           RANGE('a', 'z')
729         END_ARGUMENT_CONDITION
730         RETURN_VALUE_CONDITION(WithinRange)
731           SINGLE_VALUE(0)
732         END_RETURN_VALUE_CONDITION
733       END_CASE
734       CASE // The locale-specific range.
735         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
736           RANGE(128, 255)
737         END_ARGUMENT_CONDITION
738       END_CASE
739       CASE // Is not an unsigned char.
740         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
741           RANGE(0, 255)
742         END_ARGUMENT_CONDITION
743         RETURN_VALUE_CONDITION(WithinRange)
744           SINGLE_VALUE(0)
745         END_RETURN_VALUE_CONDITION
746       END_CASE
747     END_SUMMARY
748     SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
749             INVALIDATION_APPROACH(EvalCallAsPure))
750       CASE
751         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
752           RANGE(32, 126)
753         END_ARGUMENT_CONDITION
754         RETURN_VALUE_CONDITION(OutOfRange)
755           SINGLE_VALUE(0)
756         END_RETURN_VALUE_CONDITION
757       END_CASE
758       CASE
759         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
760           RANGE(32, 126)
761         END_ARGUMENT_CONDITION
762         RETURN_VALUE_CONDITION(WithinRange)
763           SINGLE_VALUE(0)
764         END_RETURN_VALUE_CONDITION
765       END_CASE
766     END_SUMMARY
767     SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
768             INVALIDATION_APPROACH(EvalCallAsPure))
769       CASE
770         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
771           RANGE('!', '/')
772           RANGE(':', '@')
773           RANGE('[', '`')
774           RANGE('{', '~')
775         END_ARGUMENT_CONDITION
776         RETURN_VALUE_CONDITION(OutOfRange)
777           SINGLE_VALUE(0)
778         END_RETURN_VALUE_CONDITION
779       END_CASE
780       CASE
781         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
782           RANGE('!', '/')
783           RANGE(':', '@')
784           RANGE('[', '`')
785           RANGE('{', '~')
786         END_ARGUMENT_CONDITION
787         RETURN_VALUE_CONDITION(WithinRange)
788           SINGLE_VALUE(0)
789         END_RETURN_VALUE_CONDITION
790       END_CASE
791     END_SUMMARY
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)
796           RANGE(9, 13)
797           SINGLE_VALUE(' ')
798         END_ARGUMENT_CONDITION
799         RETURN_VALUE_CONDITION(OutOfRange)
800           SINGLE_VALUE(0)
801         END_RETURN_VALUE_CONDITION
802       END_CASE
803       CASE // The locale-specific range.
804         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
805           RANGE(128, 255)
806         END_ARGUMENT_CONDITION
807       END_CASE
808       CASE
809         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
810           RANGE(9, 13)
811           SINGLE_VALUE(' ')
812           RANGE(128, 255)
813         END_ARGUMENT_CONDITION
814         RETURN_VALUE_CONDITION(WithinRange)
815           SINGLE_VALUE(0)
816         END_RETURN_VALUE_CONDITION
817       END_CASE
818     END_SUMMARY
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)
823           RANGE('A', 'Z')
824         END_ARGUMENT_CONDITION
825         RETURN_VALUE_CONDITION(OutOfRange)
826           SINGLE_VALUE(0)
827         END_RETURN_VALUE_CONDITION
828       END_CASE
829       CASE // The locale-specific range.
830         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
831           RANGE(128, 255)
832         END_ARGUMENT_CONDITION
833       END_CASE
834       CASE // Other.
835         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
836           RANGE('A', 'Z') RANGE(128, 255)
837         END_ARGUMENT_CONDITION
838         RETURN_VALUE_CONDITION(WithinRange)
839           SINGLE_VALUE(0)
840         END_RETURN_VALUE_CONDITION
841       END_CASE
842     END_SUMMARY
843     SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
844             INVALIDATION_APPROACH(EvalCallAsPure))
845       CASE
846         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
847           RANGE('0', '9')
848           RANGE('A', 'F')
849           RANGE('a', 'f')
850         END_ARGUMENT_CONDITION
851         RETURN_VALUE_CONDITION(OutOfRange)
852           SINGLE_VALUE(0)
853         END_RETURN_VALUE_CONDITION
854       END_CASE
855       CASE
856         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
857           RANGE('0', '9')
858           RANGE('A', 'F')
859           RANGE('a', 'f')
860         END_ARGUMENT_CONDITION
861         RETURN_VALUE_CONDITION(WithinRange)
862           SINGLE_VALUE(0)
863         END_RETURN_VALUE_CONDITION
864       END_CASE
865     END_SUMMARY
866
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)
872           RANGE(-1, 255)
873         END_RETURN_VALUE_CONDITION
874       END_CASE
875     END_SUMMARY
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)
880           RANGE(-1, 255)
881         END_RETURN_VALUE_CONDITION
882       END_CASE
883     END_SUMMARY
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)
888           RANGE(-1, 255)
889         END_RETURN_VALUE_CONDITION
890       END_CASE
891     END_SUMMARY
892
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))
899         CASE
900           RETURN_VALUE_CONDITION(ComparesToArgument)
901             IS_LESS_THAN(ARG_NO(2))
902           END_RETURN_VALUE_CONDITION
903           RETURN_VALUE_CONDITION(WithinRange)
904             RANGE(-1, IntMax)
905           END_RETURN_VALUE_CONDITION
906         END_CASE
907       END_VARIANT
908       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
909               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
910         CASE
911           RETURN_VALUE_CONDITION(ComparesToArgument)
912             IS_LESS_THAN(ARG_NO(2))
913           END_RETURN_VALUE_CONDITION
914           RETURN_VALUE_CONDITION(WithinRange)
915             RANGE(-1, LongMax)
916           END_RETURN_VALUE_CONDITION
917         END_CASE
918       END_VARIANT
919       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
920               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
921         CASE
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
928         END_CASE
929       END_VARIANT
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))
936         CASE
937           RETURN_VALUE_CONDITION(ComparesToArgument)
938             IS_LESS_THAN(ARG_NO(2))
939           END_RETURN_VALUE_CONDITION
940           RETURN_VALUE_CONDITION(WithinRange)
941             RANGE(-1, IntMax)
942           END_RETURN_VALUE_CONDITION
943         END_CASE
944       END_VARIANT
945       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
946               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
947         CASE
948           RETURN_VALUE_CONDITION(ComparesToArgument)
949             IS_LESS_THAN(ARG_NO(2))
950           END_RETURN_VALUE_CONDITION
951           RETURN_VALUE_CONDITION(WithinRange)
952             RANGE(-1, LongMax)
953           END_RETURN_VALUE_CONDITION
954         END_CASE
955       END_VARIANT
956       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
957               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
958         CASE
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
965         END_CASE
966       END_VARIANT
967     END_SUMMARY_WITH_VARIANTS
968     SUMMARY(fread,
969             ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
970             RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
971       CASE
972         RETURN_VALUE_CONDITION(ComparesToArgument)
973           IS_LESS_THAN(ARG_NO(2))
974         END_RETURN_VALUE_CONDITION
975       END_CASE
976     END_SUMMARY
977     SUMMARY(fwrite,
978             ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
979             RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
980       CASE
981         RETURN_VALUE_CONDITION(ComparesToArgument)
982           IS_LESS_THAN(ARG_NO(2))
983         END_RETURN_VALUE_CONDITION
984       END_CASE
985     END_SUMMARY
986
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))
991         CASE
992           RETURN_VALUE_CONDITION(WithinRange)
993             SINGLE_VALUE(-1)
994             RANGE(1, IntMax)
995           END_RETURN_VALUE_CONDITION
996         END_CASE
997       END_VARIANT
998       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
999               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1000         CASE
1001           RETURN_VALUE_CONDITION(WithinRange)
1002             SINGLE_VALUE(-1)
1003             RANGE(1, LongMax)
1004           END_RETURN_VALUE_CONDITION
1005         END_CASE
1006       END_VARIANT
1007       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
1008               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1009         CASE
1010           RETURN_VALUE_CONDITION(WithinRange)
1011             SINGLE_VALUE(-1)
1012             RANGE(1, LongLongMax)
1013           END_RETURN_VALUE_CONDITION
1014         END_CASE
1015       END_VARIANT
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))
1020         CASE
1021           RETURN_VALUE_CONDITION(WithinRange)
1022             SINGLE_VALUE(-1)
1023             RANGE(1, IntMax)
1024           END_RETURN_VALUE_CONDITION
1025         END_CASE
1026       END_VARIANT
1027       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1028             RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1029         CASE
1030           RETURN_VALUE_CONDITION(WithinRange)
1031             SINGLE_VALUE(-1)
1032             RANGE(1, LongMax)
1033           END_RETURN_VALUE_CONDITION
1034         END_CASE
1035       END_VARIANT
1036       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1037             RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1038         CASE
1039           RETURN_VALUE_CONDITION(WithinRange)
1040             SINGLE_VALUE(-1)
1041             RANGE(1, LongLongMax)
1042           END_RETURN_VALUE_CONDITION
1043         END_CASE
1044       END_VARIANT
1045     END_SUMMARY_WITH_VARIANTS
1046   };
1047 }
1048
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>();
1055 }