]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
MFV r351500: Fix CLEAR_HASH macro to be usable as a single statement.
[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 "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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   IdentifierInfo *II = FD->getIdentifier();
444   if (!II)
445     return None;
446   StringRef Name = II->getName();
447   if (Name.empty() || !C.isCLibraryFunction(FD, Name))
448     return None;
449
450   auto FSMI = FunctionSummaryMap.find(Name);
451   if (FSMI == FunctionSummaryMap.end())
452     return None;
453
454   // Verify that function signature matches the spec in advance.
455   // Otherwise we might be modeling the wrong function.
456   // Strict checking is important because we will be conducting
457   // very integral-type-sensitive operations on arguments and
458   // return values.
459   const FunctionVariantsTy &SpecVariants = FSMI->second;
460   for (const FunctionSummaryTy &Spec : SpecVariants)
461     if (Spec.matchesCall(CE))
462       return Spec;
463
464   return None;
465 }
466
467 void StdLibraryFunctionsChecker::initFunctionSummaries(
468     BasicValueFactory &BVF) const {
469   if (!FunctionSummaryMap.empty())
470     return;
471
472   ASTContext &ACtx = BVF.getContext();
473
474   // These types are useful for writing specifications quickly,
475   // New specifications should probably introduce more types.
476   // Some types are hard to obtain from the AST, eg. "ssize_t".
477   // In such cases it should be possible to provide multiple variants
478   // of function summary for common cases (eg. ssize_t could be int or long
479   // or long long, so three summary variants would be enough).
480   // Of course, function variants are also useful for C++ overloads.
481   QualType Irrelevant; // A placeholder, whenever we do not care about the type.
482   QualType IntTy = ACtx.IntTy;
483   QualType LongTy = ACtx.LongTy;
484   QualType LongLongTy = ACtx.LongLongTy;
485   QualType SizeTy = ACtx.getSizeType();
486
487   RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
488   RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
489   RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
490
491   // We are finally ready to define specifications for all supported functions.
492   //
493   // The signature needs to have the correct number of arguments.
494   // However, we insert `Irrelevant' when the type is insignificant.
495   //
496   // Argument ranges should always cover all variants. If return value
497   // is completely unknown, omit it from the respective range set.
498   //
499   // All types in the spec need to be canonical.
500   //
501   // Every item in the list of range sets represents a particular
502   // execution path the analyzer would need to explore once
503   // the call is modeled - a new program state is constructed
504   // for every range set, and each range line in the range set
505   // corresponds to a specific constraint within this state.
506   //
507   // Upon comparing to another argument, the other argument is casted
508   // to the current argument's type. This avoids proper promotion but
509   // seems useful. For example, read() receives size_t argument,
510   // and its return value, which is of type ssize_t, cannot be greater
511   // than this argument. If we made a promotion, and the size argument
512   // is equal to, say, 10, then we'd impose a range of [0, 10] on the
513   // return value, however the correct range is [-1, 10].
514   //
515   // Please update the list of functions in the header after editing!
516   //
517   // The format is as follows:
518   //
519   //{ "function name",
520   //  { spec:
521   //    { argument types list, ... },
522   //    return type, purity, { range set list:
523   //      { range list:
524   //        { argument index, within or out of, {{from, to}, ...} },
525   //        { argument index, compares to argument, {{how, which}} },
526   //        ...
527   //      }
528   //    }
529   //  }
530   //}
531
532 #define SUMMARY_WITH_VARIANTS(identifier) {#identifier, {
533 #define END_SUMMARY_WITH_VARIANTS }},
534 #define VARIANT(argument_types, return_type, invalidation_approach)            \
535   { argument_types, return_type, invalidation_approach, {
536 #define END_VARIANT } },
537 #define SUMMARY(identifier, argument_types, return_type,                       \
538                 invalidation_approach)                                         \
539   { #identifier, { { argument_types, return_type, invalidation_approach, {
540 #define END_SUMMARY } } } },
541 #define ARGUMENT_TYPES(...) { __VA_ARGS__ }
542 #define RETURN_TYPE(x) x
543 #define INVALIDATION_APPROACH(x) x
544 #define CASE {
545 #define END_CASE },
546 #define ARGUMENT_CONDITION(argument_number, condition_kind)                    \
547   { argument_number, condition_kind, {
548 #define END_ARGUMENT_CONDITION }},
549 #define RETURN_VALUE_CONDITION(condition_kind)                                 \
550   { Ret, condition_kind, {
551 #define END_RETURN_VALUE_CONDITION }},
552 #define ARG_NO(x) x##U
553 #define RANGE(x, y) { x, y },
554 #define SINGLE_VALUE(x) RANGE(x, x)
555 #define IS_LESS_THAN(arg) { BO_LE, arg }
556
557   FunctionSummaryMap = {
558     // The isascii() family of functions.
559     SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
560             INVALIDATION_APPROACH(EvalCallAsPure))
561       CASE // Boils down to isupper() or islower() or isdigit()
562         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
563           RANGE('0', '9')
564           RANGE('A', 'Z')
565           RANGE('a', 'z')
566         END_ARGUMENT_CONDITION
567         RETURN_VALUE_CONDITION(OutOfRange)
568           SINGLE_VALUE(0)
569         END_RETURN_VALUE_CONDITION
570       END_CASE
571       CASE // The locale-specific range.
572         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
573           RANGE(128, 255)
574         END_ARGUMENT_CONDITION
575         // No post-condition. We are completely unaware of
576         // locale-specific return values.
577       END_CASE
578       CASE
579         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
580           RANGE('0', '9')
581           RANGE('A', 'Z')
582           RANGE('a', 'z')
583           RANGE(128, 255)
584         END_ARGUMENT_CONDITION
585         RETURN_VALUE_CONDITION(WithinRange)
586           SINGLE_VALUE(0)
587         END_RETURN_VALUE_CONDITION
588       END_CASE
589     END_SUMMARY
590     SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
591             INVALIDATION_APPROACH(EvalCallAsPure))
592       CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
593         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
594           RANGE('A', 'Z')
595           RANGE('a', 'z')
596         END_ARGUMENT_CONDITION
597         RETURN_VALUE_CONDITION(OutOfRange)
598           SINGLE_VALUE(0)
599         END_RETURN_VALUE_CONDITION
600       END_CASE
601       CASE // The locale-specific range.
602         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
603           RANGE(128, 255)
604         END_ARGUMENT_CONDITION
605       END_CASE
606       CASE // Other.
607         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
608           RANGE('A', 'Z')
609           RANGE('a', 'z')
610           RANGE(128, 255)
611         END_ARGUMENT_CONDITION
612         RETURN_VALUE_CONDITION(WithinRange)
613           SINGLE_VALUE(0)
614         END_RETURN_VALUE_CONDITION
615       END_CASE
616     END_SUMMARY
617     SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
618             INVALIDATION_APPROACH(EvalCallAsPure))
619       CASE // Is ASCII.
620         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
621           RANGE(0, 127)
622         END_ARGUMENT_CONDITION
623         RETURN_VALUE_CONDITION(OutOfRange)
624           SINGLE_VALUE(0)
625         END_RETURN_VALUE_CONDITION
626       END_CASE
627       CASE
628         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
629           RANGE(0, 127)
630         END_ARGUMENT_CONDITION
631         RETURN_VALUE_CONDITION(WithinRange)
632           SINGLE_VALUE(0)
633         END_RETURN_VALUE_CONDITION
634       END_CASE
635     END_SUMMARY
636     SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
637             INVALIDATION_APPROACH(EvalCallAsPure))
638       CASE
639         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
640           SINGLE_VALUE('\t')
641           SINGLE_VALUE(' ')
642         END_ARGUMENT_CONDITION
643         RETURN_VALUE_CONDITION(OutOfRange)
644           SINGLE_VALUE(0)
645         END_RETURN_VALUE_CONDITION
646       END_CASE
647       CASE
648         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
649           SINGLE_VALUE('\t')
650           SINGLE_VALUE(' ')
651         END_ARGUMENT_CONDITION
652         RETURN_VALUE_CONDITION(WithinRange)
653           SINGLE_VALUE(0)
654         END_RETURN_VALUE_CONDITION
655       END_CASE
656     END_SUMMARY
657     SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
658             INVALIDATION_APPROACH(EvalCallAsPure))
659       CASE // 0..31 or 127
660         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
661           RANGE(0, 32)
662           SINGLE_VALUE(127)
663         END_ARGUMENT_CONDITION
664         RETURN_VALUE_CONDITION(OutOfRange)
665           SINGLE_VALUE(0)
666         END_RETURN_VALUE_CONDITION
667       END_CASE
668       CASE
669         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
670           RANGE(0, 32)
671           SINGLE_VALUE(127)
672         END_ARGUMENT_CONDITION
673         RETURN_VALUE_CONDITION(WithinRange)
674           SINGLE_VALUE(0)
675         END_RETURN_VALUE_CONDITION
676       END_CASE
677     END_SUMMARY
678     SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
679             INVALIDATION_APPROACH(EvalCallAsPure))
680       CASE // Is a digit.
681         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
682           RANGE('0', '9')
683         END_ARGUMENT_CONDITION
684         RETURN_VALUE_CONDITION(OutOfRange)
685           SINGLE_VALUE(0)
686         END_RETURN_VALUE_CONDITION
687       END_CASE
688       CASE
689         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
690           RANGE('0', '9')
691         END_ARGUMENT_CONDITION
692         RETURN_VALUE_CONDITION(WithinRange)
693           SINGLE_VALUE(0)
694         END_RETURN_VALUE_CONDITION
695       END_CASE
696     END_SUMMARY
697     SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
698             INVALIDATION_APPROACH(EvalCallAsPure))
699       CASE
700         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
701           RANGE(33, 126)
702         END_ARGUMENT_CONDITION
703         RETURN_VALUE_CONDITION(OutOfRange)
704           SINGLE_VALUE(0)
705         END_RETURN_VALUE_CONDITION
706       END_CASE
707       CASE
708         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
709           RANGE(33, 126)
710         END_ARGUMENT_CONDITION
711         RETURN_VALUE_CONDITION(WithinRange)
712           SINGLE_VALUE(0)
713         END_RETURN_VALUE_CONDITION
714       END_CASE
715     END_SUMMARY
716     SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
717             INVALIDATION_APPROACH(EvalCallAsPure))
718       CASE // Is certainly lowercase.
719         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
720           RANGE('a', 'z')
721         END_ARGUMENT_CONDITION
722         RETURN_VALUE_CONDITION(OutOfRange)
723           SINGLE_VALUE(0)
724         END_RETURN_VALUE_CONDITION
725       END_CASE
726       CASE // Is ascii but not lowercase.
727         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
728           RANGE(0, 127)
729         END_ARGUMENT_CONDITION
730         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
731           RANGE('a', 'z')
732         END_ARGUMENT_CONDITION
733         RETURN_VALUE_CONDITION(WithinRange)
734           SINGLE_VALUE(0)
735         END_RETURN_VALUE_CONDITION
736       END_CASE
737       CASE // The locale-specific range.
738         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
739           RANGE(128, 255)
740         END_ARGUMENT_CONDITION
741       END_CASE
742       CASE // Is not an unsigned char.
743         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
744           RANGE(0, 255)
745         END_ARGUMENT_CONDITION
746         RETURN_VALUE_CONDITION(WithinRange)
747           SINGLE_VALUE(0)
748         END_RETURN_VALUE_CONDITION
749       END_CASE
750     END_SUMMARY
751     SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
752             INVALIDATION_APPROACH(EvalCallAsPure))
753       CASE
754         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
755           RANGE(32, 126)
756         END_ARGUMENT_CONDITION
757         RETURN_VALUE_CONDITION(OutOfRange)
758           SINGLE_VALUE(0)
759         END_RETURN_VALUE_CONDITION
760       END_CASE
761       CASE
762         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
763           RANGE(32, 126)
764         END_ARGUMENT_CONDITION
765         RETURN_VALUE_CONDITION(WithinRange)
766           SINGLE_VALUE(0)
767         END_RETURN_VALUE_CONDITION
768       END_CASE
769     END_SUMMARY
770     SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
771             INVALIDATION_APPROACH(EvalCallAsPure))
772       CASE
773         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
774           RANGE('!', '/')
775           RANGE(':', '@')
776           RANGE('[', '`')
777           RANGE('{', '~')
778         END_ARGUMENT_CONDITION
779         RETURN_VALUE_CONDITION(OutOfRange)
780           SINGLE_VALUE(0)
781         END_RETURN_VALUE_CONDITION
782       END_CASE
783       CASE
784         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
785           RANGE('!', '/')
786           RANGE(':', '@')
787           RANGE('[', '`')
788           RANGE('{', '~')
789         END_ARGUMENT_CONDITION
790         RETURN_VALUE_CONDITION(WithinRange)
791           SINGLE_VALUE(0)
792         END_RETURN_VALUE_CONDITION
793       END_CASE
794     END_SUMMARY
795     SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
796             INVALIDATION_APPROACH(EvalCallAsPure))
797       CASE // Space, '\f', '\n', '\r', '\t', '\v'.
798         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
799           RANGE(9, 13)
800           SINGLE_VALUE(' ')
801         END_ARGUMENT_CONDITION
802         RETURN_VALUE_CONDITION(OutOfRange)
803           SINGLE_VALUE(0)
804         END_RETURN_VALUE_CONDITION
805       END_CASE
806       CASE // The locale-specific range.
807         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
808           RANGE(128, 255)
809         END_ARGUMENT_CONDITION
810       END_CASE
811       CASE
812         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
813           RANGE(9, 13)
814           SINGLE_VALUE(' ')
815           RANGE(128, 255)
816         END_ARGUMENT_CONDITION
817         RETURN_VALUE_CONDITION(WithinRange)
818           SINGLE_VALUE(0)
819         END_RETURN_VALUE_CONDITION
820       END_CASE
821     END_SUMMARY
822     SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy),
823             INVALIDATION_APPROACH(EvalCallAsPure))
824       CASE // Is certainly uppercase.
825         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
826           RANGE('A', 'Z')
827         END_ARGUMENT_CONDITION
828         RETURN_VALUE_CONDITION(OutOfRange)
829           SINGLE_VALUE(0)
830         END_RETURN_VALUE_CONDITION
831       END_CASE
832       CASE // The locale-specific range.
833         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
834           RANGE(128, 255)
835         END_ARGUMENT_CONDITION
836       END_CASE
837       CASE // Other.
838         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
839           RANGE('A', 'Z') RANGE(128, 255)
840         END_ARGUMENT_CONDITION
841         RETURN_VALUE_CONDITION(WithinRange)
842           SINGLE_VALUE(0)
843         END_RETURN_VALUE_CONDITION
844       END_CASE
845     END_SUMMARY
846     SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
847             INVALIDATION_APPROACH(EvalCallAsPure))
848       CASE
849         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
850           RANGE('0', '9')
851           RANGE('A', 'F')
852           RANGE('a', 'f')
853         END_ARGUMENT_CONDITION
854         RETURN_VALUE_CONDITION(OutOfRange)
855           SINGLE_VALUE(0)
856         END_RETURN_VALUE_CONDITION
857       END_CASE
858       CASE
859         ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
860           RANGE('0', '9')
861           RANGE('A', 'F')
862           RANGE('a', 'f')
863         END_ARGUMENT_CONDITION
864         RETURN_VALUE_CONDITION(WithinRange)
865           SINGLE_VALUE(0)
866         END_RETURN_VALUE_CONDITION
867       END_CASE
868     END_SUMMARY
869
870     // The getc() family of functions that returns either a char or an EOF.
871     SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
872             INVALIDATION_APPROACH(NoEvalCall))
873       CASE // FIXME: EOF is assumed to be defined as -1.
874         RETURN_VALUE_CONDITION(WithinRange)
875           RANGE(-1, 255)
876         END_RETURN_VALUE_CONDITION
877       END_CASE
878     END_SUMMARY
879     SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
880             INVALIDATION_APPROACH(NoEvalCall))
881       CASE // FIXME: EOF is assumed to be defined as -1.
882         RETURN_VALUE_CONDITION(WithinRange)
883           RANGE(-1, 255)
884         END_RETURN_VALUE_CONDITION
885       END_CASE
886     END_SUMMARY
887     SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy),
888             INVALIDATION_APPROACH(NoEvalCall))
889       CASE // FIXME: EOF is assumed to be defined as -1.
890         RETURN_VALUE_CONDITION(WithinRange)
891           RANGE(-1, 255)
892         END_RETURN_VALUE_CONDITION
893       END_CASE
894     END_SUMMARY
895
896     // read()-like functions that never return more than buffer size.
897     // We are not sure how ssize_t is defined on every platform, so we provide
898     // three variants that should cover common cases.
899     SUMMARY_WITH_VARIANTS(read)
900       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
901               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
902         CASE
903           RETURN_VALUE_CONDITION(ComparesToArgument)
904             IS_LESS_THAN(ARG_NO(2))
905           END_RETURN_VALUE_CONDITION
906           RETURN_VALUE_CONDITION(WithinRange)
907             RANGE(-1, IntMax)
908           END_RETURN_VALUE_CONDITION
909         END_CASE
910       END_VARIANT
911       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
912               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
913         CASE
914           RETURN_VALUE_CONDITION(ComparesToArgument)
915             IS_LESS_THAN(ARG_NO(2))
916           END_RETURN_VALUE_CONDITION
917           RETURN_VALUE_CONDITION(WithinRange)
918             RANGE(-1, LongMax)
919           END_RETURN_VALUE_CONDITION
920         END_CASE
921       END_VARIANT
922       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
923               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
924         CASE
925           RETURN_VALUE_CONDITION(ComparesToArgument)
926             IS_LESS_THAN(ARG_NO(2))
927           END_RETURN_VALUE_CONDITION
928           RETURN_VALUE_CONDITION(WithinRange)
929             RANGE(-1, LongLongMax)
930           END_RETURN_VALUE_CONDITION
931         END_CASE
932       END_VARIANT
933     END_SUMMARY_WITH_VARIANTS
934     SUMMARY_WITH_VARIANTS(write)
935       // Again, due to elusive nature of ssize_t, we have duplicate
936       // our summaries to cover different variants.
937       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
938               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
939         CASE
940           RETURN_VALUE_CONDITION(ComparesToArgument)
941             IS_LESS_THAN(ARG_NO(2))
942           END_RETURN_VALUE_CONDITION
943           RETURN_VALUE_CONDITION(WithinRange)
944             RANGE(-1, IntMax)
945           END_RETURN_VALUE_CONDITION
946         END_CASE
947       END_VARIANT
948       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
949               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
950         CASE
951           RETURN_VALUE_CONDITION(ComparesToArgument)
952             IS_LESS_THAN(ARG_NO(2))
953           END_RETURN_VALUE_CONDITION
954           RETURN_VALUE_CONDITION(WithinRange)
955             RANGE(-1, LongMax)
956           END_RETURN_VALUE_CONDITION
957         END_CASE
958       END_VARIANT
959       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
960               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
961         CASE
962           RETURN_VALUE_CONDITION(ComparesToArgument)
963             IS_LESS_THAN(ARG_NO(2))
964           END_RETURN_VALUE_CONDITION
965           RETURN_VALUE_CONDITION(WithinRange)
966             RANGE(-1, LongLongMax)
967           END_RETURN_VALUE_CONDITION
968         END_CASE
969       END_VARIANT
970     END_SUMMARY_WITH_VARIANTS
971     SUMMARY(fread,
972             ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
973             RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
974       CASE
975         RETURN_VALUE_CONDITION(ComparesToArgument)
976           IS_LESS_THAN(ARG_NO(2))
977         END_RETURN_VALUE_CONDITION
978       END_CASE
979     END_SUMMARY
980     SUMMARY(fwrite,
981             ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
982             RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
983       CASE
984         RETURN_VALUE_CONDITION(ComparesToArgument)
985           IS_LESS_THAN(ARG_NO(2))
986         END_RETURN_VALUE_CONDITION
987       END_CASE
988     END_SUMMARY
989
990     // getline()-like functions either fail or read at least the delimiter.
991     SUMMARY_WITH_VARIANTS(getline)
992       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
993               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
994         CASE
995           RETURN_VALUE_CONDITION(WithinRange)
996             SINGLE_VALUE(-1)
997             RANGE(1, IntMax)
998           END_RETURN_VALUE_CONDITION
999         END_CASE
1000       END_VARIANT
1001       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
1002               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1003         CASE
1004           RETURN_VALUE_CONDITION(WithinRange)
1005             SINGLE_VALUE(-1)
1006             RANGE(1, LongMax)
1007           END_RETURN_VALUE_CONDITION
1008         END_CASE
1009       END_VARIANT
1010       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
1011               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1012         CASE
1013           RETURN_VALUE_CONDITION(WithinRange)
1014             SINGLE_VALUE(-1)
1015             RANGE(1, LongLongMax)
1016           END_RETURN_VALUE_CONDITION
1017         END_CASE
1018       END_VARIANT
1019     END_SUMMARY_WITH_VARIANTS
1020     SUMMARY_WITH_VARIANTS(getdelim)
1021       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1022             RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
1023         CASE
1024           RETURN_VALUE_CONDITION(WithinRange)
1025             SINGLE_VALUE(-1)
1026             RANGE(1, IntMax)
1027           END_RETURN_VALUE_CONDITION
1028         END_CASE
1029       END_VARIANT
1030       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1031             RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1032         CASE
1033           RETURN_VALUE_CONDITION(WithinRange)
1034             SINGLE_VALUE(-1)
1035             RANGE(1, LongMax)
1036           END_RETURN_VALUE_CONDITION
1037         END_CASE
1038       END_VARIANT
1039       VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1040             RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1041         CASE
1042           RETURN_VALUE_CONDITION(WithinRange)
1043             SINGLE_VALUE(-1)
1044             RANGE(1, LongLongMax)
1045           END_RETURN_VALUE_CONDITION
1046         END_CASE
1047       END_VARIANT
1048     END_SUMMARY_WITH_VARIANTS
1049   };
1050 }
1051
1052 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
1053   // If this checker grows large enough to support C++, Objective-C, or other
1054   // standard libraries, we could use multiple register...Checker() functions,
1055   // which would register various checkers with the help of the same Checker
1056   // class, turning on different function summaries.
1057   mgr.registerChecker<StdLibraryFunctionsChecker>();
1058 }