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