xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1 //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This checker improves modeling of a few simple library functions.
10 // It does not generate warnings.
11 //
12 // This checker provides a specification format - `FunctionSummaryTy' - and
13 // contains descriptions of some library functions in this format. Each
14 // specification contains a list of branches for splitting the program state
15 // upon call, and range constraints on argument and return-value symbols that
16 // are satisfied on each branch. This spec can be expanded to include more
17 // items, like external effects of the function.
18 //
19 // The main difference between this approach and the body farms technique is
20 // in more explicit control over how many branches are produced. For example,
21 // consider standard C function `ispunct(int x)', which returns a non-zero value
22 // iff `x' is a punctuation character, that is, when `x' is in range
23 //   ['!', '/']   [':', '@']  U  ['[', '\`']  U  ['{', '~'].
24 // `FunctionSummaryTy' provides only two branches for this function. However,
25 // any attempt to describe this range with if-statements in the body farm
26 // would result in many more branches. Because each branch needs to be analyzed
27 // independently, this significantly reduces performance. Additionally,
28 // once we consider a branch on which `x' is in range, say, ['!', '/'],
29 // we assume that such branch is an important separate path through the program,
30 // which may lead to false positives because considering this particular path
31 // was not consciously intended, and therefore it might have been unreachable.
32 //
33 // This checker uses eval::Call for modeling "pure" functions, for which
34 // their `FunctionSummaryTy' is a precise model. This avoids unnecessary
35 // invalidation passes. Conflicts with other checkers are unlikely because
36 // if the function has no other effects, other checkers would probably never
37 // want to improve upon the modeling done by this checker.
38 //
39 // Non-"pure" functions, for which only partial improvement over the default
40 // behavior is expected, are modeled via check::PostCall, non-intrusively.
41 //
42 // The following standard C functions are currently supported:
43 //
44 //   fgetc      getline   isdigit   isupper
45 //   fread      isalnum   isgraph   isxdigit
46 //   fwrite     isalpha   islower   read
47 //   getc       isascii   isprint   write
48 //   getchar    isblank   ispunct
49 //   getdelim   iscntrl   isspace
50 //
51 //===----------------------------------------------------------------------===//
52 
53 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
54 #include "clang/StaticAnalyzer/Core/Checker.h"
55 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
56 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
57 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
58 
59 using namespace clang;
60 using namespace clang::ento;
61 
62 namespace {
63 class StdLibraryFunctionsChecker : public Checker<check::PostCall, eval::Call> {
64   /// Below is a series of typedefs necessary to define function specs.
65   /// We avoid nesting types here because each additional qualifier
66   /// would need to be repeated in every function spec.
67   struct FunctionSummaryTy;
68 
69   /// Specify how much the analyzer engine should entrust modeling this function
70   /// to us. If he doesn't, he performs additional invalidations.
71   enum InvalidationKindTy { NoEvalCall, EvalCallAsPure };
72 
73   /// A pair of ValueRangeKindTy and IntRangeVectorTy would describe a range
74   /// imposed on a particular argument or return value symbol.
75   ///
76   /// Given a range, should the argument stay inside or outside this range?
77   /// The special `ComparesToArgument' value indicates that we should
78   /// impose a constraint that involves other argument or return value symbols.
79   enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument };
80 
81   // The universal integral type to use in value range descriptions.
82   // Unsigned to make sure overflows are well-defined.
83   typedef uint64_t RangeIntTy;
84 
85   /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
86   /// a non-negative integer, which less than 5 and not equal to 2. For
87   /// `ComparesToArgument', holds information about how exactly to compare to
88   /// the argument.
89   typedef std::vector<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy;
90 
91   /// A reference to an argument or return value by its number.
92   /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
93   /// obviously uint32_t should be enough for all practical purposes.
94   typedef uint32_t ArgNoTy;
95   static const ArgNoTy Ret = std::numeric_limits<ArgNoTy>::max();
96 
97   /// Incapsulates a single range on a single symbol within a branch.
98   class ValueRange {
99     ArgNoTy ArgNo; // Argument to which we apply the range.
100     ValueRangeKindTy Kind; // Kind of range definition.
101     IntRangeVectorTy Args; // Polymorphic arguments.
102 
103   public:
104     ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
105                const IntRangeVectorTy &Args)
106         : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
107 
108     ArgNoTy getArgNo() const { return ArgNo; }
109     ValueRangeKindTy getKind() const { return Kind; }
110 
111     BinaryOperator::Opcode getOpcode() const {
112       assert(Kind == ComparesToArgument);
113       assert(Args.size() == 1);
114       BinaryOperator::Opcode Op =
115           static_cast<BinaryOperator::Opcode>(Args[0].first);
116       assert(BinaryOperator::isComparisonOp(Op) &&
117              "Only comparison ops are supported for ComparesToArgument");
118       return Op;
119     }
120 
121     ArgNoTy getOtherArgNo() const {
122       assert(Kind == ComparesToArgument);
123       assert(Args.size() == 1);
124       return static_cast<ArgNoTy>(Args[0].second);
125     }
126 
127     const IntRangeVectorTy &getRanges() const {
128       assert(Kind != ComparesToArgument);
129       return Args;
130     }
131 
132     // We avoid creating a virtual apply() method because
133     // it makes initializer lists harder to write.
134   private:
135     ProgramStateRef
136     applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call,
137                       const FunctionSummaryTy &Summary) const;
138     ProgramStateRef
139     applyAsWithinRange(ProgramStateRef State, const CallEvent &Call,
140                        const FunctionSummaryTy &Summary) const;
141     ProgramStateRef
142     applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call,
143                               const FunctionSummaryTy &Summary) const;
144 
145   public:
146     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
147                           const FunctionSummaryTy &Summary) const {
148       switch (Kind) {
149       case OutOfRange:
150         return applyAsOutOfRange(State, Call, Summary);
151       case WithinRange:
152         return applyAsWithinRange(State, Call, Summary);
153       case ComparesToArgument:
154         return applyAsComparesToArgument(State, Call, Summary);
155       }
156       llvm_unreachable("Unknown ValueRange kind!");
157     }
158   };
159 
160   /// The complete list of ranges that defines a single branch.
161   typedef std::vector<ValueRange> ValueRangeSet;
162 
163   /// Includes information about function prototype (which is necessary to
164   /// ensure we're modeling the right function and casting values properly),
165   /// approach to invalidation, and a list of branches - essentially, a list
166   /// of list of ranges - essentially, a list of lists of lists of segments.
167   struct FunctionSummaryTy {
168     const std::vector<QualType> ArgTypes;
169     const QualType RetType;
170     const InvalidationKindTy InvalidationKind;
171     const std::vector<ValueRangeSet> Ranges;
172 
173   private:
174     static void assertTypeSuitableForSummary(QualType T) {
175       assert(!T->isVoidType() &&
176              "We should have had no significant void types in the spec");
177       assert(T.isCanonical() &&
178              "We should only have canonical types in the spec");
179       // FIXME: lift this assert (but not the ones above!)
180       assert(T->isIntegralOrEnumerationType() &&
181              "We only support integral ranges in the spec");
182     }
183 
184   public:
185     QualType getArgType(ArgNoTy ArgNo) const {
186       QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo];
187       assertTypeSuitableForSummary(T);
188       return T;
189     }
190 
191     /// Try our best to figure out if the call expression is the call of
192     /// *the* library function to which this specification applies.
193     bool matchesCall(const CallExpr *CE) const;
194   };
195 
196   // The same function (as in, function identifier) may have different
197   // summaries assigned to it, with different argument and return value types.
198   // We call these "variants" of the function. This can be useful for handling
199   // C++ function overloads, and also it can be used when the same function
200   // may have different definitions on different platforms.
201   typedef std::vector<FunctionSummaryTy> FunctionVariantsTy;
202 
203   // The map of all functions supported by the checker. It is initialized
204   // lazily, and it doesn't change after initialization.
205   typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy;
206   mutable FunctionSummaryMapTy FunctionSummaryMap;
207 
208   // Auxiliary functions to support ArgNoTy within all structures
209   // in a unified manner.
210   static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) {
211     return Summary.getArgType(ArgNo);
212   }
213   static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) {
214     return ArgNo == Ret ? Call.getResultType().getCanonicalType()
215                         : Call.getArgExpr(ArgNo)->getType().getCanonicalType();
216   }
217   static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) {
218     return ArgNo == Ret ? CE->getType().getCanonicalType()
219                         : CE->getArg(ArgNo)->getType().getCanonicalType();
220   }
221   static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) {
222     return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo);
223   }
224 
225 public:
226   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
227   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
228 
229 private:
230   Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD,
231                                           const CallExpr *CE,
232                                           CheckerContext &C) const;
233 
234   void initFunctionSummaries(BasicValueFactory &BVF) const;
235 };
236 } // end of anonymous namespace
237 
238 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
239     ProgramStateRef State, const CallEvent &Call,
240     const FunctionSummaryTy &Summary) const {
241 
242   ProgramStateManager &Mgr = State->getStateManager();
243   SValBuilder &SVB = Mgr.getSValBuilder();
244   BasicValueFactory &BVF = SVB.getBasicValueFactory();
245   ConstraintManager &CM = Mgr.getConstraintManager();
246   QualType T = getArgType(Summary, getArgNo());
247   SVal V = getArgSVal(Call, getArgNo());
248 
249   if (auto N = V.getAs<NonLoc>()) {
250     const IntRangeVectorTy &R = getRanges();
251     size_t E = R.size();
252     for (size_t I = 0; I != E; ++I) {
253       const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
254       const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
255       assert(Min <= Max);
256       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
257       if (!State)
258         break;
259     }
260   }
261 
262   return State;
263 }
264 
265 ProgramStateRef
266 StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
267     ProgramStateRef State, const CallEvent &Call,
268     const FunctionSummaryTy &Summary) const {
269 
270   ProgramStateManager &Mgr = State->getStateManager();
271   SValBuilder &SVB = Mgr.getSValBuilder();
272   BasicValueFactory &BVF = SVB.getBasicValueFactory();
273   ConstraintManager &CM = Mgr.getConstraintManager();
274   QualType T = getArgType(Summary, getArgNo());
275   SVal V = getArgSVal(Call, getArgNo());
276 
277   // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
278   // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
279   // and then cut away all holes in R one by one.
280   if (auto N = V.getAs<NonLoc>()) {
281     const IntRangeVectorTy &R = getRanges();
282     size_t E = R.size();
283 
284     const llvm::APSInt &MinusInf = BVF.getMinValue(T);
285     const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
286 
287     const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
288     if (Left != PlusInf) {
289       assert(MinusInf <= Left);
290       State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
291       if (!State)
292         return nullptr;
293     }
294 
295     const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
296     if (Right != MinusInf) {
297       assert(Right <= PlusInf);
298       State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
299       if (!State)
300         return nullptr;
301     }
302 
303     for (size_t I = 1; I != E; ++I) {
304       const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
305       const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
306       assert(Min <= Max);
307       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
308       if (!State)
309         return nullptr;
310     }
311   }
312 
313   return State;
314 }
315 
316 ProgramStateRef
317 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
318     ProgramStateRef State, const CallEvent &Call,
319     const FunctionSummaryTy &Summary) const {
320 
321   ProgramStateManager &Mgr = State->getStateManager();
322   SValBuilder &SVB = Mgr.getSValBuilder();
323   QualType CondT = SVB.getConditionType();
324   QualType T = getArgType(Summary, getArgNo());
325   SVal V = getArgSVal(Call, getArgNo());
326 
327   BinaryOperator::Opcode Op = getOpcode();
328   ArgNoTy OtherArg = getOtherArgNo();
329   SVal OtherV = getArgSVal(Call, OtherArg);
330   QualType OtherT = getArgType(Call, OtherArg);
331   // Note: we avoid integral promotion for comparison.
332   OtherV = SVB.evalCast(OtherV, T, OtherT);
333   if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
334                        .getAs<DefinedOrUnknownSVal>())
335     State = State->assume(*CompV, true);
336   return State;
337 }
338 
339 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
340                                                CheckerContext &C) const {
341   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
342   if (!FD)
343     return;
344 
345   const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
346   if (!CE)
347     return;
348 
349   Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
350   if (!FoundSummary)
351     return;
352 
353   // Now apply ranges.
354   const FunctionSummaryTy &Summary = *FoundSummary;
355   ProgramStateRef State = C.getState();
356 
357   for (const auto &VRS: Summary.Ranges) {
358     ProgramStateRef NewState = State;
359     for (const auto &VR: VRS) {
360       NewState = VR.apply(NewState, Call, Summary);
361       if (!NewState)
362         break;
363     }
364 
365     if (NewState && NewState != State)
366       C.addTransition(NewState);
367   }
368 }
369 
370 bool StdLibraryFunctionsChecker::evalCall(const CallExpr *CE,
371                                           CheckerContext &C) const {
372   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl());
373   if (!FD)
374     return false;
375 
376   Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
377   if (!FoundSummary)
378     return false;
379 
380   const FunctionSummaryTy &Summary = *FoundSummary;
381   switch (Summary.InvalidationKind) {
382   case EvalCallAsPure: {
383     ProgramStateRef State = C.getState();
384     const LocationContext *LC = C.getLocationContext();
385     SVal V = C.getSValBuilder().conjureSymbolVal(
386         CE, LC, CE->getType().getCanonicalType(), C.blockCount());
387     State = State->BindExpr(CE, LC, V);
388     C.addTransition(State);
389     return true;
390   }
391   case NoEvalCall:
392     // Summary tells us to avoid performing eval::Call. The function is possibly
393     // evaluated by another checker, or evaluated conservatively.
394     return false;
395   }
396   llvm_unreachable("Unknown invalidation kind!");
397 }
398 
399 bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
400     const CallExpr *CE) const {
401   // Check number of arguments:
402   if (CE->getNumArgs() != ArgTypes.size())
403     return false;
404 
405   // Check return type if relevant:
406   if (!RetType.isNull() && RetType != CE->getType().getCanonicalType())
407     return false;
408 
409   // Check argument types when relevant:
410   for (size_t I = 0, E = ArgTypes.size(); I != E; ++I) {
411     QualType FormalT = ArgTypes[I];
412     // Null type marks irrelevant arguments.
413     if (FormalT.isNull())
414       continue;
415 
416     assertTypeSuitableForSummary(FormalT);
417 
418     QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I);
419     assert(ActualT.isCanonical());
420     if (ActualT != FormalT)
421       return false;
422   }
423 
424   return true;
425 }
426 
427 Optional<StdLibraryFunctionsChecker::FunctionSummaryTy>
428 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
429                                                 const CallExpr *CE,
430                                                 CheckerContext &C) const {
431   // Note: we cannot always obtain FD from CE
432   // (eg. virtual call, or call by pointer).
433   assert(CE);
434 
435   if (!FD)
436     return None;
437 
438   SValBuilder &SVB = C.getSValBuilder();
439   BasicValueFactory &BVF = SVB.getBasicValueFactory();
440   initFunctionSummaries(BVF);
441 
442   IdentifierInfo *II = FD->getIdentifier();
443   if (!II)
444     return None;
445   StringRef Name = II->getName();
446   if (Name.empty() || !C.isCLibraryFunction(FD, Name))
447     return None;
448 
449   auto FSMI = FunctionSummaryMap.find(Name);
450   if (FSMI == FunctionSummaryMap.end())
451     return None;
452 
453   // Verify that function signature matches the spec in advance.
454   // Otherwise we might be modeling the wrong function.
455   // Strict checking is important because we will be conducting
456   // very integral-type-sensitive operations on arguments and
457   // return values.
458   const FunctionVariantsTy &SpecVariants = FSMI->second;
459   for (const FunctionSummaryTy &Spec : SpecVariants)
460     if (Spec.matchesCall(CE))
461       return Spec;
462 
463   return None;
464 }
465 
466 void StdLibraryFunctionsChecker::initFunctionSummaries(
467     BasicValueFactory &BVF) const {
468   if (!FunctionSummaryMap.empty())
469     return;
470 
471   ASTContext &ACtx = BVF.getContext();
472 
473   // These types are useful for writing specifications quickly,
474   // New specifications should probably introduce more types.
475   // Some types are hard to obtain from the AST, eg. "ssize_t".
476   // In such cases it should be possible to provide multiple variants
477   // of function summary for common cases (eg. ssize_t could be int or long
478   // or long long, so three summary variants would be enough).
479   // Of course, function variants are also useful for C++ overloads.
480   QualType Irrelevant; // A placeholder, whenever we do not care about the type.
481   QualType IntTy = ACtx.IntTy;
482   QualType LongTy = ACtx.LongTy;
483   QualType LongLongTy = ACtx.LongLongTy;
484   QualType SizeTy = ACtx.getSizeType();
485 
486   RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
487   RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
488   RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
489 
490   // We are finally ready to define specifications for all supported functions.
491   //
492   // The signature needs to have the correct number of arguments.
493   // However, we insert `Irrelevant' when the type is insignificant.
494   //
495   // Argument ranges should always cover all variants. If return value
496   // is completely unknown, omit it from the respective range set.
497   //
498   // All types in the spec need to be canonical.
499   //
500   // Every item in the list of range sets represents a particular
501   // execution path the analyzer would need to explore once
502   // the call is modeled - a new program state is constructed
503   // for every range set, and each range line in the range set
504   // corresponds to a specific constraint within this state.
505   //
506   // Upon comparing to another argument, the other argument is casted
507   // to the current argument's type. This avoids proper promotion but
508   // seems useful. For example, read() receives size_t argument,
509   // and its return value, which is of type ssize_t, cannot be greater
510   // than this argument. If we made a promotion, and the size argument
511   // is equal to, say, 10, then we'd impose a range of [0, 10] on the
512   // return value, however the correct range is [-1, 10].
513   //
514   // Please update the list of functions in the header after editing!
515   //
516   // The format is as follows:
517   //
518   //{ "function name",
519   //  { spec:
520   //    { argument types list, ... },
521   //    return type, purity, { range set list:
522   //      { range list:
523   //        { argument index, within or out of, {{from, to}, ...} },
524   //        { argument index, compares to argument, {{how, which}} },
525   //        ...
526   //      }
527   //    }
528   //  }
529   //}
530 
531 #define SUMMARY_WITH_VARIANTS(identifier) {#identifier, {
532 #define END_SUMMARY_WITH_VARIANTS }},
533 #define VARIANT(argument_types, return_type, invalidation_approach)            \
534   { argument_types, return_type, invalidation_approach, {
535 #define END_VARIANT } },
536 #define SUMMARY(identifier, argument_types, return_type,                       \
537                 invalidation_approach)                                         \
538   { #identifier, { { argument_types, return_type, invalidation_approach, {
539 #define END_SUMMARY } } } },
540 #define ARGUMENT_TYPES(...) { __VA_ARGS__ }
541 #define RETURN_TYPE(x) x
542 #define INVALIDATION_APPROACH(x) x
543 #define CASE {
544 #define END_CASE },
545 #define ARGUMENT_CONDITION(argument_number, condition_kind)                    \
546   { argument_number, condition_kind, {
547 #define END_ARGUMENT_CONDITION }},
548 #define RETURN_VALUE_CONDITION(condition_kind)                                 \
549   { Ret, condition_kind, {
550 #define END_RETURN_VALUE_CONDITION }},
551 #define ARG_NO(x) x##U
552 #define RANGE(x, y) { x, y },
553 #define SINGLE_VALUE(x) RANGE(x, x)
554 #define IS_LESS_THAN(arg) { BO_LE, arg }
555 
556   FunctionSummaryMap = {
557     // The isascii() family of functions.
558     SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
559             INVALIDATION_APPROACH(EvalCallAsPure))
560       CASE // Boils down to isupper() or islower() or isdigit()
561         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
562           RANGE('0', '9')
563           RANGE('A', 'Z')
564           RANGE('a', 'z')
565         END_ARGUMENT_CONDITION
566         RETURN_VALUE_CONDITION(OutOfRange)
567           SINGLE_VALUE(0)
568         END_RETURN_VALUE_CONDITION
569       END_CASE
570       CASE // The locale-specific range.
571         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
572           RANGE(128, 255)
573         END_ARGUMENT_CONDITION
574         // No post-condition. We are completely unaware of
575         // locale-specific return values.
576       END_CASE
577       CASE
578         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
579           RANGE('0', '9')
580           RANGE('A', 'Z')
581           RANGE('a', 'z')
582           RANGE(128, 255)
583         END_ARGUMENT_CONDITION
584         RETURN_VALUE_CONDITION(WithinRange)
585           SINGLE_VALUE(0)
586         END_RETURN_VALUE_CONDITION
587       END_CASE
588     END_SUMMARY
589     SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
590             INVALIDATION_APPROACH(EvalCallAsPure))
591       CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
592         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
593           RANGE('A', 'Z')
594           RANGE('a', 'z')
595         END_ARGUMENT_CONDITION
596         RETURN_VALUE_CONDITION(OutOfRange)
597           SINGLE_VALUE(0)
598         END_RETURN_VALUE_CONDITION
599       END_CASE
600       CASE // The locale-specific range.
601         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
602           RANGE(128, 255)
603         END_ARGUMENT_CONDITION
604       END_CASE
605       CASE // Other.
606         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
607           RANGE('A', 'Z')
608           RANGE('a', 'z')
609           RANGE(128, 255)
610         END_ARGUMENT_CONDITION
611         RETURN_VALUE_CONDITION(WithinRange)
612           SINGLE_VALUE(0)
613         END_RETURN_VALUE_CONDITION
614       END_CASE
615     END_SUMMARY
616     SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
617             INVALIDATION_APPROACH(EvalCallAsPure))
618       CASE // Is ASCII.
619         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
620           RANGE(0, 127)
621         END_ARGUMENT_CONDITION
622         RETURN_VALUE_CONDITION(OutOfRange)
623           SINGLE_VALUE(0)
624         END_RETURN_VALUE_CONDITION
625       END_CASE
626       CASE
627         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
628           RANGE(0, 127)
629         END_ARGUMENT_CONDITION
630         RETURN_VALUE_CONDITION(WithinRange)
631           SINGLE_VALUE(0)
632         END_RETURN_VALUE_CONDITION
633       END_CASE
634     END_SUMMARY
635     SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
636             INVALIDATION_APPROACH(EvalCallAsPure))
637       CASE
638         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
639           SINGLE_VALUE('\t')
640           SINGLE_VALUE(' ')
641         END_ARGUMENT_CONDITION
642         RETURN_VALUE_CONDITION(OutOfRange)
643           SINGLE_VALUE(0)
644         END_RETURN_VALUE_CONDITION
645       END_CASE
646       CASE
647         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
648           SINGLE_VALUE('\t')
649           SINGLE_VALUE(' ')
650         END_ARGUMENT_CONDITION
651         RETURN_VALUE_CONDITION(WithinRange)
652           SINGLE_VALUE(0)
653         END_RETURN_VALUE_CONDITION
654       END_CASE
655     END_SUMMARY
656     SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
657             INVALIDATION_APPROACH(EvalCallAsPure))
658       CASE // 0..31 or 127
659         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
660           RANGE(0, 32)
661           SINGLE_VALUE(127)
662         END_ARGUMENT_CONDITION
663         RETURN_VALUE_CONDITION(OutOfRange)
664           SINGLE_VALUE(0)
665         END_RETURN_VALUE_CONDITION
666       END_CASE
667       CASE
668         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
669           RANGE(0, 32)
670           SINGLE_VALUE(127)
671         END_ARGUMENT_CONDITION
672         RETURN_VALUE_CONDITION(WithinRange)
673           SINGLE_VALUE(0)
674         END_RETURN_VALUE_CONDITION
675       END_CASE
676     END_SUMMARY
677     SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
678             INVALIDATION_APPROACH(EvalCallAsPure))
679       CASE // Is a digit.
680         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
681           RANGE('0', '9')
682         END_ARGUMENT_CONDITION
683         RETURN_VALUE_CONDITION(OutOfRange)
684           SINGLE_VALUE(0)
685         END_RETURN_VALUE_CONDITION
686       END_CASE
687       CASE
688         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
689           RANGE('0', '9')
690         END_ARGUMENT_CONDITION
691         RETURN_VALUE_CONDITION(WithinRange)
692           SINGLE_VALUE(0)
693         END_RETURN_VALUE_CONDITION
694       END_CASE
695     END_SUMMARY
696     SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
697             INVALIDATION_APPROACH(EvalCallAsPure))
698       CASE
699         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
700           RANGE(33, 126)
701         END_ARGUMENT_CONDITION
702         RETURN_VALUE_CONDITION(OutOfRange)
703           SINGLE_VALUE(0)
704         END_RETURN_VALUE_CONDITION
705       END_CASE
706       CASE
707         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
708           RANGE(33, 126)
709         END_ARGUMENT_CONDITION
710         RETURN_VALUE_CONDITION(WithinRange)
711           SINGLE_VALUE(0)
712         END_RETURN_VALUE_CONDITION
713       END_CASE
714     END_SUMMARY
715     SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
716             INVALIDATION_APPROACH(EvalCallAsPure))
717       CASE // Is certainly lowercase.
718         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
719           RANGE('a', 'z')
720         END_ARGUMENT_CONDITION
721         RETURN_VALUE_CONDITION(OutOfRange)
722           SINGLE_VALUE(0)
723         END_RETURN_VALUE_CONDITION
724       END_CASE
725       CASE // Is ascii but not lowercase.
726         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
727           RANGE(0, 127)
728         END_ARGUMENT_CONDITION
729         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
730           RANGE('a', 'z')
731         END_ARGUMENT_CONDITION
732         RETURN_VALUE_CONDITION(WithinRange)
733           SINGLE_VALUE(0)
734         END_RETURN_VALUE_CONDITION
735       END_CASE
736       CASE // The locale-specific range.
737         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
738           RANGE(128, 255)
739         END_ARGUMENT_CONDITION
740       END_CASE
741       CASE // Is not an unsigned char.
742         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
743           RANGE(0, 255)
744         END_ARGUMENT_CONDITION
745         RETURN_VALUE_CONDITION(WithinRange)
746           SINGLE_VALUE(0)
747         END_RETURN_VALUE_CONDITION
748       END_CASE
749     END_SUMMARY
750     SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
751             INVALIDATION_APPROACH(EvalCallAsPure))
752       CASE
753         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
754           RANGE(32, 126)
755         END_ARGUMENT_CONDITION
756         RETURN_VALUE_CONDITION(OutOfRange)
757           SINGLE_VALUE(0)
758         END_RETURN_VALUE_CONDITION
759       END_CASE
760       CASE
761         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
762           RANGE(32, 126)
763         END_ARGUMENT_CONDITION
764         RETURN_VALUE_CONDITION(WithinRange)
765           SINGLE_VALUE(0)
766         END_RETURN_VALUE_CONDITION
767       END_CASE
768     END_SUMMARY
769     SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
770             INVALIDATION_APPROACH(EvalCallAsPure))
771       CASE
772         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
773           RANGE('!', '/')
774           RANGE(':', '@')
775           RANGE('[', '`')
776           RANGE('{', '~')
777         END_ARGUMENT_CONDITION
778         RETURN_VALUE_CONDITION(OutOfRange)
779           SINGLE_VALUE(0)
780         END_RETURN_VALUE_CONDITION
781       END_CASE
782       CASE
783         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
784           RANGE('!', '/')
785           RANGE(':', '@')
786           RANGE('[', '`')
787           RANGE('{', '~')
788         END_ARGUMENT_CONDITION
789         RETURN_VALUE_CONDITION(WithinRange)
790           SINGLE_VALUE(0)
791         END_RETURN_VALUE_CONDITION
792       END_CASE
793     END_SUMMARY
794     SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
795             INVALIDATION_APPROACH(EvalCallAsPure))
796       CASE // Space, '\f', '\n', '\r', '\t', '\v'.
797         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
798           RANGE(9, 13)
799           SINGLE_VALUE(' ')
800         END_ARGUMENT_CONDITION
801         RETURN_VALUE_CONDITION(OutOfRange)
802           SINGLE_VALUE(0)
803         END_RETURN_VALUE_CONDITION
804       END_CASE
805       CASE // The locale-specific range.
806         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
807           RANGE(128, 255)
808         END_ARGUMENT_CONDITION
809       END_CASE
810       CASE
811         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
812           RANGE(9, 13)
813           SINGLE_VALUE(' ')
814           RANGE(128, 255)
815         END_ARGUMENT_CONDITION
816         RETURN_VALUE_CONDITION(WithinRange)
817           SINGLE_VALUE(0)
818         END_RETURN_VALUE_CONDITION
819       END_CASE
820     END_SUMMARY
821     SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy),
822             INVALIDATION_APPROACH(EvalCallAsPure))
823       CASE // Is certainly uppercase.
824         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
825           RANGE('A', 'Z')
826         END_ARGUMENT_CONDITION
827         RETURN_VALUE_CONDITION(OutOfRange)
828           SINGLE_VALUE(0)
829         END_RETURN_VALUE_CONDITION
830       END_CASE
831       CASE // The locale-specific range.
832         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
833           RANGE(128, 255)
834         END_ARGUMENT_CONDITION
835       END_CASE
836       CASE // Other.
837         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
838           RANGE('A', 'Z') RANGE(128, 255)
839         END_ARGUMENT_CONDITION
840         RETURN_VALUE_CONDITION(WithinRange)
841           SINGLE_VALUE(0)
842         END_RETURN_VALUE_CONDITION
843       END_CASE
844     END_SUMMARY
845     SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
846             INVALIDATION_APPROACH(EvalCallAsPure))
847       CASE
848         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
849           RANGE('0', '9')
850           RANGE('A', 'F')
851           RANGE('a', 'f')
852         END_ARGUMENT_CONDITION
853         RETURN_VALUE_CONDITION(OutOfRange)
854           SINGLE_VALUE(0)
855         END_RETURN_VALUE_CONDITION
856       END_CASE
857       CASE
858         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
859           RANGE('0', '9')
860           RANGE('A', 'F')
861           RANGE('a', 'f')
862         END_ARGUMENT_CONDITION
863         RETURN_VALUE_CONDITION(WithinRange)
864           SINGLE_VALUE(0)
865         END_RETURN_VALUE_CONDITION
866       END_CASE
867     END_SUMMARY
868 
869     // The getc() family of functions that returns either a char or an EOF.
870     SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
871             INVALIDATION_APPROACH(NoEvalCall))
872       CASE // FIXME: EOF is assumed to be defined as -1.
873         RETURN_VALUE_CONDITION(WithinRange)
874           RANGE(-1, 255)
875         END_RETURN_VALUE_CONDITION
876       END_CASE
877     END_SUMMARY
878     SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
879             INVALIDATION_APPROACH(NoEvalCall))
880       CASE // FIXME: EOF is assumed to be defined as -1.
881         RETURN_VALUE_CONDITION(WithinRange)
882           RANGE(-1, 255)
883         END_RETURN_VALUE_CONDITION
884       END_CASE
885     END_SUMMARY
886     SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy),
887             INVALIDATION_APPROACH(NoEvalCall))
888       CASE // FIXME: EOF is assumed to be defined as -1.
889         RETURN_VALUE_CONDITION(WithinRange)
890           RANGE(-1, 255)
891         END_RETURN_VALUE_CONDITION
892       END_CASE
893     END_SUMMARY
894 
895     // read()-like functions that never return more than buffer size.
896     // We are not sure how ssize_t is defined on every platform, so we provide
897     // three variants that should cover common cases.
898     SUMMARY_WITH_VARIANTS(read)
899       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
900               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
901         CASE
902           RETURN_VALUE_CONDITION(ComparesToArgument)
903             IS_LESS_THAN(ARG_NO(2))
904           END_RETURN_VALUE_CONDITION
905           RETURN_VALUE_CONDITION(WithinRange)
906             RANGE(-1, IntMax)
907           END_RETURN_VALUE_CONDITION
908         END_CASE
909       END_VARIANT
910       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
911               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
912         CASE
913           RETURN_VALUE_CONDITION(ComparesToArgument)
914             IS_LESS_THAN(ARG_NO(2))
915           END_RETURN_VALUE_CONDITION
916           RETURN_VALUE_CONDITION(WithinRange)
917             RANGE(-1, LongMax)
918           END_RETURN_VALUE_CONDITION
919         END_CASE
920       END_VARIANT
921       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
922               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
923         CASE
924           RETURN_VALUE_CONDITION(ComparesToArgument)
925             IS_LESS_THAN(ARG_NO(2))
926           END_RETURN_VALUE_CONDITION
927           RETURN_VALUE_CONDITION(WithinRange)
928             RANGE(-1, LongLongMax)
929           END_RETURN_VALUE_CONDITION
930         END_CASE
931       END_VARIANT
932     END_SUMMARY_WITH_VARIANTS
933     SUMMARY_WITH_VARIANTS(write)
934       // Again, due to elusive nature of ssize_t, we have duplicate
935       // our summaries to cover different variants.
936       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
937               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
938         CASE
939           RETURN_VALUE_CONDITION(ComparesToArgument)
940             IS_LESS_THAN(ARG_NO(2))
941           END_RETURN_VALUE_CONDITION
942           RETURN_VALUE_CONDITION(WithinRange)
943             RANGE(-1, IntMax)
944           END_RETURN_VALUE_CONDITION
945         END_CASE
946       END_VARIANT
947       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
948               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
949         CASE
950           RETURN_VALUE_CONDITION(ComparesToArgument)
951             IS_LESS_THAN(ARG_NO(2))
952           END_RETURN_VALUE_CONDITION
953           RETURN_VALUE_CONDITION(WithinRange)
954             RANGE(-1, LongMax)
955           END_RETURN_VALUE_CONDITION
956         END_CASE
957       END_VARIANT
958       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
959               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
960         CASE
961           RETURN_VALUE_CONDITION(ComparesToArgument)
962             IS_LESS_THAN(ARG_NO(2))
963           END_RETURN_VALUE_CONDITION
964           RETURN_VALUE_CONDITION(WithinRange)
965             RANGE(-1, LongLongMax)
966           END_RETURN_VALUE_CONDITION
967         END_CASE
968       END_VARIANT
969     END_SUMMARY_WITH_VARIANTS
970     SUMMARY(fread,
971             ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
972             RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
973       CASE
974         RETURN_VALUE_CONDITION(ComparesToArgument)
975           IS_LESS_THAN(ARG_NO(2))
976         END_RETURN_VALUE_CONDITION
977       END_CASE
978     END_SUMMARY
979     SUMMARY(fwrite,
980             ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
981             RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
982       CASE
983         RETURN_VALUE_CONDITION(ComparesToArgument)
984           IS_LESS_THAN(ARG_NO(2))
985         END_RETURN_VALUE_CONDITION
986       END_CASE
987     END_SUMMARY
988 
989     // getline()-like functions either fail or read at least the delimiter.
990     SUMMARY_WITH_VARIANTS(getline)
991       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
992               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
993         CASE
994           RETURN_VALUE_CONDITION(WithinRange)
995             SINGLE_VALUE(-1)
996             RANGE(1, IntMax)
997           END_RETURN_VALUE_CONDITION
998         END_CASE
999       END_VARIANT
1000       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
1001               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1002         CASE
1003           RETURN_VALUE_CONDITION(WithinRange)
1004             SINGLE_VALUE(-1)
1005             RANGE(1, LongMax)
1006           END_RETURN_VALUE_CONDITION
1007         END_CASE
1008       END_VARIANT
1009       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
1010               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1011         CASE
1012           RETURN_VALUE_CONDITION(WithinRange)
1013             SINGLE_VALUE(-1)
1014             RANGE(1, LongLongMax)
1015           END_RETURN_VALUE_CONDITION
1016         END_CASE
1017       END_VARIANT
1018     END_SUMMARY_WITH_VARIANTS
1019     SUMMARY_WITH_VARIANTS(getdelim)
1020       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1021             RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
1022         CASE
1023           RETURN_VALUE_CONDITION(WithinRange)
1024             SINGLE_VALUE(-1)
1025             RANGE(1, IntMax)
1026           END_RETURN_VALUE_CONDITION
1027         END_CASE
1028       END_VARIANT
1029       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1030             RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1031         CASE
1032           RETURN_VALUE_CONDITION(WithinRange)
1033             SINGLE_VALUE(-1)
1034             RANGE(1, LongMax)
1035           END_RETURN_VALUE_CONDITION
1036         END_CASE
1037       END_VARIANT
1038       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1039             RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1040         CASE
1041           RETURN_VALUE_CONDITION(WithinRange)
1042             SINGLE_VALUE(-1)
1043             RANGE(1, LongLongMax)
1044           END_RETURN_VALUE_CONDITION
1045         END_CASE
1046       END_VARIANT
1047     END_SUMMARY_WITH_VARIANTS
1048   };
1049 }
1050 
1051 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
1052   // If this checker grows large enough to support C++, Objective-C, or other
1053   // standard libraries, we could use multiple register...Checker() functions,
1054   // which would register various checkers with the help of the same Checker
1055   // class, turning on different function summaries.
1056   mgr.registerChecker<StdLibraryFunctionsChecker>();
1057 }
1058