Clang Project

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