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//
11// This checker provides a specification format - `Summary' - and
12// contains descriptions of some library functions in this format. Each
13// specification contains a list of branches for splitting the program state
14// upon call, and range constraints on argument and return-value symbols that
15// are satisfied on each branch. This spec can be expanded to include more
16// items, like external effects of the function.
17//
18// The main difference between this approach and the body farms technique is
19// in more explicit control over how many branches are produced. For example,
20// consider standard C function `ispunct(int x)', which returns a non-zero value
21// iff `x' is a punctuation character, that is, when `x' is in range
22//   ['!', '/']   [':', '@']  U  ['[', '\`']  U  ['{', '~'].
23// `Summary' provides only two branches for this function. However,
24// any attempt to describe this range with if-statements in the body farm
25// would result in many more branches. Because each branch needs to be analyzed
26// independently, this significantly reduces performance. Additionally,
27// once we consider a branch on which `x' is in range, say, ['!', '/'],
28// we assume that such branch is an important separate path through the program,
29// which may lead to false positives because considering this particular path
30// was not consciously intended, and therefore it might have been unreachable.
31//
32// This checker uses eval::Call for modeling pure functions (functions without
33// side effets), for which their `Summary' is a precise model. This avoids
34// unnecessary invalidation passes. Conflicts with other checkers are unlikely
35// because if the function has no other effects, other checkers would probably
36// never want to improve upon the modeling done by this checker.
37//
38// Non-pure functions, for which only partial improvement over the default
39// behavior is expected, are modeled via check::PostCall, non-intrusively.
40//
41// The following standard C functions are currently supported:
42//
43//   fgetc      getline   isdigit   isupper
44//   fread      isalnum   isgraph   isxdigit
45//   fwrite     isalpha   islower   read
46//   getc       isascii   isprint   write
47//   getchar    isblank   ispunct
48//   getdelim   iscntrl   isspace
49//
50//===----------------------------------------------------------------------===//
51
52#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
53#include "clang/StaticAnalyzer/Core/BugReporter/BugType.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#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
59#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
60
61using namespace clang;
62using namespace clang::ento;
63
64namespace {
65class StdLibraryFunctionsChecker
66    : public Checker<check::PreCall, check::PostCall, eval::Call> {
67
68  class Summary;
69
70  /// Specify how much the analyzer engine should entrust modeling this function
71  /// to us. If he doesn't, he performs additional invalidations.
72  enum InvalidationKind { NoEvalCall, EvalCallAsPure };
73
74  // The universal integral type to use in value range descriptions.
75  // Unsigned to make sure overflows are well-defined.
76  typedef uint64_t RangeInt;
77
78  /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
79  /// a non-negative integer, which less than 5 and not equal to 2. For
80  /// `ComparesToArgument', holds information about how exactly to compare to
81  /// the argument.
82  typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
83
84  /// A reference to an argument or return value by its number.
85  /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
86  /// obviously uint32_t should be enough for all practical purposes.
87  typedef uint32_t ArgNo;
88  static const ArgNo Ret;
89
90  class ValueConstraint;
91
92  // Pointer to the ValueConstraint. We need a copyable, polymorphic and
93  // default initialize able type (vector needs that). A raw pointer was good,
94  // however, we cannot default initialize that. unique_ptr makes the Summary
95  // class non-copyable, therefore not an option. Releasing the copyability
96  // requirement would render the initialization of the Summary map infeasible.
97  using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
98
99  /// Polymorphic base class that represents a constraint on a given argument
100  /// (or return value) of a function. Derived classes implement different kind
101  /// of constraints, e.g range constraints or correlation between two
102  /// arguments.
103  class ValueConstraint {
104  public:
105    ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
106    virtual ~ValueConstraint() {}
107    /// Apply the effects of the constraint on the given program state. If null
108    /// is returned then the constraint is not feasible.
109    virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
110                                  const Summary &Summary,
111                                  CheckerContext &C) const = 0;
112    virtual ValueConstraintPtr negate() const {
113      llvm_unreachable("Not implemented");
114    };
115
116    // Check whether the constraint is malformed or not. It is malformed if the
117    // specified argument has a mismatch with the given FunctionDecl (e.g. the
118    // arg number is out-of-range of the function's argument list).
119    bool checkValidity(const FunctionDecl *FD) const {
120      const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
121      assert(ValidArg && "Arg out of range!");
122      if (!ValidArg)
123        return false;
124      // Subclasses may further refine the validation.
125      return checkSpecificValidity(FD);
126    }
127    ArgNo getArgNo() const { return ArgN; }
128
129  protected:
130    ArgNo ArgN; // Argument to which we apply the constraint.
131
132    /// Do polymorphic sanity check on the constraint.
133    virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
134      return true;
135    }
136  };
137
138  /// Given a range, should the argument stay inside or outside this range?
139  enum RangeKind { OutOfRange, WithinRange };
140
141  /// Encapsulates a single range on a single symbol within a branch.
142  class RangeConstraint : public ValueConstraint {
143    RangeKind Kind;      // Kind of range definition.
144    IntRangeVector Args; // Polymorphic arguments.
145
146  public:
147    RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Args)
148        : ValueConstraint(ArgN), Kind(Kind), Args(Args) {}
149
150    const IntRangeVector &getRanges() const {
151      return Args;
152    }
153
154  private:
155    ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
156                                      const CallEvent &Call,
157                                      const Summary &Summary) const;
158    ProgramStateRef applyAsWithinRange(ProgramStateRef State,
159                                       const CallEvent &Call,
160                                       const Summary &Summary) const;
161  public:
162    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
163                          const Summary &Summary,
164                          CheckerContext &C) const override {
165      switch (Kind) {
166      case OutOfRange:
167        return applyAsOutOfRange(State, Call, Summary);
168      case WithinRange:
169        return applyAsWithinRange(State, Call, Summary);
170      }
171      llvm_unreachable("Unknown range kind!");
172    }
173
174    ValueConstraintPtr negate() const override {
175      RangeConstraint Tmp(*this);
176      switch (Kind) {
177      case OutOfRange:
178        Tmp.Kind = WithinRange;
179        break;
180      case WithinRange:
181        Tmp.Kind = OutOfRange;
182        break;
183      }
184      return std::make_shared<RangeConstraint>(Tmp);
185    }
186
187    bool checkSpecificValidity(const FunctionDecl *FD) const override {
188      const bool ValidArg =
189          getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
190      assert(ValidArg &&
191             "This constraint should be applied on an integral type");
192      return ValidArg;
193    }
194  };
195
196  class ComparisonConstraint : public ValueConstraint {
197    BinaryOperator::Opcode Opcode;
198    ArgNo OtherArgN;
199
200  public:
201    ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
202                         ArgNo OtherArgN)
203        : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
204    ArgNo getOtherArgNo() const { return OtherArgN; }
205    BinaryOperator::Opcode getOpcode() const { return Opcode; }
206    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
207                          const Summary &Summary,
208                          CheckerContext &C) const override;
209  };
210
211  class NotNullConstraint : public ValueConstraint {
212    using ValueConstraint::ValueConstraint;
213    // This variable has a role when we negate the constraint.
214    bool CannotBeNull = true;
215
216  public:
217    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
218                          const Summary &Summary,
219                          CheckerContext &C) const override {
220      SVal V = getArgSVal(Call, getArgNo());
221      if (V.isUndef())
222        return State;
223
224      DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
225      if (!L.getAs<Loc>())
226        return State;
227
228      return State->assume(L, CannotBeNull);
229    }
230
231    ValueConstraintPtr negate() const override {
232      NotNullConstraint Tmp(*this);
233      Tmp.CannotBeNull = !this->CannotBeNull;
234      return std::make_shared<NotNullConstraint>(Tmp);
235    }
236
237    bool checkSpecificValidity(const FunctionDecl *FD) const override {
238      const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
239      assert(ValidArg &&
240             "This constraint should be applied only on a pointer type");
241      return ValidArg;
242    }
243  };
244
245  // Represents a buffer argument with an additional size argument.
246  // E.g. the first two arguments here:
247  //   ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
248  // Another example:
249  //   size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
250  //   // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
251  class BufferSizeConstraint : public ValueConstraint {
252    // The argument which holds the size of the buffer.
253    ArgNo SizeArgN;
254    // The argument which is a multiplier to size. This is set in case of
255    // `fread` like functions where the size is computed as a multiplication of
256    // two arguments.
257    llvm::Optional<ArgNo> SizeMultiplierArgN;
258    // The operator we use in apply. This is negated in negate().
259    BinaryOperator::Opcode Op = BO_LE;
260
261  public:
262    BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
263        : ValueConstraint(Buffer), SizeArgN(BufSize) {}
264
265    BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
266        : ValueConstraint(Buffer), SizeArgN(BufSize),
267          SizeMultiplierArgN(BufSizeMultiplier) {}
268
269    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
270                          const Summary &Summary,
271                          CheckerContext &C) const override {
272      SValBuilder &SvalBuilder = C.getSValBuilder();
273      // The buffer argument.
274      SVal BufV = getArgSVal(Call, getArgNo());
275      // The size argument.
276      SVal SizeV = getArgSVal(Call, SizeArgN);
277      // Multiply with another argument if given.
278      if (SizeMultiplierArgN) {
279        SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
280        SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
281                                      Summary.getArgType(SizeArgN));
282      }
283      // The dynamic size of the buffer argument, got from the analyzer engine.
284      SVal BufDynSize = getDynamicSizeWithOffset(State, BufV);
285
286      SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
287                                            SvalBuilder.getContext().BoolTy);
288      if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
289        return State->assume(*F, true);
290
291      // We can get here only if the size argument or the dynamic size is
292      // undefined. But the dynamic size should never be undefined, only
293      // unknown. So, here, the size of the argument is undefined, i.e. we
294      // cannot apply the constraint. Actually, other checkers like
295      // CallAndMessage should catch this situation earlier, because we call a
296      // function with an uninitialized argument.
297      llvm_unreachable("Size argument or the dynamic size is Undefined");
298    }
299
300    ValueConstraintPtr negate() const override {
301      BufferSizeConstraint Tmp(*this);
302      Tmp.Op = BinaryOperator::negateComparisonOp(Op);
303      return std::make_shared<BufferSizeConstraint>(Tmp);
304    }
305  };
306
307  /// The complete list of constraints that defines a single branch.
308  typedef std::vector<ValueConstraintPtr> ConstraintSet;
309
310  using ArgTypes = std::vector<QualType>;
311
312  // A placeholder type, we use it whenever we do not care about the concrete
313  // type in a Signature.
314  const QualType Irrelevant{};
315  bool static isIrrelevant(QualType T) { return T.isNull(); }
316
317  // The signature of a function we want to describe with a summary. This is a
318  // concessive signature, meaning there may be irrelevant types in the
319  // signature which we do not check against a function with concrete types.
320  struct Signature {
321    const ArgTypes ArgTys;
322    const QualType RetTy;
323    Signature(ArgTypes ArgTys, QualType RetTy) : ArgTys(ArgTys), RetTy(RetTy) {
324      assertRetTypeSuitableForSignature(RetTy);
325      for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
326        QualType ArgTy = ArgTys[I];
327        assertArgTypeSuitableForSignature(ArgTy);
328      }
329    }
330    bool matches(const FunctionDecl *FD) const;
331
332  private:
333    static void assertArgTypeSuitableForSignature(QualType T) {
334      assert((T.isNull() || !T->isVoidType()) &&
335             "We should have no void types in the spec");
336      assert((T.isNull() || T.isCanonical()) &&
337             "We should only have canonical types in the spec");
338    }
339    static void assertRetTypeSuitableForSignature(QualType T) {
340      assert((T.isNull() || T.isCanonical()) &&
341             "We should only have canonical types in the spec");
342    }
343  };
344
345  static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
346    assert(FD && "Function must be set");
347    QualType T = (ArgN == Ret)
348                     ? FD->getReturnType().getCanonicalType()
349                     : FD->getParamDecl(ArgN)->getType().getCanonicalType();
350    return T;
351  }
352
353  using Cases = std::vector<ConstraintSet>;
354
355  /// A summary includes information about
356  ///   * function prototype (signature)
357  ///   * approach to invalidation,
358  ///   * a list of branches - a list of list of ranges -
359  ///     A branch represents a path in the exploded graph of a function (which
360  ///     is a tree). So, a branch is a series of assumptions. In other words,
361  ///     branches represent split states and additional assumptions on top of
362  ///     the splitting assumption.
363  ///     For example, consider the branches in `isalpha(x)`
364  ///       Branch 1)
365  ///         x is in range ['A', 'Z'] or in ['a', 'z']
366  ///         then the return value is not 0. (I.e. out-of-range [0, 0])
367  ///       Branch 2)
368  ///         x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
369  ///         then the return value is 0.
370  ///   * a list of argument constraints, that must be true on every branch.
371  ///     If these constraints are not satisfied that means a fatal error
372  ///     usually resulting in undefined behaviour.
373  ///
374  /// Application of a summary:
375  ///   The signature and argument constraints together contain information
376  ///   about which functions are handled by the summary. The signature can use
377  ///   "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
378  ///   a signature means that type is not compared to the type of the parameter
379  ///   in the found FunctionDecl. Argument constraints may specify additional
380  ///   rules for the given parameter's type, those rules are checked once the
381  ///   signature is matched.
382  class Summary {
383    const Signature Sign;
384    const InvalidationKind InvalidationKd;
385    Cases CaseConstraints;
386    ConstraintSet ArgConstraints;
387
388    // The function to which the summary applies. This is set after lookup and
389    // match to the signature.
390    const FunctionDecl *FD = nullptr;
391
392  public:
393    Summary(ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd)
394        : Sign(ArgTys, RetTy), InvalidationKd(InvalidationKd) {}
395
396    Summary &Case(ConstraintSet&& CS) {
397      CaseConstraints.push_back(std::move(CS));
398      return *this;
399    }
400    Summary &ArgConstraint(ValueConstraintPtr VC) {
401      ArgConstraints.push_back(VC);
402      return *this;
403    }
404
405    InvalidationKind getInvalidationKd() const { return InvalidationKd; }
406    const Cases &getCaseConstraints() const { return CaseConstraints; }
407    const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
408
409    QualType getArgType(ArgNo ArgN) const {
410      return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
411    }
412
413    // Returns true if the summary should be applied to the given function.
414    // And if yes then store the function declaration.
415    bool matchesAndSet(const FunctionDecl *FD) {
416      bool Result = Sign.matches(FD) && validateByConstraints(FD);
417      if (Result) {
418        assert(!this->FD && "FD must not be set more than once");
419        this->FD = FD;
420      }
421      return Result;
422    }
423
424  private:
425    // Once we know the exact type of the function then do sanity check on all
426    // the given constraints.
427    bool validateByConstraints(const FunctionDecl *FD) const {
428      for (const ConstraintSet &Case : CaseConstraints)
429        for (const ValueConstraintPtr &Constraint : Case)
430          if (!Constraint->checkValidity(FD))
431            return false;
432      for (const ValueConstraintPtr &Constraint : ArgConstraints)
433        if (!Constraint->checkValidity(FD))
434          return false;
435      return true;
436    }
437  };
438
439  // The map of all functions supported by the checker. It is initialized
440  // lazily, and it doesn't change after initialization.
441  using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
442  mutable FunctionSummaryMapType FunctionSummaryMap;
443
444  mutable std::unique_ptr<BugType> BT_InvalidArg;
445
446  static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
447    return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
448  }
449
450public:
451  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
452  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
453  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
454
455  enum CheckKind {
456    CK_StdCLibraryFunctionArgsChecker,
457    CK_StdCLibraryFunctionsTesterChecker,
458    CK_NumCheckKinds
459  };
460  DefaultBool ChecksEnabled[CK_NumCheckKinds];
461  CheckerNameRef CheckNames[CK_NumCheckKinds];
462
463  bool DisplayLoadedSummaries = false;
464  bool ModelPOSIX = false;
465
466private:
467  Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
468                                        CheckerContext &C) const;
469  Optional<Summary> findFunctionSummary(const CallEvent &Call,
470                                        CheckerContext &C) const;
471
472  void initFunctionSummaries(CheckerContext &C) const;
473
474  void reportBug(const CallEvent &Call, ExplodedNode *N,
475                 CheckerContext &C) const {
476    if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
477      return;
478    // TODO Add detailed diagnostic.
479    StringRef Msg = "Function argument constraint is not satisfied";
480    if (!BT_InvalidArg)
481      BT_InvalidArg = std::make_unique<BugType>(
482          CheckNames[CK_StdCLibraryFunctionArgsChecker],
483          "Unsatisfied argument constraints", categories::LogicError);
484    auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
485    bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R);
486    C.emitReport(std::move(R));
487  }
488};
489
490const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
491    std::numeric_limits<ArgNo>::max();
492
493} // end of anonymous namespace
494
495ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange(
496    ProgramStateRef State, const CallEvent &Call,
497    const Summary &Summary) const {
498
499  ProgramStateManager &Mgr = State->getStateManager();
500  SValBuilder &SVB = Mgr.getSValBuilder();
501  BasicValueFactory &BVF = SVB.getBasicValueFactory();
502  ConstraintManager &CM = Mgr.getConstraintManager();
503  QualType T = Summary.getArgType(getArgNo());
504  SVal V = getArgSVal(Call, getArgNo());
505
506  if (auto N = V.getAs<NonLoc>()) {
507    const IntRangeVector &R = getRanges();
508    size_t E = R.size();
509    for (size_t I = 0; I != E; ++I) {
510      const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
511      const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
512      assert(Min <= Max);
513      State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
514      if (!State)
515        break;
516    }
517  }
518
519  return State;
520}
521
522ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange(
523    ProgramStateRef State, const CallEvent &Call,
524    const Summary &Summary) const {
525
526  ProgramStateManager &Mgr = State->getStateManager();
527  SValBuilder &SVB = Mgr.getSValBuilder();
528  BasicValueFactory &BVF = SVB.getBasicValueFactory();
529  ConstraintManager &CM = Mgr.getConstraintManager();
530  QualType T = Summary.getArgType(getArgNo());
531  SVal V = getArgSVal(Call, getArgNo());
532
533  // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
534  // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
535  // and then cut away all holes in R one by one.
536  //
537  // E.g. consider a range list R as [A, B] and [C, D]
538  // -------+--------+------------------+------------+----------->
539  //        A        B                  C            D
540  // Then we assume that the value is not in [-inf, A - 1],
541  // then not in [D + 1, +inf], then not in [B + 1, C - 1]
542  if (auto N = V.getAs<NonLoc>()) {
543    const IntRangeVector &R = getRanges();
544    size_t E = R.size();
545
546    const llvm::APSInt &MinusInf = BVF.getMinValue(T);
547    const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
548
549    const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
550    if (Left != PlusInf) {
551      assert(MinusInf <= Left);
552      State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
553      if (!State)
554        return nullptr;
555    }
556
557    const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
558    if (Right != MinusInf) {
559      assert(Right <= PlusInf);
560      State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
561      if (!State)
562        return nullptr;
563    }
564
565    for (size_t I = 1; I != E; ++I) {
566      const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
567      const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
568      if (Min <= Max) {
569        State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
570        if (!State)
571          return nullptr;
572      }
573    }
574  }
575
576  return State;
577}
578
579ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
580    ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
581    CheckerContext &C) const {
582
583  ProgramStateManager &Mgr = State->getStateManager();
584  SValBuilder &SVB = Mgr.getSValBuilder();
585  QualType CondT = SVB.getConditionType();
586  QualType T = Summary.getArgType(getArgNo());
587  SVal V = getArgSVal(Call, getArgNo());
588
589  BinaryOperator::Opcode Op = getOpcode();
590  ArgNo OtherArg = getOtherArgNo();
591  SVal OtherV = getArgSVal(Call, OtherArg);
592  QualType OtherT = Summary.getArgType(OtherArg);
593  // Note: we avoid integral promotion for comparison.
594  OtherV = SVB.evalCast(OtherV, T, OtherT);
595  if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
596                       .getAs<DefinedOrUnknownSVal>())
597    State = State->assume(*CompV, true);
598  return State;
599}
600
601void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
602                                              CheckerContext &C) const {
603  Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
604  if (!FoundSummary)
605    return;
606
607  const Summary &Summary = *FoundSummary;
608  ProgramStateRef State = C.getState();
609
610  ProgramStateRef NewState = State;
611  for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
612    ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
613    ProgramStateRef FailureSt =
614        Constraint->negate()->apply(NewState, Call, Summary, C);
615    // The argument constraint is not satisfied.
616    if (FailureSt && !SuccessSt) {
617      if (ExplodedNode *N = C.generateErrorNode(NewState))
618        reportBug(Call, N, C);
619      break;
620    } else {
621      // We will apply the constraint even if we cannot reason about the
622      // argument. This means both SuccessSt and FailureSt can be true. If we
623      // weren't applying the constraint that would mean that symbolic
624      // execution continues on a code whose behaviour is undefined.
625      assert(SuccessSt);
626      NewState = SuccessSt;
627    }
628  }
629  if (NewState && NewState != State)
630    C.addTransition(NewState);
631}
632
633void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
634                                               CheckerContext &C) const {
635  Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
636  if (!FoundSummary)
637    return;
638
639  // Now apply the constraints.
640  const Summary &Summary = *FoundSummary;
641  ProgramStateRef State = C.getState();
642
643  // Apply case/branch specifications.
644  for (const ConstraintSet &Case : Summary.getCaseConstraints()) {
645    ProgramStateRef NewState = State;
646    for (const ValueConstraintPtr &Constraint : Case) {
647      NewState = Constraint->apply(NewState, Call, Summary, C);
648      if (!NewState)
649        break;
650    }
651
652    if (NewState && NewState != State)
653      C.addTransition(NewState);
654  }
655}
656
657bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
658                                          CheckerContext &C) const {
659  Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
660  if (!FoundSummary)
661    return false;
662
663  const Summary &Summary = *FoundSummary;
664  switch (Summary.getInvalidationKd()) {
665  case EvalCallAsPure: {
666    ProgramStateRef State = C.getState();
667    const LocationContext *LC = C.getLocationContext();
668    const auto *CE = cast_or_null<CallExpr>(Call.getOriginExpr());
669    SVal V = C.getSValBuilder().conjureSymbolVal(
670        CE, LC, CE->getType().getCanonicalType(), C.blockCount());
671    State = State->BindExpr(CE, LC, V);
672    C.addTransition(State);
673    return true;
674  }
675  case NoEvalCall:
676    // Summary tells us to avoid performing eval::Call. The function is possibly
677    // evaluated by another checker, or evaluated conservatively.
678    return false;
679  }
680  llvm_unreachable("Unknown invalidation kind!");
681}
682
683bool StdLibraryFunctionsChecker::Signature::matches(
684    const FunctionDecl *FD) const {
685  // Check number of arguments:
686  if (FD->param_size() != ArgTys.size())
687    return false;
688
689  // Check return type.
690  if (!isIrrelevant(RetTy))
691    if (RetTy != FD->getReturnType().getCanonicalType())
692      return false;
693
694  // Check argument types.
695  for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
696    QualType ArgTy = ArgTys[I];
697    if (isIrrelevant(ArgTy))
698      continue;
699    if (ArgTy != FD->getParamDecl(I)->getType().getCanonicalType())
700      return false;
701  }
702
703  return true;
704}
705
706Optional<StdLibraryFunctionsChecker::Summary>
707StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
708                                                CheckerContext &C) const {
709  if (!FD)
710    return None;
711
712  initFunctionSummaries(C);
713
714  auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
715  if (FSMI == FunctionSummaryMap.end())
716    return None;
717  return FSMI->second;
718}
719
720Optional<StdLibraryFunctionsChecker::Summary>
721StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
722                                                CheckerContext &C) const {
723  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
724  if (!FD)
725    return None;
726  return findFunctionSummary(FD, C);
727}
728
729static llvm::Optional<QualType> lookupType(StringRef Name,
730                                           const ASTContext &ACtx) {
731  IdentifierInfo &II = ACtx.Idents.get(Name);
732  auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
733  if (LookupRes.size() == 0)
734    return None;
735
736  // Prioritze typedef declarations.
737  // This is needed in case of C struct typedefs. E.g.:
738  //   typedef struct FILE FILE;
739  // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' and
740  // we have a TypedefDecl with the name 'FILE'.
741  for (Decl *D : LookupRes)
742    if (auto *TD = dyn_cast<TypedefNameDecl>(D))
743      return ACtx.getTypeDeclType(TD).getCanonicalType();
744
745  // Find the first TypeDecl.
746  // There maybe cases when a function has the same name as a struct.
747  // E.g. in POSIX: `struct stat` and the function `stat()`:
748  //   int stat(const char *restrict path, struct stat *restrict buf);
749  for (Decl *D : LookupRes)
750    if (auto *TD = dyn_cast<TypeDecl>(D))
751      return ACtx.getTypeDeclType(TD).getCanonicalType();
752  return None;
753}
754
755void StdLibraryFunctionsChecker::initFunctionSummaries(
756    CheckerContext &C) const {
757  if (!FunctionSummaryMap.empty())
758    return;
759
760  SValBuilder &SVB = C.getSValBuilder();
761  BasicValueFactory &BVF = SVB.getBasicValueFactory();
762  const ASTContext &ACtx = BVF.getContext();
763
764  // These types are useful for writing specifications quickly,
765  // New specifications should probably introduce more types.
766  // Some types are hard to obtain from the AST, eg. "ssize_t".
767  // In such cases it should be possible to provide multiple variants
768  // of function summary for common cases (eg. ssize_t could be int or long
769  // or long long, so three summary variants would be enough).
770  // Of course, function variants are also useful for C++ overloads.
771  const QualType VoidTy = ACtx.VoidTy;
772  const QualType IntTy = ACtx.IntTy;
773  const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
774  const QualType LongTy = ACtx.LongTy;
775  const QualType LongLongTy = ACtx.LongLongTy;
776  const QualType SizeTy = ACtx.getSizeType();
777
778  const QualType VoidPtrTy = ACtx.VoidPtrTy; // void *
779  const QualType IntPtrTy = ACtx.getPointerType(IntTy); // int *
780  const QualType UnsignedIntPtrTy =
781      ACtx.getPointerType(UnsignedIntTy); // unsigned int *
782  const QualType VoidPtrRestrictTy =
783      ACtx.getLangOpts().C99 ? ACtx.getRestrictType(VoidPtrTy) // void *restrict
784                             : VoidPtrTy;
785  const QualType ConstVoidPtrTy =
786      ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void *
787  const QualType CharPtrTy = ACtx.getPointerType(ACtx.CharTy); // char *
788  const QualType CharPtrRestrictTy =
789      ACtx.getLangOpts().C99 ? ACtx.getRestrictType(CharPtrTy) // char *restrict
790                             : CharPtrTy;
791  const QualType ConstCharPtrTy =
792      ACtx.getPointerType(ACtx.CharTy.withConst()); // const char *
793  const QualType ConstCharPtrRestrictTy =
794      ACtx.getLangOpts().C99
795          ? ACtx.getRestrictType(ConstCharPtrTy) // const char *restrict
796          : ConstCharPtrTy;
797  const QualType Wchar_tPtrTy = ACtx.getPointerType(ACtx.WCharTy); // wchar_t *
798  const QualType ConstWchar_tPtrTy =
799      ACtx.getPointerType(ACtx.WCharTy.withConst()); // const wchar_t *
800  const QualType ConstVoidPtrRestrictTy =
801      ACtx.getLangOpts().C99
802          ? ACtx.getRestrictType(ConstVoidPtrTy) // const void *restrict
803          : ConstVoidPtrTy;
804
805  const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
806  const RangeInt UnsignedIntMax =
807      BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
808  const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
809  const RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
810  const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
811
812  // Set UCharRangeMax to min of int or uchar maximum value.
813  // The C standard states that the arguments of functions like isalpha must
814  // be representable as an unsigned char. Their type is 'int', so the max
815  // value of the argument should be min(UCharMax, IntMax). This just happen
816  // to be true for commonly used and well tested instruction set
817  // architectures, but not for others.
818  const RangeInt UCharRangeMax =
819      std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
820
821  // The platform dependent value of EOF.
822  // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
823  const auto EOFv = [&C]() -> RangeInt {
824    if (const llvm::Optional<int> OptInt =
825            tryExpandAsInteger("EOF", C.getPreprocessor()))
826      return *OptInt;
827    return -1;
828  }();
829
830  // Auxiliary class to aid adding summaries to the summary map.
831  struct AddToFunctionSummaryMap {
832    const ASTContext &ACtx;
833    FunctionSummaryMapType &Map;
834    bool DisplayLoadedSummaries;
835    AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
836                            bool DisplayLoadedSummaries)
837        : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
838    }
839
840    // Add a summary to a FunctionDecl found by lookup. The lookup is performed
841    // by the given Name, and in the global scope. The summary will be attached
842    // to the found FunctionDecl only if the signatures match.
843    void operator()(StringRef Name, Summary S) {
844      IdentifierInfo &II = ACtx.Idents.get(Name);
845      auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
846      if (LookupRes.size() == 0)
847        return;
848      for (Decl *D : LookupRes) {
849        if (auto *FD = dyn_cast<FunctionDecl>(D)) {
850          if (S.matchesAndSet(FD)) {
851            auto Res = Map.insert({FD->getCanonicalDecl(), S});
852            assert(Res.second && "Function already has a summary set!");
853            (void)Res;
854            if (DisplayLoadedSummaries) {
855              llvm::errs() << "Loaded summary for: ";
856              FD->print(llvm::errs());
857              llvm::errs() << "\n";
858            }
859            return;
860          }
861        }
862      }
863    }
864    // Add several summaries for the given name.
865    void operator()(StringRef Name, const std::vector<Summary> &Summaries) {
866      for (const Summary &S : Summaries)
867        operator()(Name, S);
868    }
869  } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
870
871  // We are finally ready to define specifications for all supported functions.
872  //
873  // The signature needs to have the correct number of arguments.
874  // However, we insert `Irrelevant' when the type is insignificant.
875  //
876  // Argument ranges should always cover all variants. If return value
877  // is completely unknown, omit it from the respective range set.
878  //
879  // All types in the spec need to be canonical.
880  //
881  // Every item in the list of range sets represents a particular
882  // execution path the analyzer would need to explore once
883  // the call is modeled - a new program state is constructed
884  // for every range set, and each range line in the range set
885  // corresponds to a specific constraint within this state.
886  //
887  // Upon comparing to another argument, the other argument is casted
888  // to the current argument's type. This avoids proper promotion but
889  // seems useful. For example, read() receives size_t argument,
890  // and its return value, which is of type ssize_t, cannot be greater
891  // than this argument. If we made a promotion, and the size argument
892  // is equal to, say, 10, then we'd impose a range of [0, 10] on the
893  // return value, however the correct range is [-1, 10].
894  //
895  // Please update the list of functions in the header after editing!
896
897  // Below are helpers functions to create the summaries.
898  auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
899                              IntRangeVector Ranges) {
900    return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
901  };
902  auto BufferSize = [](auto... Args) {
903    return std::make_shared<BufferSizeConstraint>(Args...);
904  };
905  struct {
906    auto operator()(RangeKind Kind, IntRangeVector Ranges) {
907      return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
908    }
909    auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
910      return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
911    }
912  } ReturnValueCondition;
913  auto Range = [](RangeInt b, RangeInt e) {
914    return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
915  };
916  auto SingleValue = [](RangeInt v) {
917    return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
918  };
919  auto LessThanOrEq = BO_LE;
920  auto NotNull = [&](ArgNo ArgN) {
921    return std::make_shared<NotNullConstraint>(ArgN);
922  };
923
924  Optional<QualType> FileTy = lookupType("FILE", ACtx);
925  Optional<QualType> FilePtrTy, FilePtrRestrictTy;
926  if (FileTy) {
927    // FILE *
928    FilePtrTy = ACtx.getPointerType(*FileTy);
929    // FILE *restrict
930    FilePtrRestrictTy =
931        ACtx.getLangOpts().C99 ? ACtx.getRestrictType(*FilePtrTy) : *FilePtrTy;
932  }
933
934  using RetType = QualType;
935  // Templates for summaries that are reused by many functions.
936  auto Getc = [&]() {
937    return Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall)
938        .Case({ReturnValueCondition(WithinRange,
939                                    {{EOFv, EOFv}, {0, UCharRangeMax}})});
940  };
941  auto Read = [&](RetType R, RangeInt Max) {
942    return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R},
943                   NoEvalCall)
944        .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
945               ReturnValueCondition(WithinRange, Range(-1, Max))});
946  };
947  auto Fread = [&]() {
948    return Summary(
949               ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, *FilePtrRestrictTy},
950               RetType{SizeTy}, NoEvalCall)
951        .Case({
952            ReturnValueCondition(LessThanOrEq, ArgNo(2)),
953        })
954        .ArgConstraint(NotNull(ArgNo(0)));
955  };
956  auto Fwrite = [&]() {
957    return Summary(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, SizeTy,
958                            *FilePtrRestrictTy},
959                   RetType{SizeTy}, NoEvalCall)
960        .Case({
961            ReturnValueCondition(LessThanOrEq, ArgNo(2)),
962        })
963        .ArgConstraint(NotNull(ArgNo(0)));
964  };
965  auto Getline = [&](RetType R, RangeInt Max) {
966    return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R},
967                   NoEvalCall)
968        .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})});
969  };
970
971  // The isascii() family of functions.
972  // The behavior is undefined if the value of the argument is not
973  // representable as unsigned char or is not equal to EOF. See e.g. C99
974  // 7.4.1.2 The isalpha function (p: 181-182).
975  addToFunctionSummaryMap(
976      "isalnum",
977      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
978          // Boils down to isupper() or islower() or isdigit().
979          .Case({ArgumentCondition(0U, WithinRange,
980                                   {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
981                 ReturnValueCondition(OutOfRange, SingleValue(0))})
982          // The locale-specific range.
983          // No post-condition. We are completely unaware of
984          // locale-specific return values.
985          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
986          .Case(
987              {ArgumentCondition(
988                   0U, OutOfRange,
989                   {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
990               ReturnValueCondition(WithinRange, SingleValue(0))})
991          .ArgConstraint(ArgumentCondition(
992              0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
993  addToFunctionSummaryMap(
994      "isalpha",
995      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
996          .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
997                 ReturnValueCondition(OutOfRange, SingleValue(0))})
998          // The locale-specific range.
999          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1000          .Case({ArgumentCondition(
1001                     0U, OutOfRange,
1002                     {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1003                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1004  addToFunctionSummaryMap(
1005      "isascii",
1006      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1007          .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1008                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1009          .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1010                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1011  addToFunctionSummaryMap(
1012      "isblank",
1013      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1014          .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1015                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1016          .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1017                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1018  addToFunctionSummaryMap(
1019      "iscntrl",
1020      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1021          .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1022                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1023          .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1024                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1025  addToFunctionSummaryMap(
1026      "isdigit",
1027      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1028          .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1029                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1030          .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1031                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1032  addToFunctionSummaryMap(
1033      "isgraph",
1034      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1035          .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1036                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1037          .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1038                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1039  addToFunctionSummaryMap(
1040      "islower",
1041      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1042          // Is certainly lowercase.
1043          .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1044                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1045          // Is ascii but not lowercase.
1046          .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1047                 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1048                 ReturnValueCondition(WithinRange, SingleValue(0))})
1049          // The locale-specific range.
1050          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1051          // Is not an unsigned char.
1052          .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1053                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1054  addToFunctionSummaryMap(
1055      "isprint",
1056      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1057          .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1058                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1059          .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1060                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1061  addToFunctionSummaryMap(
1062      "ispunct",
1063      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1064          .Case({ArgumentCondition(
1065                     0U, WithinRange,
1066                     {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1067                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1068          .Case({ArgumentCondition(
1069                     0U, OutOfRange,
1070                     {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1071                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1072  addToFunctionSummaryMap(
1073      "isspace",
1074      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1075          // Space, '\f', '\n', '\r', '\t', '\v'.
1076          .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1077                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1078          // The locale-specific range.
1079          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1080          .Case({ArgumentCondition(0U, OutOfRange,
1081                                   {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1082                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1083  addToFunctionSummaryMap(
1084      "isupper",
1085      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1086          // Is certainly uppercase.
1087          .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1088                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1089          // The locale-specific range.
1090          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1091          // Other.
1092          .Case({ArgumentCondition(0U, OutOfRange,
1093                                   {{'A', 'Z'}, {128, UCharRangeMax}}),
1094                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1095  addToFunctionSummaryMap(
1096      "isxdigit",
1097      Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1098          .Case({ArgumentCondition(0U, WithinRange,
1099                                   {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1100                 ReturnValueCondition(OutOfRange, SingleValue(0))})
1101          .Case({ArgumentCondition(0U, OutOfRange,
1102                                   {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1103                 ReturnValueCondition(WithinRange, SingleValue(0))}));
1104
1105  // The getc() family of functions that returns either a char or an EOF.
1106  if (FilePtrTy) {
1107    addToFunctionSummaryMap("getc", Getc());
1108    addToFunctionSummaryMap("fgetc", Getc());
1109  }
1110  addToFunctionSummaryMap(
1111      "getchar", Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall)
1112                     .Case({ReturnValueCondition(
1113                         WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})}));
1114
1115  // read()-like functions that never return more than buffer size.
1116  if (FilePtrRestrictTy) {
1117    addToFunctionSummaryMap("fread", Fread());
1118    addToFunctionSummaryMap("fwrite", Fwrite());
1119  }
1120
1121  // We are not sure how ssize_t is defined on every platform, so we
1122  // provide three variants that should cover common cases.
1123  // FIXME these are actually defined by POSIX and not by the C standard, we
1124  // should handle them together with the rest of the POSIX functions.
1125  addToFunctionSummaryMap("read", {Read(IntTy, IntMax), Read(LongTy, LongMax),
1126                                   Read(LongLongTy, LongLongMax)});
1127  addToFunctionSummaryMap("write", {Read(IntTy, IntMax), Read(LongTy, LongMax),
1128                                    Read(LongLongTy, LongLongMax)});
1129
1130  // getline()-like functions either fail or read at least the delimiter.
1131  // FIXME these are actually defined by POSIX and not by the C standard, we
1132  // should handle them together with the rest of the POSIX functions.
1133  addToFunctionSummaryMap("getline",
1134                          {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
1135                           Getline(LongLongTy, LongLongMax)});
1136  addToFunctionSummaryMap("getdelim",
1137                          {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
1138                           Getline(LongLongTy, LongLongMax)});
1139
1140  if (ModelPOSIX) {
1141
1142    // long a64l(const char *str64);
1143    addToFunctionSummaryMap(
1144        "a64l", Summary(ArgTypes{ConstCharPtrTy}, RetType{LongTy}, NoEvalCall)
1145                    .ArgConstraint(NotNull(ArgNo(0))));
1146
1147    // char *l64a(long value);
1148    addToFunctionSummaryMap(
1149        "l64a", Summary(ArgTypes{LongTy}, RetType{CharPtrTy}, NoEvalCall)
1150                    .ArgConstraint(
1151                        ArgumentCondition(0, WithinRange, Range(0, LongMax))));
1152
1153    // int access(const char *pathname, int amode);
1154    addToFunctionSummaryMap("access", Summary(ArgTypes{ConstCharPtrTy, IntTy},
1155                                              RetType{IntTy}, NoEvalCall)
1156                                          .ArgConstraint(NotNull(ArgNo(0))));
1157
1158    // int faccessat(int dirfd, const char *pathname, int mode, int flags);
1159    addToFunctionSummaryMap(
1160        "faccessat", Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
1161                             RetType{IntTy}, NoEvalCall)
1162                         .ArgConstraint(NotNull(ArgNo(1))));
1163
1164    // int dup(int fildes);
1165    addToFunctionSummaryMap(
1166        "dup", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1167                   .ArgConstraint(
1168                       ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1169
1170    // int dup2(int fildes1, int filedes2);
1171    addToFunctionSummaryMap(
1172        "dup2",
1173        Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall)
1174            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1175            .ArgConstraint(
1176                ArgumentCondition(1, WithinRange, Range(0, IntMax))));
1177
1178    // int fdatasync(int fildes);
1179    addToFunctionSummaryMap(
1180        "fdatasync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1181                         .ArgConstraint(ArgumentCondition(0, WithinRange,
1182                                                          Range(0, IntMax))));
1183
1184    // int fnmatch(const char *pattern, const char *string, int flags);
1185    addToFunctionSummaryMap(
1186        "fnmatch", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
1187                           RetType{IntTy}, EvalCallAsPure)
1188                       .ArgConstraint(NotNull(ArgNo(0)))
1189                       .ArgConstraint(NotNull(ArgNo(1))));
1190
1191    // int fsync(int fildes);
1192    addToFunctionSummaryMap(
1193        "fsync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1194                     .ArgConstraint(
1195                         ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1196
1197    Optional<QualType> Off_tTy = lookupType("off_t", ACtx);
1198
1199    if (Off_tTy)
1200      // int truncate(const char *path, off_t length);
1201      addToFunctionSummaryMap("truncate",
1202                              Summary(ArgTypes{ConstCharPtrTy, *Off_tTy},
1203                                      RetType{IntTy}, NoEvalCall)
1204                                  .ArgConstraint(NotNull(ArgNo(0))));
1205
1206    // int symlink(const char *oldpath, const char *newpath);
1207    addToFunctionSummaryMap("symlink",
1208                            Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1209                                    RetType{IntTy}, NoEvalCall)
1210                                .ArgConstraint(NotNull(ArgNo(0)))
1211                                .ArgConstraint(NotNull(ArgNo(1))));
1212
1213    // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
1214    addToFunctionSummaryMap(
1215        "symlinkat",
1216        Summary(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, RetType{IntTy},
1217                NoEvalCall)
1218            .ArgConstraint(NotNull(ArgNo(0)))
1219            .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
1220            .ArgConstraint(NotNull(ArgNo(2))));
1221
1222    if (Off_tTy)
1223      // int lockf(int fd, int cmd, off_t len);
1224      addToFunctionSummaryMap(
1225          "lockf",
1226          Summary(ArgTypes{IntTy, IntTy, *Off_tTy}, RetType{IntTy}, NoEvalCall)
1227              .ArgConstraint(
1228                  ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1229
1230    Optional<QualType> Mode_tTy = lookupType("mode_t", ACtx);
1231
1232    if (Mode_tTy)
1233      // int creat(const char *pathname, mode_t mode);
1234      addToFunctionSummaryMap("creat",
1235                              Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy},
1236                                      RetType{IntTy}, NoEvalCall)
1237                                  .ArgConstraint(NotNull(ArgNo(0))));
1238
1239    // unsigned int sleep(unsigned int seconds);
1240    addToFunctionSummaryMap(
1241        "sleep",
1242        Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall)
1243            .ArgConstraint(
1244                ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1245
1246    Optional<QualType> DirTy = lookupType("DIR", ACtx);
1247    Optional<QualType> DirPtrTy;
1248    if (DirTy)
1249      DirPtrTy = ACtx.getPointerType(*DirTy);
1250
1251    if (DirPtrTy)
1252      // int dirfd(DIR *dirp);
1253      addToFunctionSummaryMap(
1254          "dirfd", Summary(ArgTypes{*DirPtrTy}, RetType{IntTy}, NoEvalCall)
1255                       .ArgConstraint(NotNull(ArgNo(0))));
1256
1257    // unsigned int alarm(unsigned int seconds);
1258    addToFunctionSummaryMap(
1259        "alarm",
1260        Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall)
1261            .ArgConstraint(
1262                ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1263
1264    if (DirPtrTy)
1265      // int closedir(DIR *dir);
1266      addToFunctionSummaryMap(
1267          "closedir", Summary(ArgTypes{*DirPtrTy}, RetType{IntTy}, NoEvalCall)
1268                          .ArgConstraint(NotNull(ArgNo(0))));
1269
1270    // char *strdup(const char *s);
1271    addToFunctionSummaryMap("strdup", Summary(ArgTypes{ConstCharPtrTy},
1272                                              RetType{CharPtrTy}, NoEvalCall)
1273                                          .ArgConstraint(NotNull(ArgNo(0))));
1274
1275    // char *strndup(const char *s, size_t n);
1276    addToFunctionSummaryMap(
1277        "strndup", Summary(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy},
1278                           NoEvalCall)
1279                       .ArgConstraint(NotNull(ArgNo(0)))
1280                       .ArgConstraint(ArgumentCondition(1, WithinRange,
1281                                                        Range(0, SizeMax))));
1282
1283    // wchar_t *wcsdup(const wchar_t *s);
1284    addToFunctionSummaryMap("wcsdup", Summary(ArgTypes{ConstWchar_tPtrTy},
1285                                              RetType{Wchar_tPtrTy}, NoEvalCall)
1286                                          .ArgConstraint(NotNull(ArgNo(0))));
1287
1288    // int mkstemp(char *template);
1289    addToFunctionSummaryMap(
1290        "mkstemp", Summary(ArgTypes{CharPtrTy}, RetType{IntTy}, NoEvalCall)
1291                       .ArgConstraint(NotNull(ArgNo(0))));
1292
1293    // char *mkdtemp(char *template);
1294    addToFunctionSummaryMap(
1295        "mkdtemp", Summary(ArgTypes{CharPtrTy}, RetType{CharPtrTy}, NoEvalCall)
1296                       .ArgConstraint(NotNull(ArgNo(0))));
1297
1298    // char *getcwd(char *buf, size_t size);
1299    addToFunctionSummaryMap(
1300        "getcwd",
1301        Summary(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}, NoEvalCall)
1302            .ArgConstraint(
1303                ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1304
1305    if (Mode_tTy) {
1306      // int mkdir(const char *pathname, mode_t mode);
1307      addToFunctionSummaryMap("mkdir",
1308                              Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy},
1309                                      RetType{IntTy}, NoEvalCall)
1310                                  .ArgConstraint(NotNull(ArgNo(0))));
1311
1312      // int mkdirat(int dirfd, const char *pathname, mode_t mode);
1313      addToFunctionSummaryMap(
1314          "mkdirat", Summary(ArgTypes{IntTy, ConstCharPtrTy, *Mode_tTy},
1315                             RetType{IntTy}, NoEvalCall)
1316                         .ArgConstraint(NotNull(ArgNo(1))));
1317    }
1318
1319    Optional<QualType> Dev_tTy = lookupType("dev_t", ACtx);
1320
1321    if (Mode_tTy && Dev_tTy) {
1322      // int mknod(const char *pathname, mode_t mode, dev_t dev);
1323      addToFunctionSummaryMap(
1324          "mknod", Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy, *Dev_tTy},
1325                           RetType{IntTy}, NoEvalCall)
1326                       .ArgConstraint(NotNull(ArgNo(0))));
1327
1328      // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
1329      addToFunctionSummaryMap("mknodat", Summary(ArgTypes{IntTy, ConstCharPtrTy,
1330                                                          *Mode_tTy, *Dev_tTy},
1331                                                 RetType{IntTy}, NoEvalCall)
1332                                             .ArgConstraint(NotNull(ArgNo(1))));
1333    }
1334
1335    if (Mode_tTy) {
1336      // int chmod(const char *path, mode_t mode);
1337      addToFunctionSummaryMap("chmod",
1338                              Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy},
1339                                      RetType{IntTy}, NoEvalCall)
1340                                  .ArgConstraint(NotNull(ArgNo(0))));
1341
1342      // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
1343      addToFunctionSummaryMap(
1344          "fchmodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, *Mode_tTy, IntTy},
1345                              RetType{IntTy}, NoEvalCall)
1346                          .ArgConstraint(ArgumentCondition(0, WithinRange,
1347                                                           Range(0, IntMax)))
1348                          .ArgConstraint(NotNull(ArgNo(1))));
1349
1350      // int fchmod(int fildes, mode_t mode);
1351      addToFunctionSummaryMap(
1352          "fchmod",
1353          Summary(ArgTypes{IntTy, *Mode_tTy}, RetType{IntTy}, NoEvalCall)
1354              .ArgConstraint(
1355                  ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1356    }
1357
1358    Optional<QualType> Uid_tTy = lookupType("uid_t", ACtx);
1359    Optional<QualType> Gid_tTy = lookupType("gid_t", ACtx);
1360
1361    if (Uid_tTy && Gid_tTy) {
1362      // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
1363      //              int flags);
1364      addToFunctionSummaryMap(
1365          "fchownat",
1366          Summary(ArgTypes{IntTy, ConstCharPtrTy, *Uid_tTy, *Gid_tTy, IntTy},
1367                  RetType{IntTy}, NoEvalCall)
1368              .ArgConstraint(
1369                  ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1370              .ArgConstraint(NotNull(ArgNo(1))));
1371
1372      // int chown(const char *path, uid_t owner, gid_t group);
1373      addToFunctionSummaryMap(
1374          "chown", Summary(ArgTypes{ConstCharPtrTy, *Uid_tTy, *Gid_tTy},
1375                           RetType{IntTy}, NoEvalCall)
1376                       .ArgConstraint(NotNull(ArgNo(0))));
1377
1378      // int lchown(const char *path, uid_t owner, gid_t group);
1379      addToFunctionSummaryMap(
1380          "lchown", Summary(ArgTypes{ConstCharPtrTy, *Uid_tTy, *Gid_tTy},
1381                            RetType{IntTy}, NoEvalCall)
1382                        .ArgConstraint(NotNull(ArgNo(0))));
1383
1384      // int fchown(int fildes, uid_t owner, gid_t group);
1385      addToFunctionSummaryMap(
1386          "fchown", Summary(ArgTypes{IntTy, *Uid_tTy, *Gid_tTy}, RetType{IntTy},
1387                            NoEvalCall)
1388                        .ArgConstraint(ArgumentCondition(0, WithinRange,
1389                                                         Range(0, IntMax))));
1390    }
1391
1392    // int rmdir(const char *pathname);
1393    addToFunctionSummaryMap(
1394        "rmdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1395                     .ArgConstraint(NotNull(ArgNo(0))));
1396
1397    // int chdir(const char *path);
1398    addToFunctionSummaryMap(
1399        "chdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1400                     .ArgConstraint(NotNull(ArgNo(0))));
1401
1402    // int link(const char *oldpath, const char *newpath);
1403    addToFunctionSummaryMap("link",
1404                            Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1405                                    RetType{IntTy}, NoEvalCall)
1406                                .ArgConstraint(NotNull(ArgNo(0)))
1407                                .ArgConstraint(NotNull(ArgNo(1))));
1408
1409    // int linkat(int fd1, const char *path1, int fd2, const char *path2,
1410    //            int flag);
1411    addToFunctionSummaryMap(
1412        "linkat",
1413        Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
1414                RetType{IntTy}, NoEvalCall)
1415            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1416            .ArgConstraint(NotNull(ArgNo(1)))
1417            .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
1418            .ArgConstraint(NotNull(ArgNo(3))));
1419
1420    // int unlink(const char *pathname);
1421    addToFunctionSummaryMap(
1422        "unlink", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1423                      .ArgConstraint(NotNull(ArgNo(0))));
1424
1425    // int unlinkat(int fd, const char *path, int flag);
1426    addToFunctionSummaryMap(
1427        "unlinkat",
1428        Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy},
1429                NoEvalCall)
1430            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1431            .ArgConstraint(NotNull(ArgNo(1))));
1432
1433    Optional<QualType> StructStatTy = lookupType("stat", ACtx);
1434    Optional<QualType> StructStatPtrTy, StructStatPtrRestrictTy;
1435    if (StructStatTy) {
1436      StructStatPtrTy = ACtx.getPointerType(*StructStatTy);
1437      StructStatPtrRestrictTy = ACtx.getLangOpts().C99
1438                                    ? ACtx.getRestrictType(*StructStatPtrTy)
1439                                    : *StructStatPtrTy;
1440    }
1441
1442    if (StructStatPtrTy)
1443      // int fstat(int fd, struct stat *statbuf);
1444      addToFunctionSummaryMap(
1445          "fstat",
1446          Summary(ArgTypes{IntTy, *StructStatPtrTy}, RetType{IntTy}, NoEvalCall)
1447              .ArgConstraint(
1448                  ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1449              .ArgConstraint(NotNull(ArgNo(1))));
1450
1451    if (StructStatPtrRestrictTy) {
1452      // int stat(const char *restrict path, struct stat *restrict buf);
1453      addToFunctionSummaryMap(
1454          "stat",
1455          Summary(ArgTypes{ConstCharPtrRestrictTy, *StructStatPtrRestrictTy},
1456                  RetType{IntTy}, NoEvalCall)
1457              .ArgConstraint(NotNull(ArgNo(0)))
1458              .ArgConstraint(NotNull(ArgNo(1))));
1459
1460      // int lstat(const char *restrict path, struct stat *restrict buf);
1461      addToFunctionSummaryMap(
1462          "lstat",
1463          Summary(ArgTypes{ConstCharPtrRestrictTy, *StructStatPtrRestrictTy},
1464                  RetType{IntTy}, NoEvalCall)
1465              .ArgConstraint(NotNull(ArgNo(0)))
1466              .ArgConstraint(NotNull(ArgNo(1))));
1467
1468      // int fstatat(int fd, const char *restrict path,
1469      //             struct stat *restrict buf, int flag);
1470      addToFunctionSummaryMap(
1471          "fstatat", Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy,
1472                                      *StructStatPtrRestrictTy, IntTy},
1473                             RetType{IntTy}, NoEvalCall)
1474                         .ArgConstraint(ArgumentCondition(0, WithinRange,
1475                                                          Range(0, IntMax)))
1476                         .ArgConstraint(NotNull(ArgNo(1)))
1477                         .ArgConstraint(NotNull(ArgNo(2))));
1478    }
1479
1480    if (DirPtrTy) {
1481      // DIR *opendir(const char *name);
1482      addToFunctionSummaryMap("opendir", Summary(ArgTypes{ConstCharPtrTy},
1483                                                 RetType{*DirPtrTy}, NoEvalCall)
1484                                             .ArgConstraint(NotNull(ArgNo(0))));
1485
1486      // DIR *fdopendir(int fd);
1487      addToFunctionSummaryMap(
1488          "fdopendir", Summary(ArgTypes{IntTy}, RetType{*DirPtrTy}, NoEvalCall)
1489                           .ArgConstraint(ArgumentCondition(0, WithinRange,
1490                                                            Range(0, IntMax))));
1491    }
1492
1493    // int isatty(int fildes);
1494    addToFunctionSummaryMap(
1495        "isatty", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1496                      .ArgConstraint(
1497                          ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1498
1499    if (FilePtrTy) {
1500      // FILE *popen(const char *command, const char *type);
1501      addToFunctionSummaryMap("popen",
1502                              Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1503                                      RetType{*FilePtrTy}, NoEvalCall)
1504                                  .ArgConstraint(NotNull(ArgNo(0)))
1505                                  .ArgConstraint(NotNull(ArgNo(1))));
1506
1507      // int pclose(FILE *stream);
1508      addToFunctionSummaryMap(
1509          "pclose", Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall)
1510                        .ArgConstraint(NotNull(ArgNo(0))));
1511    }
1512
1513    // int close(int fildes);
1514    addToFunctionSummaryMap(
1515        "close", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1516                     .ArgConstraint(
1517                         ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1518
1519    // long fpathconf(int fildes, int name);
1520    addToFunctionSummaryMap(
1521        "fpathconf",
1522        Summary(ArgTypes{IntTy, IntTy}, RetType{LongTy}, NoEvalCall)
1523            .ArgConstraint(
1524                ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1525
1526    // long pathconf(const char *path, int name);
1527    addToFunctionSummaryMap("pathconf", Summary(ArgTypes{ConstCharPtrTy, IntTy},
1528                                                RetType{LongTy}, NoEvalCall)
1529                                            .ArgConstraint(NotNull(ArgNo(0))));
1530
1531    if (FilePtrTy)
1532      // FILE *fdopen(int fd, const char *mode);
1533      addToFunctionSummaryMap(
1534          "fdopen", Summary(ArgTypes{IntTy, ConstCharPtrTy},
1535                            RetType{*FilePtrTy}, NoEvalCall)
1536                        .ArgConstraint(
1537                            ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1538                        .ArgConstraint(NotNull(ArgNo(1))));
1539
1540    if (DirPtrTy) {
1541      // void rewinddir(DIR *dir);
1542      addToFunctionSummaryMap(
1543          "rewinddir", Summary(ArgTypes{*DirPtrTy}, RetType{VoidTy}, NoEvalCall)
1544                           .ArgConstraint(NotNull(ArgNo(0))));
1545
1546      // void seekdir(DIR *dirp, long loc);
1547      addToFunctionSummaryMap("seekdir", Summary(ArgTypes{*DirPtrTy, LongTy},
1548                                                 RetType{VoidTy}, NoEvalCall)
1549                                             .ArgConstraint(NotNull(ArgNo(0))));
1550    }
1551
1552    // int rand_r(unsigned int *seedp);
1553    addToFunctionSummaryMap("rand_r", Summary(ArgTypes{UnsignedIntPtrTy},
1554                                              RetType{IntTy}, NoEvalCall)
1555                                          .ArgConstraint(NotNull(ArgNo(0))));
1556
1557    // int strcasecmp(const char *s1, const char *s2);
1558    addToFunctionSummaryMap("strcasecmp",
1559                            Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1560                                    RetType{IntTy}, EvalCallAsPure)
1561                                .ArgConstraint(NotNull(ArgNo(0)))
1562                                .ArgConstraint(NotNull(ArgNo(1))));
1563
1564    // int strncasecmp(const char *s1, const char *s2, size_t n);
1565    addToFunctionSummaryMap(
1566        "strncasecmp", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, SizeTy},
1567                               RetType{IntTy}, EvalCallAsPure)
1568                           .ArgConstraint(NotNull(ArgNo(0)))
1569                           .ArgConstraint(NotNull(ArgNo(1)))
1570                           .ArgConstraint(ArgumentCondition(
1571                               2, WithinRange, Range(0, SizeMax))));
1572
1573    if (FilePtrTy && Off_tTy) {
1574
1575      // int fileno(FILE *stream);
1576      addToFunctionSummaryMap(
1577          "fileno", Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall)
1578                        .ArgConstraint(NotNull(ArgNo(0))));
1579
1580      // int fseeko(FILE *stream, off_t offset, int whence);
1581      addToFunctionSummaryMap("fseeko",
1582                              Summary(ArgTypes{*FilePtrTy, *Off_tTy, IntTy},
1583                                      RetType{IntTy}, NoEvalCall)
1584                                  .ArgConstraint(NotNull(ArgNo(0))));
1585
1586      // off_t ftello(FILE *stream);
1587      addToFunctionSummaryMap(
1588          "ftello", Summary(ArgTypes{*FilePtrTy}, RetType{*Off_tTy}, NoEvalCall)
1589                        .ArgConstraint(NotNull(ArgNo(0))));
1590    }
1591
1592    if (Off_tTy) {
1593      Optional<RangeInt> Off_tMax = BVF.getMaxValue(*Off_tTy).getLimitedValue();
1594
1595      // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
1596      // off_t offset);
1597      addToFunctionSummaryMap(
1598          "mmap",
1599          Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, *Off_tTy},
1600                  RetType{VoidPtrTy}, NoEvalCall)
1601              .ArgConstraint(
1602                  ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1603              .ArgConstraint(
1604                  ArgumentCondition(4, WithinRange, Range(0, *Off_tMax))));
1605    }
1606
1607    Optional<QualType> Off64_tTy = lookupType("off64_t", ACtx);
1608    Optional<RangeInt> Off64_tMax;
1609    if (Off64_tTy) {
1610      Off64_tMax = BVF.getMaxValue(*Off_tTy).getLimitedValue();
1611      // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
1612      // off64_t offset);
1613      addToFunctionSummaryMap(
1614          "mmap64",
1615          Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, *Off64_tTy},
1616                  RetType{VoidPtrTy}, NoEvalCall)
1617              .ArgConstraint(
1618                  ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1619              .ArgConstraint(
1620                  ArgumentCondition(4, WithinRange, Range(0, *Off64_tMax))));
1621    }
1622
1623    // int pipe(int fildes[2]);
1624    addToFunctionSummaryMap(
1625        "pipe", Summary(ArgTypes{IntPtrTy}, RetType{IntTy}, NoEvalCall)
1626                    .ArgConstraint(NotNull(ArgNo(0))));
1627
1628    if (Off_tTy)
1629      // off_t lseek(int fildes, off_t offset, int whence);
1630      addToFunctionSummaryMap(
1631          "lseek", Summary(ArgTypes{IntTy, *Off_tTy, IntTy}, RetType{*Off_tTy},
1632                           NoEvalCall)
1633                       .ArgConstraint(ArgumentCondition(0, WithinRange,
1634                                                        Range(0, IntMax))));
1635
1636    Optional<QualType> Ssize_tTy = lookupType("ssize_t", ACtx);
1637
1638    if (Ssize_tTy) {
1639      // ssize_t readlink(const char *restrict path, char *restrict buf,
1640      //                  size_t bufsize);
1641      addToFunctionSummaryMap(
1642          "readlink",
1643          Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
1644                  RetType{*Ssize_tTy}, NoEvalCall)
1645              .ArgConstraint(NotNull(ArgNo(0)))
1646              .ArgConstraint(NotNull(ArgNo(1)))
1647              .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1648                                        /*BufSize=*/ArgNo(2)))
1649              .ArgConstraint(
1650                  ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
1651
1652      // ssize_t readlinkat(int fd, const char *restrict path,
1653      //                    char *restrict buf, size_t bufsize);
1654      addToFunctionSummaryMap(
1655          "readlinkat", Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy,
1656                                         CharPtrRestrictTy, SizeTy},
1657                                RetType{*Ssize_tTy}, NoEvalCall)
1658                            .ArgConstraint(ArgumentCondition(0, WithinRange,
1659                                                             Range(0, IntMax)))
1660                            .ArgConstraint(NotNull(ArgNo(1)))
1661                            .ArgConstraint(NotNull(ArgNo(2)))
1662                            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
1663                                                      /*BufSize=*/ArgNo(3)))
1664                            .ArgConstraint(ArgumentCondition(
1665                                3, WithinRange, Range(0, SizeMax))));
1666    }
1667
1668    // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
1669    // *newpath);
1670    addToFunctionSummaryMap("renameat", Summary(ArgTypes{IntTy, ConstCharPtrTy,
1671                                                         IntTy, ConstCharPtrTy},
1672                                                RetType{IntTy}, NoEvalCall)
1673                                            .ArgConstraint(NotNull(ArgNo(1)))
1674                                            .ArgConstraint(NotNull(ArgNo(3))));
1675
1676    // char *realpath(const char *restrict file_name,
1677    //                char *restrict resolved_name);
1678    addToFunctionSummaryMap(
1679        "realpath", Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
1680                            RetType{CharPtrTy}, NoEvalCall)
1681                        .ArgConstraint(NotNull(ArgNo(0))));
1682
1683    QualType CharPtrConstPtr = ACtx.getPointerType(CharPtrTy.withConst());
1684
1685    // int execv(const char *path, char *const argv[]);
1686    addToFunctionSummaryMap("execv",
1687                            Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr},
1688                                    RetType{IntTy}, NoEvalCall)
1689                                .ArgConstraint(NotNull(ArgNo(0))));
1690
1691    // int execvp(const char *file, char *const argv[]);
1692    addToFunctionSummaryMap("execvp",
1693                            Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr},
1694                                    RetType{IntTy}, NoEvalCall)
1695                                .ArgConstraint(NotNull(ArgNo(0))));
1696
1697    // int getopt(int argc, char * const argv[], const char *optstring);
1698    addToFunctionSummaryMap(
1699        "getopt",
1700        Summary(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
1701                RetType{IntTy}, NoEvalCall)
1702            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1703            .ArgConstraint(NotNull(ArgNo(1)))
1704            .ArgConstraint(NotNull(ArgNo(2))));
1705  }
1706
1707  // Functions for testing.
1708  if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
1709    addToFunctionSummaryMap(
1710        "__two_constrained_args",
1711        Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure)
1712            .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
1713            .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
1714    addToFunctionSummaryMap(
1715        "__arg_constrained_twice",
1716        Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1717            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
1718            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
1719    addToFunctionSummaryMap(
1720        "__defaultparam",
1721        Summary(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}, EvalCallAsPure)
1722            .ArgConstraint(NotNull(ArgNo(0))));
1723    addToFunctionSummaryMap("__variadic",
1724                            Summary(ArgTypes{VoidPtrTy, ConstCharPtrTy},
1725                                    RetType{IntTy}, EvalCallAsPure)
1726                                .ArgConstraint(NotNull(ArgNo(0)))
1727                                .ArgConstraint(NotNull(ArgNo(1))));
1728    addToFunctionSummaryMap(
1729        "__buf_size_arg_constraint",
1730        Summary(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy},
1731                EvalCallAsPure)
1732            .ArgConstraint(
1733                BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
1734    addToFunctionSummaryMap(
1735        "__buf_size_arg_constraint_mul",
1736        Summary(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy},
1737                EvalCallAsPure)
1738            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
1739                                      /*BufSizeMultiplier=*/ArgNo(2))));
1740  }
1741}
1742
1743void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
1744  auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
1745  Checker->DisplayLoadedSummaries =
1746      mgr.getAnalyzerOptions().getCheckerBooleanOption(
1747          Checker, "DisplayLoadedSummaries");
1748  Checker->ModelPOSIX =
1749      mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX");
1750}
1751
1752bool ento::shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager &mgr) {
1753  return true;
1754}
1755
1756#define REGISTER_CHECKER(name)                                                 \
1757  void ento::register##name(CheckerManager &mgr) {                             \
1758    StdLibraryFunctionsChecker *checker =                                      \
1759        mgr.getChecker<StdLibraryFunctionsChecker>();                          \
1760    checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true;      \
1761    checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] =               \
1762        mgr.getCurrentCheckerName();                                           \
1763  }                                                                            \
1764                                                                               \
1765  bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
1766
1767REGISTER_CHECKER(StdCLibraryFunctionArgsChecker)
1768REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker)
1769