xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp (revision b5fdd533e5c8ed9726bfaaf961272010cbde6c75)
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 //===----------------------------------------------------------------------===//
42 
43 #include "ErrnoModeling.h"
44 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
45 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
46 #include "clang/StaticAnalyzer/Core/Checker.h"
47 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
48 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
49 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
50 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
51 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
52 #include "llvm/ADT/SmallString.h"
53 #include "llvm/ADT/StringExtras.h"
54 
55 #include <optional>
56 #include <string>
57 
58 using namespace clang;
59 using namespace clang::ento;
60 
61 namespace {
62 class StdLibraryFunctionsChecker
63     : public Checker<check::PreCall, check::PostCall, eval::Call> {
64 
65   class Summary;
66 
67   /// Specify how much the analyzer engine should entrust modeling this function
68   /// to us. If he doesn't, he performs additional invalidations.
69   enum InvalidationKind { NoEvalCall, EvalCallAsPure };
70 
71   // The universal integral type to use in value range descriptions.
72   // Unsigned to make sure overflows are well-defined.
73   typedef uint64_t RangeInt;
74 
75   /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
76   /// a non-negative integer, which less than 5 and not equal to 2. For
77   /// `ComparesToArgument', holds information about how exactly to compare to
78   /// the argument.
79   typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
80 
81   /// A reference to an argument or return value by its number.
82   /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
83   /// obviously uint32_t should be enough for all practical purposes.
84   typedef uint32_t ArgNo;
85   static const ArgNo Ret;
86 
87   /// Returns the string representation of an argument index.
88   /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
89   static SmallString<8> getArgDesc(ArgNo);
90 
91   class ValueConstraint;
92 
93   // Pointer to the ValueConstraint. We need a copyable, polymorphic and
94   // default initialize able type (vector needs that). A raw pointer was good,
95   // however, we cannot default initialize that. unique_ptr makes the Summary
96   // class non-copyable, therefore not an option. Releasing the copyability
97   // requirement would render the initialization of the Summary map infeasible.
98   using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
99 
100   /// Polymorphic base class that represents a constraint on a given argument
101   /// (or return value) of a function. Derived classes implement different kind
102   /// of constraints, e.g range constraints or correlation between two
103   /// arguments.
104   class ValueConstraint {
105   public:
106     ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
107     virtual ~ValueConstraint() {}
108     /// Apply the effects of the constraint on the given program state. If null
109     /// is returned then the constraint is not feasible.
110     virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
111                                   const Summary &Summary,
112                                   CheckerContext &C) const = 0;
113     virtual ValueConstraintPtr negate() const {
114       llvm_unreachable("Not implemented");
115     };
116 
117     // Check whether the constraint is malformed or not. It is malformed if the
118     // specified argument has a mismatch with the given FunctionDecl (e.g. the
119     // arg number is out-of-range of the function's argument list).
120     bool checkValidity(const FunctionDecl *FD) const {
121       const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
122       assert(ValidArg && "Arg out of range!");
123       if (!ValidArg)
124         return false;
125       // Subclasses may further refine the validation.
126       return checkSpecificValidity(FD);
127     }
128     ArgNo getArgNo() const { return ArgN; }
129 
130     // Return those arguments that should be tracked when we report a bug. By
131     // default it is the argument that is constrained, however, in some special
132     // cases we need to track other arguments as well. E.g. a buffer size might
133     // be encoded in another argument.
134     virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
135 
136     virtual StringRef getName() const = 0;
137 
138     // Represents that in which context do we require a description of the
139     // constraint.
140     enum class DescriptionKind {
141       // The constraint is violated.
142       Violation,
143       // We assume that the constraint is satisfied.
144       Assumption
145     };
146 
147     // Give a description that explains the constraint to the user. Used when
148     // the bug is reported.
149     virtual std::string describe(DescriptionKind DK, ProgramStateRef State,
150                                  const Summary &Summary) const {
151       // There are some descendant classes that are not used as argument
152       // constraints, e.g. ComparisonConstraint. In that case we can safely
153       // ignore the implementation of this function.
154       llvm_unreachable("Not implemented");
155     }
156 
157   protected:
158     ArgNo ArgN; // Argument to which we apply the constraint.
159 
160     /// Do polymorphic validation check on the constraint.
161     virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
162       return true;
163     }
164   };
165 
166   /// Given a range, should the argument stay inside or outside this range?
167   enum RangeKind { OutOfRange, WithinRange };
168 
169   /// Encapsulates a range on a single symbol.
170   class RangeConstraint : public ValueConstraint {
171     RangeKind Kind;
172     // A range is formed as a set of intervals (sub-ranges).
173     // E.g. {['A', 'Z'], ['a', 'z']}
174     //
175     // The default constructed RangeConstraint has an empty range set, applying
176     // such constraint does not involve any assumptions, thus the State remains
177     // unchanged. This is meaningful, if the range is dependent on a looked up
178     // type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
179     // is default initialized to be empty.
180     IntRangeVector Ranges;
181 
182   public:
183     StringRef getName() const override { return "Range"; }
184     RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
185         : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
186 
187     std::string describe(DescriptionKind DK, ProgramStateRef State,
188                          const Summary &Summary) const override;
189 
190     const IntRangeVector &getRanges() const { return Ranges; }
191 
192   private:
193     ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
194                                       const CallEvent &Call,
195                                       const Summary &Summary) const;
196     ProgramStateRef applyAsWithinRange(ProgramStateRef State,
197                                        const CallEvent &Call,
198                                        const Summary &Summary) const;
199 
200   public:
201     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
202                           const Summary &Summary,
203                           CheckerContext &C) const override {
204       switch (Kind) {
205       case OutOfRange:
206         return applyAsOutOfRange(State, Call, Summary);
207       case WithinRange:
208         return applyAsWithinRange(State, Call, Summary);
209       }
210       llvm_unreachable("Unknown range kind!");
211     }
212 
213     ValueConstraintPtr negate() const override {
214       RangeConstraint Tmp(*this);
215       switch (Kind) {
216       case OutOfRange:
217         Tmp.Kind = WithinRange;
218         break;
219       case WithinRange:
220         Tmp.Kind = OutOfRange;
221         break;
222       }
223       return std::make_shared<RangeConstraint>(Tmp);
224     }
225 
226     bool checkSpecificValidity(const FunctionDecl *FD) const override {
227       const bool ValidArg =
228           getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
229       assert(ValidArg &&
230              "This constraint should be applied on an integral type");
231       return ValidArg;
232     }
233   };
234 
235   class ComparisonConstraint : public ValueConstraint {
236     BinaryOperator::Opcode Opcode;
237     ArgNo OtherArgN;
238 
239   public:
240     StringRef getName() const override { return "Comparison"; };
241     ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
242                          ArgNo OtherArgN)
243         : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
244     ArgNo getOtherArgNo() const { return OtherArgN; }
245     BinaryOperator::Opcode getOpcode() const { return Opcode; }
246     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
247                           const Summary &Summary,
248                           CheckerContext &C) const override;
249   };
250 
251   class NotNullConstraint : public ValueConstraint {
252     using ValueConstraint::ValueConstraint;
253     // This variable has a role when we negate the constraint.
254     bool CannotBeNull = true;
255 
256   public:
257     std::string describe(DescriptionKind DK, ProgramStateRef State,
258                          const Summary &Summary) const override;
259     StringRef getName() const override { return "NonNull"; }
260     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
261                           const Summary &Summary,
262                           CheckerContext &C) const override {
263       SVal V = getArgSVal(Call, getArgNo());
264       if (V.isUndef())
265         return State;
266 
267       DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
268       if (!isa<Loc>(L))
269         return State;
270 
271       return State->assume(L, CannotBeNull);
272     }
273 
274     ValueConstraintPtr negate() const override {
275       NotNullConstraint Tmp(*this);
276       Tmp.CannotBeNull = !this->CannotBeNull;
277       return std::make_shared<NotNullConstraint>(Tmp);
278     }
279 
280     bool checkSpecificValidity(const FunctionDecl *FD) const override {
281       const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
282       assert(ValidArg &&
283              "This constraint should be applied only on a pointer type");
284       return ValidArg;
285     }
286   };
287 
288   // Represents a buffer argument with an additional size constraint. The
289   // constraint may be a concrete value, or a symbolic value in an argument.
290   // Example 1. Concrete value as the minimum buffer size.
291   //   char *asctime_r(const struct tm *restrict tm, char *restrict buf);
292   //   // `buf` size must be at least 26 bytes according the POSIX standard.
293   // Example 2. Argument as a buffer size.
294   //   ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
295   // Example 3. The size is computed as a multiplication of other args.
296   //   size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
297   //   // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
298   class BufferSizeConstraint : public ValueConstraint {
299     // The concrete value which is the minimum size for the buffer.
300     std::optional<llvm::APSInt> ConcreteSize;
301     // The argument which holds the size of the buffer.
302     std::optional<ArgNo> SizeArgN;
303     // The argument which is a multiplier to size. This is set in case of
304     // `fread` like functions where the size is computed as a multiplication of
305     // two arguments.
306     std::optional<ArgNo> SizeMultiplierArgN;
307     // The operator we use in apply. This is negated in negate().
308     BinaryOperator::Opcode Op = BO_LE;
309 
310   public:
311     StringRef getName() const override { return "BufferSize"; }
312     BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
313         : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
314     BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
315         : ValueConstraint(Buffer), SizeArgN(BufSize) {}
316     BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
317         : ValueConstraint(Buffer), SizeArgN(BufSize),
318           SizeMultiplierArgN(BufSizeMultiplier) {}
319 
320     std::vector<ArgNo> getArgsToTrack() const override {
321       std::vector<ArgNo> Result{ArgN};
322       if (SizeArgN)
323         Result.push_back(*SizeArgN);
324       if (SizeMultiplierArgN)
325         Result.push_back(*SizeMultiplierArgN);
326       return Result;
327     }
328 
329     std::string describe(DescriptionKind DK, ProgramStateRef State,
330                          const Summary &Summary) const override;
331 
332     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
333                           const Summary &Summary,
334                           CheckerContext &C) const override {
335       SValBuilder &SvalBuilder = C.getSValBuilder();
336       // The buffer argument.
337       SVal BufV = getArgSVal(Call, getArgNo());
338 
339       // Get the size constraint.
340       const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
341         if (ConcreteSize) {
342           return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
343         }
344         assert(SizeArgN && "The constraint must be either a concrete value or "
345                            "encoded in an argument.");
346         // The size argument.
347         SVal SizeV = getArgSVal(Call, *SizeArgN);
348         // Multiply with another argument if given.
349         if (SizeMultiplierArgN) {
350           SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
351           SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
352                                         Summary.getArgType(*SizeArgN));
353         }
354         return SizeV;
355       }();
356 
357       // The dynamic size of the buffer argument, got from the analyzer engine.
358       SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
359 
360       SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
361                                             SvalBuilder.getContext().BoolTy);
362       if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
363         return State->assume(*F, true);
364 
365       // We can get here only if the size argument or the dynamic size is
366       // undefined. But the dynamic size should never be undefined, only
367       // unknown. So, here, the size of the argument is undefined, i.e. we
368       // cannot apply the constraint. Actually, other checkers like
369       // CallAndMessage should catch this situation earlier, because we call a
370       // function with an uninitialized argument.
371       llvm_unreachable("Size argument or the dynamic size is Undefined");
372     }
373 
374     ValueConstraintPtr negate() const override {
375       BufferSizeConstraint Tmp(*this);
376       Tmp.Op = BinaryOperator::negateComparisonOp(Op);
377       return std::make_shared<BufferSizeConstraint>(Tmp);
378     }
379 
380     bool checkSpecificValidity(const FunctionDecl *FD) const override {
381       const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
382       assert(ValidArg &&
383              "This constraint should be applied only on a pointer type");
384       return ValidArg;
385     }
386   };
387 
388   /// The complete list of constraints that defines a single branch.
389   using ConstraintSet = std::vector<ValueConstraintPtr>;
390 
391   /// Define how a function affects the system variable 'errno'.
392   /// This works together with the \c ErrnoModeling and \c ErrnoChecker classes.
393   /// Currently 3 use cases exist: success, failure, irrelevant.
394   /// In the future the failure case can be customized to set \c errno to a
395   /// more specific constraint (for example > 0), or new case can be added
396   /// for functions which require check of \c errno in both success and failure
397   /// case.
398   class ErrnoConstraintBase {
399   public:
400     /// Apply specific state changes related to the errno variable.
401     virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
402                                   const Summary &Summary,
403                                   CheckerContext &C) const = 0;
404     /// Get a NoteTag about the changes made to 'errno' and the possible bug.
405     /// It may return \c nullptr (if no bug report from \c ErrnoChecker is
406     /// expected).
407     virtual const NoteTag *describe(CheckerContext &C,
408                                     StringRef FunctionName) const {
409       return nullptr;
410     }
411 
412     virtual ~ErrnoConstraintBase() {}
413 
414   protected:
415     ErrnoConstraintBase() = default;
416 
417     /// This is used for conjure symbol for errno to differentiate from the
418     /// original call expression (same expression is used for the errno symbol).
419     static int Tag;
420   };
421 
422   /// Set errno constraint at failure cases of standard functions.
423   /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
424   /// by the program. \c ErrnoChecker does not emit a bug report after such a
425   /// function call.
426   class FailureErrnoConstraint : public ErrnoConstraintBase {
427   public:
428     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
429                           const Summary &Summary,
430                           CheckerContext &C) const override {
431       SValBuilder &SVB = C.getSValBuilder();
432       NonLoc ErrnoSVal =
433           SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
434                                C.getLocationContext(), C.getASTContext().IntTy,
435                                C.blockCount())
436               .castAs<NonLoc>();
437       return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
438     }
439   };
440 
441   /// Set errno constraint at success cases of standard functions.
442   /// Success case: 'errno' is not allowed to be used.
443   /// \c ErrnoChecker can emit bug report after such a function call if errno
444   /// is used.
445   class SuccessErrnoConstraint : public ErrnoConstraintBase {
446   public:
447     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
448                           const Summary &Summary,
449                           CheckerContext &C) const override {
450       return errno_modeling::setErrnoForStdSuccess(State, C);
451     }
452 
453     const NoteTag *describe(CheckerContext &C,
454                             StringRef FunctionName) const override {
455       return errno_modeling::getNoteTagForStdSuccess(C, FunctionName);
456     }
457   };
458 
459   /// Set errno constraints if use of 'errno' is irrelevant to the
460   /// modeled function or modeling is not possible.
461   class NoErrnoConstraint : public ErrnoConstraintBase {
462   public:
463     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
464                           const Summary &Summary,
465                           CheckerContext &C) const override {
466       return errno_modeling::setErrnoState(State, errno_modeling::Irrelevant);
467     }
468   };
469 
470   /// A single branch of a function summary.
471   ///
472   /// A branch is defined by a series of constraints - "assumptions" -
473   /// that together form a single possible outcome of invoking the function.
474   /// When static analyzer considers a branch, it tries to introduce
475   /// a child node in the Exploded Graph. The child node has to include
476   /// constraints that define the branch. If the constraints contradict
477   /// existing constraints in the state, the node is not created and the branch
478   /// is dropped; otherwise it's queued for future exploration.
479   /// The branch is accompanied by a note text that may be displayed
480   /// to the user when a bug is found on a path that takes this branch.
481   ///
482   /// For example, consider the branches in `isalpha(x)`:
483   ///   Branch 1)
484   ///     x is in range ['A', 'Z'] or in ['a', 'z']
485   ///     then the return value is not 0. (I.e. out-of-range [0, 0])
486   ///     and the note may say "Assuming the character is alphabetical"
487   ///   Branch 2)
488   ///     x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
489   ///     then the return value is 0
490   ///     and the note may say "Assuming the character is non-alphabetical".
491   class SummaryCase {
492     ConstraintSet Constraints;
493     const ErrnoConstraintBase &ErrnoConstraint;
494     StringRef Note;
495 
496   public:
497     SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,
498                 StringRef Note)
499         : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),
500           Note(Note) {}
501 
502     SummaryCase(const ConstraintSet &Constraints,
503                 const ErrnoConstraintBase &ErrnoC, StringRef Note)
504         : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}
505 
506     const ConstraintSet &getConstraints() const { return Constraints; }
507     const ErrnoConstraintBase &getErrnoConstraint() const {
508       return ErrnoConstraint;
509     }
510     StringRef getNote() const { return Note; }
511   };
512 
513   using ArgTypes = std::vector<Optional<QualType>>;
514   using RetType = Optional<QualType>;
515 
516   // A placeholder type, we use it whenever we do not care about the concrete
517   // type in a Signature.
518   const QualType Irrelevant{};
519   bool static isIrrelevant(QualType T) { return T.isNull(); }
520 
521   // The signature of a function we want to describe with a summary. This is a
522   // concessive signature, meaning there may be irrelevant types in the
523   // signature which we do not check against a function with concrete types.
524   // All types in the spec need to be canonical.
525   class Signature {
526     using ArgQualTypes = std::vector<QualType>;
527     ArgQualTypes ArgTys;
528     QualType RetTy;
529     // True if any component type is not found by lookup.
530     bool Invalid = false;
531 
532   public:
533     // Construct a signature from optional types. If any of the optional types
534     // are not set then the signature will be invalid.
535     Signature(ArgTypes ArgTys, RetType RetTy) {
536       for (Optional<QualType> Arg : ArgTys) {
537         if (!Arg) {
538           Invalid = true;
539           return;
540         } else {
541           assertArgTypeSuitableForSignature(*Arg);
542           this->ArgTys.push_back(*Arg);
543         }
544       }
545       if (!RetTy) {
546         Invalid = true;
547         return;
548       } else {
549         assertRetTypeSuitableForSignature(*RetTy);
550         this->RetTy = *RetTy;
551       }
552     }
553 
554     bool isInvalid() const { return Invalid; }
555     bool matches(const FunctionDecl *FD) const;
556 
557   private:
558     static void assertArgTypeSuitableForSignature(QualType T) {
559       assert((T.isNull() || !T->isVoidType()) &&
560              "We should have no void types in the spec");
561       assert((T.isNull() || T.isCanonical()) &&
562              "We should only have canonical types in the spec");
563     }
564     static void assertRetTypeSuitableForSignature(QualType T) {
565       assert((T.isNull() || T.isCanonical()) &&
566              "We should only have canonical types in the spec");
567     }
568   };
569 
570   static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
571     assert(FD && "Function must be set");
572     QualType T = (ArgN == Ret)
573                      ? FD->getReturnType().getCanonicalType()
574                      : FD->getParamDecl(ArgN)->getType().getCanonicalType();
575     return T;
576   }
577 
578   using SummaryCases = std::vector<SummaryCase>;
579 
580   /// A summary includes information about
581   ///   * function prototype (signature)
582   ///   * approach to invalidation,
583   ///   * a list of branches - so, a list of list of ranges,
584   ///   * a list of argument constraints, that must be true on every branch.
585   ///     If these constraints are not satisfied that means a fatal error
586   ///     usually resulting in undefined behaviour.
587   ///
588   /// Application of a summary:
589   ///   The signature and argument constraints together contain information
590   ///   about which functions are handled by the summary. The signature can use
591   ///   "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
592   ///   a signature means that type is not compared to the type of the parameter
593   ///   in the found FunctionDecl. Argument constraints may specify additional
594   ///   rules for the given parameter's type, those rules are checked once the
595   ///   signature is matched.
596   class Summary {
597     const InvalidationKind InvalidationKd;
598     SummaryCases Cases;
599     ConstraintSet ArgConstraints;
600 
601     // The function to which the summary applies. This is set after lookup and
602     // match to the signature.
603     const FunctionDecl *FD = nullptr;
604 
605   public:
606     Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
607 
608     Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,
609                   StringRef Note = "") {
610       Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));
611       return *this;
612     }
613     Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,
614                   StringRef Note = "") {
615       Cases.push_back(SummaryCase(CS, ErrnoC, Note));
616       return *this;
617     }
618     Summary &ArgConstraint(ValueConstraintPtr VC) {
619       assert(VC->getArgNo() != Ret &&
620              "Arg constraint should not refer to the return value");
621       ArgConstraints.push_back(VC);
622       return *this;
623     }
624 
625     InvalidationKind getInvalidationKd() const { return InvalidationKd; }
626     const SummaryCases &getCases() const { return Cases; }
627     const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
628 
629     QualType getArgType(ArgNo ArgN) const {
630       return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
631     }
632 
633     // Returns true if the summary should be applied to the given function.
634     // And if yes then store the function declaration.
635     bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
636       bool Result = Sign.matches(FD) && validateByConstraints(FD);
637       if (Result) {
638         assert(!this->FD && "FD must not be set more than once");
639         this->FD = FD;
640       }
641       return Result;
642     }
643 
644   private:
645     // Once we know the exact type of the function then do validation check on
646     // all the given constraints.
647     bool validateByConstraints(const FunctionDecl *FD) const {
648       for (const SummaryCase &Case : Cases)
649         for (const ValueConstraintPtr &Constraint : Case.getConstraints())
650           if (!Constraint->checkValidity(FD))
651             return false;
652       for (const ValueConstraintPtr &Constraint : ArgConstraints)
653         if (!Constraint->checkValidity(FD))
654           return false;
655       return true;
656     }
657   };
658 
659   // The map of all functions supported by the checker. It is initialized
660   // lazily, and it doesn't change after initialization.
661   using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
662   mutable FunctionSummaryMapType FunctionSummaryMap;
663 
664   mutable std::unique_ptr<BugType> BT_InvalidArg;
665   mutable bool SummariesInitialized = false;
666 
667   static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
668     return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
669   }
670 
671 public:
672   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
673   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
674   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
675 
676   enum CheckKind {
677     CK_StdCLibraryFunctionArgsChecker,
678     CK_StdCLibraryFunctionsTesterChecker,
679     CK_NumCheckKinds
680   };
681   bool ChecksEnabled[CK_NumCheckKinds] = {false};
682   CheckerNameRef CheckNames[CK_NumCheckKinds];
683 
684   bool DisplayLoadedSummaries = false;
685   bool ModelPOSIX = false;
686   bool ShouldAssumeControlledEnvironment = false;
687 
688 private:
689   Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
690                                         CheckerContext &C) const;
691   Optional<Summary> findFunctionSummary(const CallEvent &Call,
692                                         CheckerContext &C) const;
693 
694   void initFunctionSummaries(CheckerContext &C) const;
695 
696   void reportBug(const CallEvent &Call, ExplodedNode *N,
697                  const ValueConstraint *VC, const Summary &Summary,
698                  CheckerContext &C) const {
699     if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
700       return;
701     std::string Msg =
702         (Twine("Function argument constraint is not satisfied, constraint: ") +
703          VC->getName().data())
704             .str();
705     if (!BT_InvalidArg)
706       BT_InvalidArg = std::make_unique<BugType>(
707           CheckNames[CK_StdCLibraryFunctionArgsChecker],
708           "Unsatisfied argument constraints", categories::LogicError);
709     auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
710 
711     for (ArgNo ArgN : VC->getArgsToTrack())
712       bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
713 
714     // Highlight the range of the argument that was violated.
715     R->addRange(Call.getArgSourceRange(VC->getArgNo()));
716 
717     // Describe the argument constraint violation in a note.
718     std::string Descr = VC->describe(
719         ValueConstraint::DescriptionKind::Violation, C.getState(), Summary);
720     // Capitalize the first letter b/c we want a full sentence.
721     Descr[0] = toupper(Descr[0]);
722     R->addNote(Descr, R->getLocation(), Call.getArgSourceRange(VC->getArgNo()));
723 
724     C.emitReport(std::move(R));
725   }
726 
727   /// These are the errno constraints that can be passed to summary cases.
728   /// One of these should fit for a single summary case.
729   /// Usually if a failure return value exists for function, that function
730   /// needs different cases for success and failure with different errno
731   /// constraints (and different return value constraints).
732   const NoErrnoConstraint ErrnoIrrelevant{};
733   const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
734   const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
735 };
736 
737 int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
738 
739 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
740     std::numeric_limits<ArgNo>::max();
741 
742 } // end of anonymous namespace
743 
744 static BasicValueFactory &getBVF(ProgramStateRef State) {
745   ProgramStateManager &Mgr = State->getStateManager();
746   SValBuilder &SVB = Mgr.getSValBuilder();
747   return SVB.getBasicValueFactory();
748 }
749 
750 std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
751     DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
752   SmallString<48> Result;
753   const auto Violation = ValueConstraint::DescriptionKind::Violation;
754   Result += "the ";
755   Result += getArgDesc(ArgN);
756   Result += DK == Violation ? " should not be NULL" : " is not NULL";
757   return Result.c_str();
758 }
759 
760 std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
761     DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
762 
763   BasicValueFactory &BVF = getBVF(State);
764 
765   QualType T = Summary.getArgType(getArgNo());
766   SmallString<48> Result;
767   const auto Violation = ValueConstraint::DescriptionKind::Violation;
768   Result += "the ";
769   Result += getArgDesc(ArgN);
770   Result += DK == Violation ? " should be " : " is ";
771 
772   // Range kind as a string.
773   Kind == OutOfRange ? Result += "out of" : Result += "within";
774 
775   // Get the range values as a string.
776   Result += " the range ";
777   if (Ranges.size() > 1)
778     Result += "[";
779   unsigned I = Ranges.size();
780   for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
781     Result += "[";
782     const llvm::APSInt &Min = BVF.getValue(R.first, T);
783     const llvm::APSInt &Max = BVF.getValue(R.second, T);
784     Min.toString(Result);
785     Result += ", ";
786     Max.toString(Result);
787     Result += "]";
788     if (--I > 0)
789       Result += ", ";
790   }
791   if (Ranges.size() > 1)
792     Result += "]";
793 
794   return Result.c_str();
795 }
796 
797 SmallString<8>
798 StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) {
799   SmallString<8> Result;
800   Result += std::to_string(ArgN + 1);
801   Result += llvm::getOrdinalSuffix(ArgN + 1);
802   Result += " argument";
803   return Result;
804 }
805 
806 std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
807     DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
808   SmallString<96> Result;
809   const auto Violation = ValueConstraint::DescriptionKind::Violation;
810   Result += "the size of the ";
811   Result += getArgDesc(ArgN);
812   Result += DK == Violation ? " should be " : " is ";
813   Result += "equal to or greater than the value of ";
814   if (ConcreteSize) {
815     ConcreteSize->toString(Result);
816   } else if (SizeArgN) {
817     Result += "the ";
818     Result += getArgDesc(*SizeArgN);
819     if (SizeMultiplierArgN) {
820       Result += " times the ";
821       Result += getArgDesc(*SizeMultiplierArgN);
822     }
823   }
824   return Result.c_str();
825 }
826 
827 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange(
828     ProgramStateRef State, const CallEvent &Call,
829     const Summary &Summary) const {
830   if (Ranges.empty())
831     return State;
832 
833   ProgramStateManager &Mgr = State->getStateManager();
834   SValBuilder &SVB = Mgr.getSValBuilder();
835   BasicValueFactory &BVF = SVB.getBasicValueFactory();
836   ConstraintManager &CM = Mgr.getConstraintManager();
837   QualType T = Summary.getArgType(getArgNo());
838   SVal V = getArgSVal(Call, getArgNo());
839 
840   if (auto N = V.getAs<NonLoc>()) {
841     const IntRangeVector &R = getRanges();
842     size_t E = R.size();
843     for (size_t I = 0; I != E; ++I) {
844       const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
845       const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
846       assert(Min <= Max);
847       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
848       if (!State)
849         break;
850     }
851   }
852 
853   return State;
854 }
855 
856 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange(
857     ProgramStateRef State, const CallEvent &Call,
858     const Summary &Summary) const {
859   if (Ranges.empty())
860     return State;
861 
862   ProgramStateManager &Mgr = State->getStateManager();
863   SValBuilder &SVB = Mgr.getSValBuilder();
864   BasicValueFactory &BVF = SVB.getBasicValueFactory();
865   ConstraintManager &CM = Mgr.getConstraintManager();
866   QualType T = Summary.getArgType(getArgNo());
867   SVal V = getArgSVal(Call, getArgNo());
868 
869   // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
870   // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
871   // and then cut away all holes in R one by one.
872   //
873   // E.g. consider a range list R as [A, B] and [C, D]
874   // -------+--------+------------------+------------+----------->
875   //        A        B                  C            D
876   // Then we assume that the value is not in [-inf, A - 1],
877   // then not in [D + 1, +inf], then not in [B + 1, C - 1]
878   if (auto N = V.getAs<NonLoc>()) {
879     const IntRangeVector &R = getRanges();
880     size_t E = R.size();
881 
882     const llvm::APSInt &MinusInf = BVF.getMinValue(T);
883     const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
884 
885     const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
886     if (Left != PlusInf) {
887       assert(MinusInf <= Left);
888       State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
889       if (!State)
890         return nullptr;
891     }
892 
893     const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
894     if (Right != MinusInf) {
895       assert(Right <= PlusInf);
896       State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
897       if (!State)
898         return nullptr;
899     }
900 
901     for (size_t I = 1; I != E; ++I) {
902       const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
903       const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
904       if (Min <= Max) {
905         State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
906         if (!State)
907           return nullptr;
908       }
909     }
910   }
911 
912   return State;
913 }
914 
915 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
916     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
917     CheckerContext &C) const {
918 
919   ProgramStateManager &Mgr = State->getStateManager();
920   SValBuilder &SVB = Mgr.getSValBuilder();
921   QualType CondT = SVB.getConditionType();
922   QualType T = Summary.getArgType(getArgNo());
923   SVal V = getArgSVal(Call, getArgNo());
924 
925   BinaryOperator::Opcode Op = getOpcode();
926   ArgNo OtherArg = getOtherArgNo();
927   SVal OtherV = getArgSVal(Call, OtherArg);
928   QualType OtherT = Summary.getArgType(OtherArg);
929   // Note: we avoid integral promotion for comparison.
930   OtherV = SVB.evalCast(OtherV, T, OtherT);
931   if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
932                        .getAs<DefinedOrUnknownSVal>())
933     State = State->assume(*CompV, true);
934   return State;
935 }
936 
937 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
938                                               CheckerContext &C) const {
939   Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
940   if (!FoundSummary)
941     return;
942 
943   const Summary &Summary = *FoundSummary;
944   ProgramStateRef State = C.getState();
945 
946   ProgramStateRef NewState = State;
947   ExplodedNode *NewNode = C.getPredecessor();
948   for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
949     ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
950     ProgramStateRef FailureSt =
951         Constraint->negate()->apply(NewState, Call, Summary, C);
952     // The argument constraint is not satisfied.
953     if (FailureSt && !SuccessSt) {
954       if (ExplodedNode *N = C.generateErrorNode(NewState))
955         reportBug(Call, N, Constraint.get(), Summary, C);
956       break;
957     }
958     // We will apply the constraint even if we cannot reason about the
959     // argument. This means both SuccessSt and FailureSt can be true. If we
960     // weren't applying the constraint that would mean that symbolic
961     // execution continues on a code whose behaviour is undefined.
962     assert(SuccessSt);
963     NewState = SuccessSt;
964     if (NewState != State) {
965       SmallString<64> Msg;
966       Msg += "Assuming ";
967       Msg += Constraint->describe(ValueConstraint::DescriptionKind::Assumption,
968                                   NewState, Summary);
969       const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
970       NewNode = C.addTransition(
971           NewState, NewNode,
972           C.getNoteTag([Msg = std::move(Msg), ArgSVal](
973                            PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
974             if (BR.isInteresting(ArgSVal))
975               OS << Msg;
976           }));
977     }
978   }
979 }
980 
981 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
982                                                CheckerContext &C) const {
983   Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
984   if (!FoundSummary)
985     return;
986 
987   // Now apply the constraints.
988   const Summary &Summary = *FoundSummary;
989   ProgramStateRef State = C.getState();
990   const ExplodedNode *Node = C.getPredecessor();
991 
992   // Apply case/branch specifications.
993   for (const SummaryCase &Case : Summary.getCases()) {
994     ProgramStateRef NewState = State;
995     for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
996       NewState = Constraint->apply(NewState, Call, Summary, C);
997       if (!NewState)
998         break;
999     }
1000 
1001     if (NewState)
1002       NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
1003 
1004     if (NewState && NewState != State) {
1005       if (Case.getNote().empty()) {
1006         const NoteTag *NT = nullptr;
1007         if (const auto *D = dyn_cast_or_null<FunctionDecl>(Call.getDecl()))
1008           NT = Case.getErrnoConstraint().describe(C, D->getNameAsString());
1009         C.addTransition(NewState, NT);
1010       } else {
1011         StringRef Note = Case.getNote();
1012         const NoteTag *Tag = C.getNoteTag(
1013             // Sorry couldn't help myself.
1014             [Node, Note]() -> std::string {
1015               // Don't emit "Assuming..." note when we ended up
1016               // knowing in advance which branch is taken.
1017               return (Node->succ_size() > 1) ? Note.str() : "";
1018             },
1019             /*IsPrunable=*/true);
1020         C.addTransition(NewState, Tag);
1021       }
1022     }
1023   }
1024 }
1025 
1026 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
1027                                           CheckerContext &C) const {
1028   Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1029   if (!FoundSummary)
1030     return false;
1031 
1032   const Summary &Summary = *FoundSummary;
1033   switch (Summary.getInvalidationKd()) {
1034   case EvalCallAsPure: {
1035     ProgramStateRef State = C.getState();
1036     const LocationContext *LC = C.getLocationContext();
1037     const auto *CE = cast<CallExpr>(Call.getOriginExpr());
1038     SVal V = C.getSValBuilder().conjureSymbolVal(
1039         CE, LC, CE->getType().getCanonicalType(), C.blockCount());
1040     State = State->BindExpr(CE, LC, V);
1041 
1042     C.addTransition(State);
1043 
1044     return true;
1045   }
1046   case NoEvalCall:
1047     // Summary tells us to avoid performing eval::Call. The function is possibly
1048     // evaluated by another checker, or evaluated conservatively.
1049     return false;
1050   }
1051   llvm_unreachable("Unknown invalidation kind!");
1052 }
1053 
1054 bool StdLibraryFunctionsChecker::Signature::matches(
1055     const FunctionDecl *FD) const {
1056   assert(!isInvalid());
1057   // Check the number of arguments.
1058   if (FD->param_size() != ArgTys.size())
1059     return false;
1060 
1061   // The "restrict" keyword is illegal in C++, however, many libc
1062   // implementations use the "__restrict" compiler intrinsic in functions
1063   // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1064   // even in C++.
1065   // In case of any non-C99 languages, we don't want to match based on the
1066   // restrict qualifier because we cannot know if the given libc implementation
1067   // qualifies the paramter type or not.
1068   auto RemoveRestrict = [&FD](QualType T) {
1069     if (!FD->getASTContext().getLangOpts().C99)
1070       T.removeLocalRestrict();
1071     return T;
1072   };
1073 
1074   // Check the return type.
1075   if (!isIrrelevant(RetTy)) {
1076     QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1077     if (RetTy != FDRetTy)
1078       return false;
1079   }
1080 
1081   // Check the argument types.
1082   for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
1083     QualType ArgTy = ArgTys[I];
1084     if (isIrrelevant(ArgTy))
1085       continue;
1086     QualType FDArgTy =
1087         RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType());
1088     if (ArgTy != FDArgTy)
1089       return false;
1090   }
1091 
1092   return true;
1093 }
1094 
1095 Optional<StdLibraryFunctionsChecker::Summary>
1096 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1097                                                 CheckerContext &C) const {
1098   if (!FD)
1099     return std::nullopt;
1100 
1101   initFunctionSummaries(C);
1102 
1103   auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
1104   if (FSMI == FunctionSummaryMap.end())
1105     return std::nullopt;
1106   return FSMI->second;
1107 }
1108 
1109 Optional<StdLibraryFunctionsChecker::Summary>
1110 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
1111                                                 CheckerContext &C) const {
1112   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1113   if (!FD)
1114     return std::nullopt;
1115   return findFunctionSummary(FD, C);
1116 }
1117 
1118 void StdLibraryFunctionsChecker::initFunctionSummaries(
1119     CheckerContext &C) const {
1120   if (SummariesInitialized)
1121     return;
1122 
1123   SValBuilder &SVB = C.getSValBuilder();
1124   BasicValueFactory &BVF = SVB.getBasicValueFactory();
1125   const ASTContext &ACtx = BVF.getContext();
1126 
1127   // Helper class to lookup a type by its name.
1128   class LookupType {
1129     const ASTContext &ACtx;
1130 
1131   public:
1132     LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1133 
1134     // Find the type. If not found then the optional is not set.
1135     llvm::Optional<QualType> operator()(StringRef Name) {
1136       IdentifierInfo &II = ACtx.Idents.get(Name);
1137       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1138       if (LookupRes.empty())
1139         return std::nullopt;
1140 
1141       // Prioritze typedef declarations.
1142       // This is needed in case of C struct typedefs. E.g.:
1143       //   typedef struct FILE FILE;
1144       // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1145       // and we have a TypedefDecl with the name 'FILE'.
1146       for (Decl *D : LookupRes)
1147         if (auto *TD = dyn_cast<TypedefNameDecl>(D))
1148           return ACtx.getTypeDeclType(TD).getCanonicalType();
1149 
1150       // Find the first TypeDecl.
1151       // There maybe cases when a function has the same name as a struct.
1152       // E.g. in POSIX: `struct stat` and the function `stat()`:
1153       //   int stat(const char *restrict path, struct stat *restrict buf);
1154       for (Decl *D : LookupRes)
1155         if (auto *TD = dyn_cast<TypeDecl>(D))
1156           return ACtx.getTypeDeclType(TD).getCanonicalType();
1157       return std::nullopt;
1158     }
1159   } lookupTy(ACtx);
1160 
1161   // Below are auxiliary classes to handle optional types that we get as a
1162   // result of the lookup.
1163   class GetRestrictTy {
1164     const ASTContext &ACtx;
1165 
1166   public:
1167     GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1168     QualType operator()(QualType Ty) {
1169       return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1170     }
1171     Optional<QualType> operator()(Optional<QualType> Ty) {
1172       if (Ty)
1173         return operator()(*Ty);
1174       return std::nullopt;
1175     }
1176   } getRestrictTy(ACtx);
1177   class GetPointerTy {
1178     const ASTContext &ACtx;
1179 
1180   public:
1181     GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1182     QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1183     Optional<QualType> operator()(Optional<QualType> Ty) {
1184       if (Ty)
1185         return operator()(*Ty);
1186       return std::nullopt;
1187     }
1188   } getPointerTy(ACtx);
1189   class {
1190   public:
1191     Optional<QualType> operator()(Optional<QualType> Ty) {
1192       return Ty ? Optional<QualType>(Ty->withConst()) : std::nullopt;
1193     }
1194     QualType operator()(QualType Ty) { return Ty.withConst(); }
1195   } getConstTy;
1196   class GetMaxValue {
1197     BasicValueFactory &BVF;
1198 
1199   public:
1200     GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1201     Optional<RangeInt> operator()(QualType Ty) {
1202       return BVF.getMaxValue(Ty).getLimitedValue();
1203     }
1204     Optional<RangeInt> operator()(Optional<QualType> Ty) {
1205       if (Ty) {
1206         return operator()(*Ty);
1207       }
1208       return std::nullopt;
1209     }
1210   } getMaxValue(BVF);
1211 
1212   // These types are useful for writing specifications quickly,
1213   // New specifications should probably introduce more types.
1214   // Some types are hard to obtain from the AST, eg. "ssize_t".
1215   // In such cases it should be possible to provide multiple variants
1216   // of function summary for common cases (eg. ssize_t could be int or long
1217   // or long long, so three summary variants would be enough).
1218   // Of course, function variants are also useful for C++ overloads.
1219   const QualType VoidTy = ACtx.VoidTy;
1220   const QualType CharTy = ACtx.CharTy;
1221   const QualType WCharTy = ACtx.WCharTy;
1222   const QualType IntTy = ACtx.IntTy;
1223   const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1224   const QualType LongTy = ACtx.LongTy;
1225   const QualType SizeTy = ACtx.getSizeType();
1226 
1227   const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1228   const QualType IntPtrTy = getPointerTy(IntTy);   // int *
1229   const QualType UnsignedIntPtrTy =
1230       getPointerTy(UnsignedIntTy); // unsigned int *
1231   const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1232   const QualType ConstVoidPtrTy =
1233       getPointerTy(getConstTy(VoidTy));            // const void *
1234   const QualType CharPtrTy = getPointerTy(CharTy); // char *
1235   const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
1236   const QualType ConstCharPtrTy =
1237       getPointerTy(getConstTy(CharTy)); // const char *
1238   const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1239   const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1240   const QualType ConstWchar_tPtrTy =
1241       getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1242   const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1243   const QualType SizePtrTy = getPointerTy(SizeTy);
1244   const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1245 
1246   const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
1247   const RangeInt UnsignedIntMax =
1248       BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
1249   const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
1250   const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
1251 
1252   // Set UCharRangeMax to min of int or uchar maximum value.
1253   // The C standard states that the arguments of functions like isalpha must
1254   // be representable as an unsigned char. Their type is 'int', so the max
1255   // value of the argument should be min(UCharMax, IntMax). This just happen
1256   // to be true for commonly used and well tested instruction set
1257   // architectures, but not for others.
1258   const RangeInt UCharRangeMax =
1259       std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
1260 
1261   // The platform dependent value of EOF.
1262   // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
1263   const auto EOFv = [&C]() -> RangeInt {
1264     if (const llvm::Optional<int> OptInt =
1265             tryExpandAsInteger("EOF", C.getPreprocessor()))
1266       return *OptInt;
1267     return -1;
1268   }();
1269 
1270   // Auxiliary class to aid adding summaries to the summary map.
1271   struct AddToFunctionSummaryMap {
1272     const ASTContext &ACtx;
1273     FunctionSummaryMapType &Map;
1274     bool DisplayLoadedSummaries;
1275     AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1276                             bool DisplayLoadedSummaries)
1277         : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1278     }
1279 
1280     // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1281     // by the given Name, and in the global scope. The summary will be attached
1282     // to the found FunctionDecl only if the signatures match.
1283     //
1284     // Returns true if the summary has been added, false otherwise.
1285     bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1286       if (Sign.isInvalid())
1287         return false;
1288       IdentifierInfo &II = ACtx.Idents.get(Name);
1289       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1290       if (LookupRes.empty())
1291         return false;
1292       for (Decl *D : LookupRes) {
1293         if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1294           if (Sum.matchesAndSet(Sign, FD)) {
1295             auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
1296             assert(Res.second && "Function already has a summary set!");
1297             (void)Res;
1298             if (DisplayLoadedSummaries) {
1299               llvm::errs() << "Loaded summary for: ";
1300               FD->print(llvm::errs());
1301               llvm::errs() << "\n";
1302             }
1303             return true;
1304           }
1305         }
1306       }
1307       return false;
1308     }
1309     // Add the same summary for different names with the Signature explicitly
1310     // given.
1311     void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1312       for (StringRef Name : Names)
1313         operator()(Name, Sign, Sum);
1314     }
1315   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1316 
1317   // Below are helpers functions to create the summaries.
1318   auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
1319                               IntRangeVector Ranges) {
1320     return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
1321   };
1322   auto BufferSize = [](auto... Args) {
1323     return std::make_shared<BufferSizeConstraint>(Args...);
1324   };
1325   struct {
1326     auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1327       return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1328     }
1329     auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1330       return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1331     }
1332   } ReturnValueCondition;
1333   struct {
1334     auto operator()(RangeInt b, RangeInt e) {
1335       return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1336     }
1337     auto operator()(RangeInt b, Optional<RangeInt> e) {
1338       if (e)
1339         return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1340       return IntRangeVector{};
1341     }
1342     auto operator()(std::pair<RangeInt, RangeInt> i0,
1343                     std::pair<RangeInt, Optional<RangeInt>> i1) {
1344       if (i1.second)
1345         return IntRangeVector{i0, {i1.first, *(i1.second)}};
1346       return IntRangeVector{i0};
1347     }
1348   } Range;
1349   auto SingleValue = [](RangeInt v) {
1350     return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1351   };
1352   auto LessThanOrEq = BO_LE;
1353   auto NotNull = [&](ArgNo ArgN) {
1354     return std::make_shared<NotNullConstraint>(ArgN);
1355   };
1356 
1357   Optional<QualType> FileTy = lookupTy("FILE");
1358   Optional<QualType> FilePtrTy = getPointerTy(FileTy);
1359   Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1360 
1361   // We are finally ready to define specifications for all supported functions.
1362   //
1363   // Argument ranges should always cover all variants. If return value
1364   // is completely unknown, omit it from the respective range set.
1365   //
1366   // Every item in the list of range sets represents a particular
1367   // execution path the analyzer would need to explore once
1368   // the call is modeled - a new program state is constructed
1369   // for every range set, and each range line in the range set
1370   // corresponds to a specific constraint within this state.
1371 
1372   // The isascii() family of functions.
1373   // The behavior is undefined if the value of the argument is not
1374   // representable as unsigned char or is not equal to EOF. See e.g. C99
1375   // 7.4.1.2 The isalpha function (p: 181-182).
1376   addToFunctionSummaryMap(
1377       "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1378       Summary(EvalCallAsPure)
1379           // Boils down to isupper() or islower() or isdigit().
1380           .Case({ArgumentCondition(0U, WithinRange,
1381                                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1382                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1383                 ErrnoIrrelevant, "Assuming the character is alphanumeric")
1384           // The locale-specific range.
1385           // No post-condition. We are completely unaware of
1386           // locale-specific return values.
1387           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1388                 ErrnoIrrelevant)
1389           .Case(
1390               {ArgumentCondition(
1391                    0U, OutOfRange,
1392                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1393                ReturnValueCondition(WithinRange, SingleValue(0))},
1394               ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
1395           .ArgConstraint(ArgumentCondition(
1396               0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1397   addToFunctionSummaryMap(
1398       "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1399       Summary(EvalCallAsPure)
1400           .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1401                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1402                 ErrnoIrrelevant, "Assuming the character is alphabetical")
1403           // The locale-specific range.
1404           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1405                 ErrnoIrrelevant)
1406           .Case({ArgumentCondition(
1407                      0U, OutOfRange,
1408                      {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1409                  ReturnValueCondition(WithinRange, SingleValue(0))},
1410                 ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
1411   addToFunctionSummaryMap(
1412       "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1413       Summary(EvalCallAsPure)
1414           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1415                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1416                 ErrnoIrrelevant, "Assuming the character is an ASCII character")
1417           .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1418                  ReturnValueCondition(WithinRange, SingleValue(0))},
1419                 ErrnoIrrelevant,
1420                 "Assuming the character is not an ASCII character"));
1421   addToFunctionSummaryMap(
1422       "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1423       Summary(EvalCallAsPure)
1424           .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1425                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1426                 ErrnoIrrelevant, "Assuming the character is a blank character")
1427           .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1428                  ReturnValueCondition(WithinRange, SingleValue(0))},
1429                 ErrnoIrrelevant,
1430                 "Assuming the character is not a blank character"));
1431   addToFunctionSummaryMap(
1432       "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1433       Summary(EvalCallAsPure)
1434           .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1435                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1436                 ErrnoIrrelevant,
1437                 "Assuming the character is a control character")
1438           .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1439                  ReturnValueCondition(WithinRange, SingleValue(0))},
1440                 ErrnoIrrelevant,
1441                 "Assuming the character is not a control character"));
1442   addToFunctionSummaryMap(
1443       "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1444       Summary(EvalCallAsPure)
1445           .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1446                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1447                 ErrnoIrrelevant, "Assuming the character is a digit")
1448           .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1449                  ReturnValueCondition(WithinRange, SingleValue(0))},
1450                 ErrnoIrrelevant, "Assuming the character is not a digit"));
1451   addToFunctionSummaryMap(
1452       "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1453       Summary(EvalCallAsPure)
1454           .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1455                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1456                 ErrnoIrrelevant,
1457                 "Assuming the character has graphical representation")
1458           .Case(
1459               {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1460                ReturnValueCondition(WithinRange, SingleValue(0))},
1461               ErrnoIrrelevant,
1462               "Assuming the character does not have graphical representation"));
1463   addToFunctionSummaryMap(
1464       "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1465       Summary(EvalCallAsPure)
1466           // Is certainly lowercase.
1467           .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1468                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1469                 ErrnoIrrelevant, "Assuming the character is a lowercase letter")
1470           // Is ascii but not lowercase.
1471           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1472                  ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1473                  ReturnValueCondition(WithinRange, SingleValue(0))},
1474                 ErrnoIrrelevant,
1475                 "Assuming the character is not a lowercase letter")
1476           // The locale-specific range.
1477           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1478                 ErrnoIrrelevant)
1479           // Is not an unsigned char.
1480           .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1481                  ReturnValueCondition(WithinRange, SingleValue(0))},
1482                 ErrnoIrrelevant));
1483   addToFunctionSummaryMap(
1484       "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1485       Summary(EvalCallAsPure)
1486           .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1487                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1488                 ErrnoIrrelevant, "Assuming the character is printable")
1489           .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1490                  ReturnValueCondition(WithinRange, SingleValue(0))},
1491                 ErrnoIrrelevant, "Assuming the character is non-printable"));
1492   addToFunctionSummaryMap(
1493       "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1494       Summary(EvalCallAsPure)
1495           .Case({ArgumentCondition(
1496                      0U, WithinRange,
1497                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1498                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1499                 ErrnoIrrelevant, "Assuming the character is a punctuation mark")
1500           .Case({ArgumentCondition(
1501                      0U, OutOfRange,
1502                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1503                  ReturnValueCondition(WithinRange, SingleValue(0))},
1504                 ErrnoIrrelevant,
1505                 "Assuming the character is not a punctuation mark"));
1506   addToFunctionSummaryMap(
1507       "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1508       Summary(EvalCallAsPure)
1509           // Space, '\f', '\n', '\r', '\t', '\v'.
1510           .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1511                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1512                 ErrnoIrrelevant,
1513                 "Assuming the character is a whitespace character")
1514           // The locale-specific range.
1515           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1516                 ErrnoIrrelevant)
1517           .Case({ArgumentCondition(0U, OutOfRange,
1518                                    {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1519                  ReturnValueCondition(WithinRange, SingleValue(0))},
1520                 ErrnoIrrelevant,
1521                 "Assuming the character is not a whitespace character"));
1522   addToFunctionSummaryMap(
1523       "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1524       Summary(EvalCallAsPure)
1525           // Is certainly uppercase.
1526           .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1527                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1528                 ErrnoIrrelevant,
1529                 "Assuming the character is an uppercase letter")
1530           // The locale-specific range.
1531           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1532                 ErrnoIrrelevant)
1533           // Other.
1534           .Case({ArgumentCondition(0U, OutOfRange,
1535                                    {{'A', 'Z'}, {128, UCharRangeMax}}),
1536                  ReturnValueCondition(WithinRange, SingleValue(0))},
1537                 ErrnoIrrelevant,
1538                 "Assuming the character is not an uppercase letter"));
1539   addToFunctionSummaryMap(
1540       "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1541       Summary(EvalCallAsPure)
1542           .Case({ArgumentCondition(0U, WithinRange,
1543                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1544                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1545                 ErrnoIrrelevant,
1546                 "Assuming the character is a hexadecimal digit")
1547           .Case({ArgumentCondition(0U, OutOfRange,
1548                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1549                  ReturnValueCondition(WithinRange, SingleValue(0))},
1550                 ErrnoIrrelevant,
1551                 "Assuming the character is not a hexadecimal digit"));
1552   addToFunctionSummaryMap(
1553       "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1554       Summary(EvalCallAsPure)
1555           .ArgConstraint(ArgumentCondition(
1556               0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1557   addToFunctionSummaryMap(
1558       "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1559       Summary(EvalCallAsPure)
1560           .ArgConstraint(ArgumentCondition(
1561               0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1562   addToFunctionSummaryMap(
1563       "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1564       Summary(EvalCallAsPure)
1565           .ArgConstraint(ArgumentCondition(
1566               0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1567 
1568   // The getc() family of functions that returns either a char or an EOF.
1569   addToFunctionSummaryMap(
1570       {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
1571       Summary(NoEvalCall)
1572           .Case({ReturnValueCondition(WithinRange,
1573                                       {{EOFv, EOFv}, {0, UCharRangeMax}})},
1574                 ErrnoIrrelevant));
1575   addToFunctionSummaryMap(
1576       "getchar", Signature(ArgTypes{}, RetType{IntTy}),
1577       Summary(NoEvalCall)
1578           .Case({ReturnValueCondition(WithinRange,
1579                                       {{EOFv, EOFv}, {0, UCharRangeMax}})},
1580                 ErrnoIrrelevant));
1581 
1582   // read()-like functions that never return more than buffer size.
1583   auto FreadSummary =
1584       Summary(NoEvalCall)
1585           .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1586                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
1587                 ErrnoIrrelevant)
1588           .ArgConstraint(NotNull(ArgNo(0)))
1589           .ArgConstraint(NotNull(ArgNo(3)))
1590           .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
1591                                     /*BufSizeMultiplier=*/ArgNo(2)));
1592 
1593   // size_t fread(void *restrict ptr, size_t size, size_t nitems,
1594   //              FILE *restrict stream);
1595   addToFunctionSummaryMap(
1596       "fread",
1597       Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
1598                 RetType{SizeTy}),
1599       FreadSummary);
1600   // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
1601   //               FILE *restrict stream);
1602   addToFunctionSummaryMap("fwrite",
1603                           Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
1604                                              SizeTy, FilePtrRestrictTy},
1605                                     RetType{SizeTy}),
1606                           FreadSummary);
1607 
1608   Optional<QualType> Ssize_tTy = lookupTy("ssize_t");
1609   Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
1610 
1611   auto ReadSummary =
1612       Summary(NoEvalCall)
1613           .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1614                  ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
1615                 ErrnoIrrelevant);
1616 
1617   // FIXME these are actually defined by POSIX and not by the C standard, we
1618   // should handle them together with the rest of the POSIX functions.
1619   // ssize_t read(int fildes, void *buf, size_t nbyte);
1620   addToFunctionSummaryMap(
1621       "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
1622       ReadSummary);
1623   // ssize_t write(int fildes, const void *buf, size_t nbyte);
1624   addToFunctionSummaryMap(
1625       "write",
1626       Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
1627       ReadSummary);
1628 
1629   auto GetLineSummary =
1630       Summary(NoEvalCall)
1631           .Case({ReturnValueCondition(WithinRange,
1632                                       Range({-1, -1}, {1, Ssize_tMax}))},
1633                 ErrnoIrrelevant);
1634 
1635   QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
1636 
1637   // getline()-like functions either fail or read at least the delimiter.
1638   // FIXME these are actually defined by POSIX and not by the C standard, we
1639   // should handle them together with the rest of the POSIX functions.
1640   // ssize_t getline(char **restrict lineptr, size_t *restrict n,
1641   //                 FILE *restrict stream);
1642   addToFunctionSummaryMap(
1643       "getline",
1644       Signature(
1645           ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
1646           RetType{Ssize_tTy}),
1647       GetLineSummary);
1648   // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
1649   //                  int delimiter, FILE *restrict stream);
1650   addToFunctionSummaryMap(
1651       "getdelim",
1652       Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
1653                          FilePtrRestrictTy},
1654                 RetType{Ssize_tTy}),
1655       GetLineSummary);
1656 
1657   {
1658     Summary GetenvSummary =
1659         Summary(NoEvalCall)
1660             .ArgConstraint(NotNull(ArgNo(0)))
1661             .Case({NotNull(Ret)}, ErrnoIrrelevant,
1662                   "Assuming the environment variable exists");
1663     // In untrusted environments the envvar might not exist.
1664     if (!ShouldAssumeControlledEnvironment)
1665       GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
1666                          "Assuming the environment variable does not exist");
1667 
1668     // char *getenv(const char *name);
1669     addToFunctionSummaryMap(
1670         "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
1671         std::move(GetenvSummary));
1672   }
1673 
1674   if (ModelPOSIX) {
1675 
1676     // long a64l(const char *str64);
1677     addToFunctionSummaryMap(
1678         "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
1679         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1680 
1681     // char *l64a(long value);
1682     addToFunctionSummaryMap("l64a",
1683                             Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
1684                             Summary(NoEvalCall)
1685                                 .ArgConstraint(ArgumentCondition(
1686                                     0, WithinRange, Range(0, LongMax))));
1687 
1688     const auto ReturnsZeroOrMinusOne =
1689         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
1690     const auto ReturnsZero =
1691         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
1692     const auto ReturnsMinusOne =
1693         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
1694     const auto ReturnsNonnegative =
1695         ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
1696     const auto ReturnsFileDescriptor =
1697         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
1698     const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
1699 
1700     // int access(const char *pathname, int amode);
1701     addToFunctionSummaryMap(
1702         "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
1703         Summary(NoEvalCall)
1704             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1705             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1706             .ArgConstraint(NotNull(ArgNo(0))));
1707 
1708     // int faccessat(int dirfd, const char *pathname, int mode, int flags);
1709     addToFunctionSummaryMap(
1710         "faccessat",
1711         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
1712                   RetType{IntTy}),
1713         Summary(NoEvalCall)
1714             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1715             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1716             .ArgConstraint(NotNull(ArgNo(1))));
1717 
1718     // int dup(int fildes);
1719     addToFunctionSummaryMap(
1720         "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1721         Summary(NoEvalCall)
1722             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1723             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1724             .ArgConstraint(
1725                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1726 
1727     // int dup2(int fildes1, int filedes2);
1728     addToFunctionSummaryMap(
1729         "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
1730         Summary(NoEvalCall)
1731             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1732             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1733             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1734             .ArgConstraint(
1735                 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
1736 
1737     // int fdatasync(int fildes);
1738     addToFunctionSummaryMap("fdatasync",
1739                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
1740                             Summary(NoEvalCall)
1741                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
1742                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1743                                 .ArgConstraint(ArgumentCondition(
1744                                     0, WithinRange, Range(0, IntMax))));
1745 
1746     // int fnmatch(const char *pattern, const char *string, int flags);
1747     addToFunctionSummaryMap(
1748         "fnmatch",
1749         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
1750                   RetType{IntTy}),
1751         Summary(NoEvalCall)
1752             .ArgConstraint(NotNull(ArgNo(0)))
1753             .ArgConstraint(NotNull(ArgNo(1))));
1754 
1755     // int fsync(int fildes);
1756     addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1757                             Summary(NoEvalCall)
1758                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
1759                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1760                                 .ArgConstraint(ArgumentCondition(
1761                                     0, WithinRange, Range(0, IntMax))));
1762 
1763     Optional<QualType> Off_tTy = lookupTy("off_t");
1764 
1765     // int truncate(const char *path, off_t length);
1766     addToFunctionSummaryMap(
1767         "truncate",
1768         Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
1769         Summary(NoEvalCall)
1770             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1771             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1772             .ArgConstraint(NotNull(ArgNo(0))));
1773 
1774     // int symlink(const char *oldpath, const char *newpath);
1775     addToFunctionSummaryMap(
1776         "symlink",
1777         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
1778         Summary(NoEvalCall)
1779             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1780             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1781             .ArgConstraint(NotNull(ArgNo(0)))
1782             .ArgConstraint(NotNull(ArgNo(1))));
1783 
1784     // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
1785     addToFunctionSummaryMap(
1786         "symlinkat",
1787         Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
1788                   RetType{IntTy}),
1789         Summary(NoEvalCall)
1790             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1791             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1792             .ArgConstraint(NotNull(ArgNo(0)))
1793             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
1794             .ArgConstraint(NotNull(ArgNo(2))));
1795 
1796     // int lockf(int fd, int cmd, off_t len);
1797     addToFunctionSummaryMap(
1798         "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
1799         Summary(NoEvalCall)
1800             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1801             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1802             .ArgConstraint(
1803                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1804 
1805     Optional<QualType> Mode_tTy = lookupTy("mode_t");
1806 
1807     // int creat(const char *pathname, mode_t mode);
1808     addToFunctionSummaryMap(
1809         "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1810         Summary(NoEvalCall)
1811             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1812             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1813             .ArgConstraint(NotNull(ArgNo(0))));
1814 
1815     // unsigned int sleep(unsigned int seconds);
1816     addToFunctionSummaryMap(
1817         "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
1818         Summary(NoEvalCall)
1819             .ArgConstraint(
1820                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1821 
1822     Optional<QualType> DirTy = lookupTy("DIR");
1823     Optional<QualType> DirPtrTy = getPointerTy(DirTy);
1824 
1825     // int dirfd(DIR *dirp);
1826     addToFunctionSummaryMap(
1827         "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
1828         Summary(NoEvalCall)
1829             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1830             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1831             .ArgConstraint(NotNull(ArgNo(0))));
1832 
1833     // unsigned int alarm(unsigned int seconds);
1834     addToFunctionSummaryMap(
1835         "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
1836         Summary(NoEvalCall)
1837             .ArgConstraint(
1838                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1839 
1840     // int closedir(DIR *dir);
1841     addToFunctionSummaryMap("closedir",
1842                             Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
1843                             Summary(NoEvalCall)
1844                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
1845                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1846                                 .ArgConstraint(NotNull(ArgNo(0))));
1847 
1848     // char *strdup(const char *s);
1849     addToFunctionSummaryMap(
1850         "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
1851         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1852 
1853     // char *strndup(const char *s, size_t n);
1854     addToFunctionSummaryMap(
1855         "strndup",
1856         Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
1857         Summary(NoEvalCall)
1858             .ArgConstraint(NotNull(ArgNo(0)))
1859             .ArgConstraint(
1860                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1861 
1862     // wchar_t *wcsdup(const wchar_t *s);
1863     addToFunctionSummaryMap(
1864         "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
1865         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1866 
1867     // int mkstemp(char *template);
1868     addToFunctionSummaryMap(
1869         "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
1870         Summary(NoEvalCall)
1871             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1872             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1873             .ArgConstraint(NotNull(ArgNo(0))));
1874 
1875     // char *mkdtemp(char *template);
1876     // FIXME: Improve for errno modeling.
1877     addToFunctionSummaryMap(
1878         "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
1879         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1880 
1881     // char *getcwd(char *buf, size_t size);
1882     // FIXME: Improve for errno modeling.
1883     addToFunctionSummaryMap(
1884         "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
1885         Summary(NoEvalCall)
1886             .ArgConstraint(
1887                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1888 
1889     // int mkdir(const char *pathname, mode_t mode);
1890     addToFunctionSummaryMap(
1891         "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1892         Summary(NoEvalCall)
1893             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1894             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1895             .ArgConstraint(NotNull(ArgNo(0))));
1896 
1897     // int mkdirat(int dirfd, const char *pathname, mode_t mode);
1898     addToFunctionSummaryMap(
1899         "mkdirat",
1900         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1901         Summary(NoEvalCall)
1902             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1903             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1904             .ArgConstraint(NotNull(ArgNo(1))));
1905 
1906     Optional<QualType> Dev_tTy = lookupTy("dev_t");
1907 
1908     // int mknod(const char *pathname, mode_t mode, dev_t dev);
1909     addToFunctionSummaryMap(
1910         "mknod",
1911         Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
1912         Summary(NoEvalCall)
1913             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1914             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1915             .ArgConstraint(NotNull(ArgNo(0))));
1916 
1917     // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
1918     addToFunctionSummaryMap(
1919         "mknodat",
1920         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
1921                   RetType{IntTy}),
1922         Summary(NoEvalCall)
1923             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1924             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1925             .ArgConstraint(NotNull(ArgNo(1))));
1926 
1927     // int chmod(const char *path, mode_t mode);
1928     addToFunctionSummaryMap(
1929         "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1930         Summary(NoEvalCall)
1931             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1932             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1933             .ArgConstraint(NotNull(ArgNo(0))));
1934 
1935     // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
1936     addToFunctionSummaryMap(
1937         "fchmodat",
1938         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
1939                   RetType{IntTy}),
1940         Summary(NoEvalCall)
1941             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1942             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1943             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1944             .ArgConstraint(NotNull(ArgNo(1))));
1945 
1946     // int fchmod(int fildes, mode_t mode);
1947     addToFunctionSummaryMap(
1948         "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
1949         Summary(NoEvalCall)
1950             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1951             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1952             .ArgConstraint(
1953                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1954 
1955     Optional<QualType> Uid_tTy = lookupTy("uid_t");
1956     Optional<QualType> Gid_tTy = lookupTy("gid_t");
1957 
1958     // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
1959     //              int flags);
1960     addToFunctionSummaryMap(
1961         "fchownat",
1962         Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
1963                   RetType{IntTy}),
1964         Summary(NoEvalCall)
1965             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1966             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1967             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1968             .ArgConstraint(NotNull(ArgNo(1))));
1969 
1970     // int chown(const char *path, uid_t owner, gid_t group);
1971     addToFunctionSummaryMap(
1972         "chown",
1973         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
1974         Summary(NoEvalCall)
1975             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1976             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1977             .ArgConstraint(NotNull(ArgNo(0))));
1978 
1979     // int lchown(const char *path, uid_t owner, gid_t group);
1980     addToFunctionSummaryMap(
1981         "lchown",
1982         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
1983         Summary(NoEvalCall)
1984             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1985             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1986             .ArgConstraint(NotNull(ArgNo(0))));
1987 
1988     // int fchown(int fildes, uid_t owner, gid_t group);
1989     addToFunctionSummaryMap(
1990         "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
1991         Summary(NoEvalCall)
1992             .Case(ReturnsZero, ErrnoMustNotBeChecked)
1993             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1994             .ArgConstraint(
1995                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1996 
1997     // int rmdir(const char *pathname);
1998     addToFunctionSummaryMap("rmdir",
1999                             Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2000                             Summary(NoEvalCall)
2001                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2002                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2003                                 .ArgConstraint(NotNull(ArgNo(0))));
2004 
2005     // int chdir(const char *path);
2006     addToFunctionSummaryMap("chdir",
2007                             Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2008                             Summary(NoEvalCall)
2009                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2010                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2011                                 .ArgConstraint(NotNull(ArgNo(0))));
2012 
2013     // int link(const char *oldpath, const char *newpath);
2014     addToFunctionSummaryMap(
2015         "link",
2016         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2017         Summary(NoEvalCall)
2018             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2019             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2020             .ArgConstraint(NotNull(ArgNo(0)))
2021             .ArgConstraint(NotNull(ArgNo(1))));
2022 
2023     // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2024     //            int flag);
2025     addToFunctionSummaryMap(
2026         "linkat",
2027         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2028                   RetType{IntTy}),
2029         Summary(NoEvalCall)
2030             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2031             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2032             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2033             .ArgConstraint(NotNull(ArgNo(1)))
2034             .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
2035             .ArgConstraint(NotNull(ArgNo(3))));
2036 
2037     // int unlink(const char *pathname);
2038     addToFunctionSummaryMap("unlink",
2039                             Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2040                             Summary(NoEvalCall)
2041                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2042                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2043                                 .ArgConstraint(NotNull(ArgNo(0))));
2044 
2045     // int unlinkat(int fd, const char *path, int flag);
2046     addToFunctionSummaryMap(
2047         "unlinkat",
2048         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2049         Summary(NoEvalCall)
2050             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2051             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2052             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2053             .ArgConstraint(NotNull(ArgNo(1))));
2054 
2055     Optional<QualType> StructStatTy = lookupTy("stat");
2056     Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2057     Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy);
2058 
2059     // int fstat(int fd, struct stat *statbuf);
2060     addToFunctionSummaryMap(
2061         "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2062         Summary(NoEvalCall)
2063             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2064             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2065             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2066             .ArgConstraint(NotNull(ArgNo(1))));
2067 
2068     // int stat(const char *restrict path, struct stat *restrict buf);
2069     addToFunctionSummaryMap(
2070         "stat",
2071         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2072                   RetType{IntTy}),
2073         Summary(NoEvalCall)
2074             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2075             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2076             .ArgConstraint(NotNull(ArgNo(0)))
2077             .ArgConstraint(NotNull(ArgNo(1))));
2078 
2079     // int lstat(const char *restrict path, struct stat *restrict buf);
2080     addToFunctionSummaryMap(
2081         "lstat",
2082         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2083                   RetType{IntTy}),
2084         Summary(NoEvalCall)
2085             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2086             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2087             .ArgConstraint(NotNull(ArgNo(0)))
2088             .ArgConstraint(NotNull(ArgNo(1))));
2089 
2090     // int fstatat(int fd, const char *restrict path,
2091     //             struct stat *restrict buf, int flag);
2092     addToFunctionSummaryMap(
2093         "fstatat",
2094         Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2095                            StructStatPtrRestrictTy, IntTy},
2096                   RetType{IntTy}),
2097         Summary(NoEvalCall)
2098             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2099             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2100             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2101             .ArgConstraint(NotNull(ArgNo(1)))
2102             .ArgConstraint(NotNull(ArgNo(2))));
2103 
2104     // DIR *opendir(const char *name);
2105     // FIXME: Improve for errno modeling.
2106     addToFunctionSummaryMap(
2107         "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
2108         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2109 
2110     // DIR *fdopendir(int fd);
2111     // FIXME: Improve for errno modeling.
2112     addToFunctionSummaryMap("fdopendir",
2113                             Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2114                             Summary(NoEvalCall)
2115                                 .ArgConstraint(ArgumentCondition(
2116                                     0, WithinRange, Range(0, IntMax))));
2117 
2118     // int isatty(int fildes);
2119     addToFunctionSummaryMap(
2120         "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2121         Summary(NoEvalCall)
2122             .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
2123                   ErrnoIrrelevant)
2124             .ArgConstraint(
2125                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2126 
2127     // FILE *popen(const char *command, const char *type);
2128     // FIXME: Improve for errno modeling.
2129     addToFunctionSummaryMap(
2130         "popen",
2131         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2132         Summary(NoEvalCall)
2133             .ArgConstraint(NotNull(ArgNo(0)))
2134             .ArgConstraint(NotNull(ArgNo(1))));
2135 
2136     // int pclose(FILE *stream);
2137     // FIXME: Improve for errno modeling.
2138     addToFunctionSummaryMap(
2139         "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2140         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2141 
2142     // int close(int fildes);
2143     addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2144                             Summary(NoEvalCall)
2145                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2146                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2147                                 .ArgConstraint(ArgumentCondition(
2148                                     0, WithinRange, Range(-1, IntMax))));
2149 
2150     // long fpathconf(int fildes, int name);
2151     addToFunctionSummaryMap("fpathconf",
2152                             Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2153                             Summary(NoEvalCall)
2154                                 .ArgConstraint(ArgumentCondition(
2155                                     0, WithinRange, Range(0, IntMax))));
2156 
2157     // long pathconf(const char *path, int name);
2158     addToFunctionSummaryMap(
2159         "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2160         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2161 
2162     // FILE *fdopen(int fd, const char *mode);
2163     // FIXME: Improve for errno modeling.
2164     addToFunctionSummaryMap(
2165         "fdopen",
2166         Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2167         Summary(NoEvalCall)
2168             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2169             .ArgConstraint(NotNull(ArgNo(1))));
2170 
2171     // void rewinddir(DIR *dir);
2172     addToFunctionSummaryMap(
2173         "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2174         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2175 
2176     // void seekdir(DIR *dirp, long loc);
2177     addToFunctionSummaryMap(
2178         "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2179         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2180 
2181     // int rand_r(unsigned int *seedp);
2182     addToFunctionSummaryMap(
2183         "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2184         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2185 
2186     // int fileno(FILE *stream);
2187     addToFunctionSummaryMap(
2188         "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2189         Summary(NoEvalCall)
2190             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2191             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2192             .ArgConstraint(NotNull(ArgNo(0))));
2193 
2194     // int fseeko(FILE *stream, off_t offset, int whence);
2195     addToFunctionSummaryMap(
2196         "fseeko",
2197         Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2198         Summary(NoEvalCall)
2199             .Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant)
2200             .ArgConstraint(NotNull(ArgNo(0))));
2201 
2202     // off_t ftello(FILE *stream);
2203     addToFunctionSummaryMap(
2204         "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2205         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2206 
2207     // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2208     // off_t offset);
2209     // FIXME: Improve for errno modeling.
2210     addToFunctionSummaryMap(
2211         "mmap",
2212         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
2213                   RetType{VoidPtrTy}),
2214         Summary(NoEvalCall)
2215             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2216             .ArgConstraint(
2217                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2218 
2219     Optional<QualType> Off64_tTy = lookupTy("off64_t");
2220     // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2221     // off64_t offset);
2222     // FIXME: Improve for errno modeling.
2223     addToFunctionSummaryMap(
2224         "mmap64",
2225         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
2226                   RetType{VoidPtrTy}),
2227         Summary(NoEvalCall)
2228             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2229             .ArgConstraint(
2230                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2231 
2232     // int pipe(int fildes[2]);
2233     addToFunctionSummaryMap("pipe",
2234                             Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2235                             Summary(NoEvalCall)
2236                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2237                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2238                                 .ArgConstraint(NotNull(ArgNo(0))));
2239 
2240     // off_t lseek(int fildes, off_t offset, int whence);
2241     // In the first case we can not tell for sure if it failed or not.
2242     // A return value different from of the expected offset (that is unknown
2243     // here) may indicate failure. For this reason we do not enforce the errno
2244     // check (can cause false positive).
2245     addToFunctionSummaryMap(
2246         "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2247         Summary(NoEvalCall)
2248             .Case(ReturnsNonnegative, ErrnoIrrelevant)
2249             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2250             .ArgConstraint(
2251                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2252 
2253     // ssize_t readlink(const char *restrict path, char *restrict buf,
2254     //                  size_t bufsize);
2255     addToFunctionSummaryMap(
2256         "readlink",
2257         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2258                   RetType{Ssize_tTy}),
2259         Summary(NoEvalCall)
2260             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2261                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2262                   ErrnoMustNotBeChecked)
2263             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2264             .ArgConstraint(NotNull(ArgNo(0)))
2265             .ArgConstraint(NotNull(ArgNo(1)))
2266             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2267                                       /*BufSize=*/ArgNo(2)))
2268             .ArgConstraint(
2269                 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
2270 
2271     // ssize_t readlinkat(int fd, const char *restrict path,
2272     //                    char *restrict buf, size_t bufsize);
2273     addToFunctionSummaryMap(
2274         "readlinkat",
2275         Signature(
2276             ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2277             RetType{Ssize_tTy}),
2278         Summary(NoEvalCall)
2279             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)),
2280                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2281                   ErrnoMustNotBeChecked)
2282             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2283             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2284             .ArgConstraint(NotNull(ArgNo(1)))
2285             .ArgConstraint(NotNull(ArgNo(2)))
2286             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
2287                                       /*BufSize=*/ArgNo(3)))
2288             .ArgConstraint(
2289                 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
2290 
2291     // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
2292     // *newpath);
2293     addToFunctionSummaryMap(
2294         "renameat",
2295         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
2296                   RetType{IntTy}),
2297         Summary(NoEvalCall)
2298             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2299             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2300             .ArgConstraint(NotNull(ArgNo(1)))
2301             .ArgConstraint(NotNull(ArgNo(3))));
2302 
2303     // char *realpath(const char *restrict file_name,
2304     //                char *restrict resolved_name);
2305     // FIXME: Improve for errno modeling.
2306     addToFunctionSummaryMap(
2307         "realpath",
2308         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
2309                   RetType{CharPtrTy}),
2310         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2311 
2312     QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
2313 
2314     // int execv(const char *path, char *const argv[]);
2315     addToFunctionSummaryMap(
2316         "execv",
2317         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2318         Summary(NoEvalCall)
2319             .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
2320                   ErrnoIrrelevant)
2321             .ArgConstraint(NotNull(ArgNo(0))));
2322 
2323     // int execvp(const char *file, char *const argv[]);
2324     addToFunctionSummaryMap(
2325         "execvp",
2326         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2327         Summary(NoEvalCall)
2328             .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
2329                   ErrnoIrrelevant)
2330             .ArgConstraint(NotNull(ArgNo(0))));
2331 
2332     // int getopt(int argc, char * const argv[], const char *optstring);
2333     addToFunctionSummaryMap(
2334         "getopt",
2335         Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
2336                   RetType{IntTy}),
2337         Summary(NoEvalCall)
2338             .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
2339                   ErrnoIrrelevant)
2340             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2341             .ArgConstraint(NotNull(ArgNo(1)))
2342             .ArgConstraint(NotNull(ArgNo(2))));
2343 
2344     Optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
2345     Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy);
2346     Optional<QualType> ConstStructSockaddrPtrTy =
2347         getPointerTy(getConstTy(StructSockaddrTy));
2348     Optional<QualType> StructSockaddrPtrRestrictTy =
2349         getRestrictTy(StructSockaddrPtrTy);
2350     Optional<QualType> ConstStructSockaddrPtrRestrictTy =
2351         getRestrictTy(ConstStructSockaddrPtrTy);
2352     Optional<QualType> Socklen_tTy = lookupTy("socklen_t");
2353     Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
2354     Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy);
2355     Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
2356 
2357     // In 'socket.h' of some libc implementations with C99, sockaddr parameter
2358     // is a transparent union of the underlying sockaddr_ family of pointers
2359     // instead of being a pointer to struct sockaddr. In these cases, the
2360     // standardized signature will not match, thus we try to match with another
2361     // signature that has the joker Irrelevant type. We also remove those
2362     // constraints which require pointer types for the sockaddr param.
2363     auto Accept =
2364         Summary(NoEvalCall)
2365             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2366             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2367             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
2368     if (!addToFunctionSummaryMap(
2369             "accept",
2370             // int accept(int socket, struct sockaddr *restrict address,
2371             //            socklen_t *restrict address_len);
2372             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2373                                Socklen_tPtrRestrictTy},
2374                       RetType{IntTy}),
2375             Accept))
2376       addToFunctionSummaryMap(
2377           "accept",
2378           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
2379                     RetType{IntTy}),
2380           Accept);
2381 
2382     // int bind(int socket, const struct sockaddr *address, socklen_t
2383     //          address_len);
2384     if (!addToFunctionSummaryMap(
2385             "bind",
2386             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
2387                       RetType{IntTy}),
2388             Summary(NoEvalCall)
2389                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2390                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2391                 .ArgConstraint(
2392                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2393                 .ArgConstraint(NotNull(ArgNo(1)))
2394                 .ArgConstraint(
2395                     BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
2396                 .ArgConstraint(
2397                     ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
2398       // Do not add constraints on sockaddr.
2399       addToFunctionSummaryMap(
2400           "bind",
2401           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
2402           Summary(NoEvalCall)
2403               .Case(ReturnsZero, ErrnoMustNotBeChecked)
2404               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2405               .ArgConstraint(
2406                   ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2407               .ArgConstraint(
2408                   ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
2409 
2410     // int getpeername(int socket, struct sockaddr *restrict address,
2411     //                 socklen_t *restrict address_len);
2412     if (!addToFunctionSummaryMap(
2413             "getpeername",
2414             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2415                                Socklen_tPtrRestrictTy},
2416                       RetType{IntTy}),
2417             Summary(NoEvalCall)
2418                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2419                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2420                 .ArgConstraint(
2421                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2422                 .ArgConstraint(NotNull(ArgNo(1)))
2423                 .ArgConstraint(NotNull(ArgNo(2)))))
2424       addToFunctionSummaryMap(
2425           "getpeername",
2426           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
2427                     RetType{IntTy}),
2428           Summary(NoEvalCall)
2429               .Case(ReturnsZero, ErrnoMustNotBeChecked)
2430               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2431               .ArgConstraint(
2432                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2433 
2434     // int getsockname(int socket, struct sockaddr *restrict address,
2435     //                 socklen_t *restrict address_len);
2436     if (!addToFunctionSummaryMap(
2437             "getsockname",
2438             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2439                                Socklen_tPtrRestrictTy},
2440                       RetType{IntTy}),
2441             Summary(NoEvalCall)
2442                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2443                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2444                 .ArgConstraint(
2445                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2446                 .ArgConstraint(NotNull(ArgNo(1)))
2447                 .ArgConstraint(NotNull(ArgNo(2)))))
2448       addToFunctionSummaryMap(
2449           "getsockname",
2450           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
2451                     RetType{IntTy}),
2452           Summary(NoEvalCall)
2453               .Case(ReturnsZero, ErrnoMustNotBeChecked)
2454               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2455               .ArgConstraint(
2456                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2457 
2458     // int connect(int socket, const struct sockaddr *address, socklen_t
2459     //             address_len);
2460     if (!addToFunctionSummaryMap(
2461             "connect",
2462             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
2463                       RetType{IntTy}),
2464             Summary(NoEvalCall)
2465                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2466                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2467                 .ArgConstraint(
2468                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2469                 .ArgConstraint(NotNull(ArgNo(1)))))
2470       addToFunctionSummaryMap(
2471           "connect",
2472           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
2473           Summary(NoEvalCall)
2474               .Case(ReturnsZero, ErrnoMustNotBeChecked)
2475               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2476               .ArgConstraint(
2477                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2478 
2479     auto Recvfrom =
2480         Summary(NoEvalCall)
2481             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2482                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2483                   ErrnoMustNotBeChecked)
2484             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2485             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2486             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2487                                       /*BufSize=*/ArgNo(2)));
2488     if (!addToFunctionSummaryMap(
2489             "recvfrom",
2490             // ssize_t recvfrom(int socket, void *restrict buffer,
2491             //                  size_t length,
2492             //                  int flags, struct sockaddr *restrict address,
2493             //                  socklen_t *restrict address_len);
2494             Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
2495                                StructSockaddrPtrRestrictTy,
2496                                Socklen_tPtrRestrictTy},
2497                       RetType{Ssize_tTy}),
2498             Recvfrom))
2499       addToFunctionSummaryMap(
2500           "recvfrom",
2501           Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
2502                              Irrelevant, Socklen_tPtrRestrictTy},
2503                     RetType{Ssize_tTy}),
2504           Recvfrom);
2505 
2506     auto Sendto =
2507         Summary(NoEvalCall)
2508             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2509                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2510                   ErrnoMustNotBeChecked)
2511             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2512             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2513             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2514                                       /*BufSize=*/ArgNo(2)));
2515     if (!addToFunctionSummaryMap(
2516             "sendto",
2517             // ssize_t sendto(int socket, const void *message, size_t length,
2518             //                int flags, const struct sockaddr *dest_addr,
2519             //                socklen_t dest_len);
2520             Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
2521                                ConstStructSockaddrPtrTy, Socklen_tTy},
2522                       RetType{Ssize_tTy}),
2523             Sendto))
2524       addToFunctionSummaryMap(
2525           "sendto",
2526           Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
2527                              Socklen_tTy},
2528                     RetType{Ssize_tTy}),
2529           Sendto);
2530 
2531     // int listen(int sockfd, int backlog);
2532     addToFunctionSummaryMap("listen",
2533                             Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2534                             Summary(NoEvalCall)
2535                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2536                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2537                                 .ArgConstraint(ArgumentCondition(
2538                                     0, WithinRange, Range(0, IntMax))));
2539 
2540     // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
2541     addToFunctionSummaryMap(
2542         "recv",
2543         Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
2544                   RetType{Ssize_tTy}),
2545         Summary(NoEvalCall)
2546             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2547                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2548                   ErrnoMustNotBeChecked)
2549             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2550             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2551             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2552                                       /*BufSize=*/ArgNo(2))));
2553 
2554     Optional<QualType> StructMsghdrTy = lookupTy("msghdr");
2555     Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
2556     Optional<QualType> ConstStructMsghdrPtrTy =
2557         getPointerTy(getConstTy(StructMsghdrTy));
2558 
2559     // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
2560     addToFunctionSummaryMap(
2561         "recvmsg",
2562         Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
2563                   RetType{Ssize_tTy}),
2564         Summary(NoEvalCall)
2565             .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2566                   ErrnoMustNotBeChecked)
2567             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2568             .ArgConstraint(
2569                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2570 
2571     // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
2572     addToFunctionSummaryMap(
2573         "sendmsg",
2574         Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
2575                   RetType{Ssize_tTy}),
2576         Summary(NoEvalCall)
2577             .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2578                   ErrnoMustNotBeChecked)
2579             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2580             .ArgConstraint(
2581                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2582 
2583     // int setsockopt(int socket, int level, int option_name,
2584     //                const void *option_value, socklen_t option_len);
2585     addToFunctionSummaryMap(
2586         "setsockopt",
2587         Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
2588                   RetType{IntTy}),
2589         Summary(NoEvalCall)
2590             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2591             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2592             .ArgConstraint(NotNull(ArgNo(3)))
2593             .ArgConstraint(
2594                 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
2595             .ArgConstraint(
2596                 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
2597 
2598     // int getsockopt(int socket, int level, int option_name,
2599     //                void *restrict option_value,
2600     //                socklen_t *restrict option_len);
2601     addToFunctionSummaryMap(
2602         "getsockopt",
2603         Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
2604                            Socklen_tPtrRestrictTy},
2605                   RetType{IntTy}),
2606         Summary(NoEvalCall)
2607             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2608             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2609             .ArgConstraint(NotNull(ArgNo(3)))
2610             .ArgConstraint(NotNull(ArgNo(4))));
2611 
2612     // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
2613     addToFunctionSummaryMap(
2614         "send",
2615         Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
2616                   RetType{Ssize_tTy}),
2617         Summary(NoEvalCall)
2618             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2619                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2620                   ErrnoMustNotBeChecked)
2621             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2622             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2623             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2624                                       /*BufSize=*/ArgNo(2))));
2625 
2626     // int socketpair(int domain, int type, int protocol, int sv[2]);
2627     addToFunctionSummaryMap(
2628         "socketpair",
2629         Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
2630         Summary(NoEvalCall)
2631             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2632             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2633             .ArgConstraint(NotNull(ArgNo(3))));
2634 
2635     // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
2636     //                 char *restrict node, socklen_t nodelen,
2637     //                 char *restrict service,
2638     //                 socklen_t servicelen, int flags);
2639     //
2640     // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
2641     // parameter is never handled as a transparent union in netdb.h
2642     addToFunctionSummaryMap(
2643         "getnameinfo",
2644         Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
2645                            CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
2646                            Socklen_tTy, IntTy},
2647                   RetType{IntTy}),
2648         Summary(NoEvalCall)
2649             .ArgConstraint(
2650                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2651             .ArgConstraint(
2652                 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
2653             .ArgConstraint(
2654                 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
2655             .ArgConstraint(
2656                 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
2657             .ArgConstraint(
2658                 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
2659             .ArgConstraint(
2660                 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
2661 
2662     Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
2663     Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
2664 
2665     // int utime(const char *filename, struct utimbuf *buf);
2666     addToFunctionSummaryMap(
2667         "utime",
2668         Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
2669         Summary(NoEvalCall)
2670             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2671             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2672             .ArgConstraint(NotNull(ArgNo(0))));
2673 
2674     Optional<QualType> StructTimespecTy = lookupTy("timespec");
2675     Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
2676     Optional<QualType> ConstStructTimespecPtrTy =
2677         getPointerTy(getConstTy(StructTimespecTy));
2678 
2679     // int futimens(int fd, const struct timespec times[2]);
2680     addToFunctionSummaryMap(
2681         "futimens",
2682         Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
2683         Summary(NoEvalCall)
2684             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2685             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2686             .ArgConstraint(
2687                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2688 
2689     // int utimensat(int dirfd, const char *pathname,
2690     //               const struct timespec times[2], int flags);
2691     addToFunctionSummaryMap("utimensat",
2692                             Signature(ArgTypes{IntTy, ConstCharPtrTy,
2693                                                ConstStructTimespecPtrTy, IntTy},
2694                                       RetType{IntTy}),
2695                             Summary(NoEvalCall)
2696                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2697                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2698                                 .ArgConstraint(NotNull(ArgNo(1))));
2699 
2700     Optional<QualType> StructTimevalTy = lookupTy("timeval");
2701     Optional<QualType> ConstStructTimevalPtrTy =
2702         getPointerTy(getConstTy(StructTimevalTy));
2703 
2704     // int utimes(const char *filename, const struct timeval times[2]);
2705     addToFunctionSummaryMap(
2706         "utimes",
2707         Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
2708                   RetType{IntTy}),
2709         Summary(NoEvalCall)
2710             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2711             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2712             .ArgConstraint(NotNull(ArgNo(0))));
2713 
2714     // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
2715     addToFunctionSummaryMap(
2716         "nanosleep",
2717         Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
2718                   RetType{IntTy}),
2719         Summary(NoEvalCall)
2720             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2721             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2722             .ArgConstraint(NotNull(ArgNo(0))));
2723 
2724     Optional<QualType> Time_tTy = lookupTy("time_t");
2725     Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
2726     Optional<QualType> ConstTime_tPtrRestrictTy =
2727         getRestrictTy(ConstTime_tPtrTy);
2728 
2729     Optional<QualType> StructTmTy = lookupTy("tm");
2730     Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
2731     Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
2732     Optional<QualType> ConstStructTmPtrTy =
2733         getPointerTy(getConstTy(StructTmTy));
2734     Optional<QualType> ConstStructTmPtrRestrictTy =
2735         getRestrictTy(ConstStructTmPtrTy);
2736 
2737     // struct tm * localtime(const time_t *tp);
2738     addToFunctionSummaryMap(
2739         "localtime",
2740         Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
2741         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2742 
2743     // struct tm *localtime_r(const time_t *restrict timer,
2744     //                        struct tm *restrict result);
2745     addToFunctionSummaryMap(
2746         "localtime_r",
2747         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
2748                   RetType{StructTmPtrTy}),
2749         Summary(NoEvalCall)
2750             .ArgConstraint(NotNull(ArgNo(0)))
2751             .ArgConstraint(NotNull(ArgNo(1))));
2752 
2753     // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
2754     addToFunctionSummaryMap(
2755         "asctime_r",
2756         Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
2757                   RetType{CharPtrTy}),
2758         Summary(NoEvalCall)
2759             .ArgConstraint(NotNull(ArgNo(0)))
2760             .ArgConstraint(NotNull(ArgNo(1)))
2761             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2762                                       /*MinBufSize=*/BVF.getValue(26, IntTy))));
2763 
2764     // char *ctime_r(const time_t *timep, char *buf);
2765     addToFunctionSummaryMap(
2766         "ctime_r",
2767         Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
2768         Summary(NoEvalCall)
2769             .ArgConstraint(NotNull(ArgNo(0)))
2770             .ArgConstraint(NotNull(ArgNo(1)))
2771             .ArgConstraint(BufferSize(
2772                 /*Buffer=*/ArgNo(1),
2773                 /*MinBufSize=*/BVF.getValue(26, IntTy))));
2774 
2775     // struct tm *gmtime_r(const time_t *restrict timer,
2776     //                     struct tm *restrict result);
2777     addToFunctionSummaryMap(
2778         "gmtime_r",
2779         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
2780                   RetType{StructTmPtrTy}),
2781         Summary(NoEvalCall)
2782             .ArgConstraint(NotNull(ArgNo(0)))
2783             .ArgConstraint(NotNull(ArgNo(1))));
2784 
2785     // struct tm * gmtime(const time_t *tp);
2786     addToFunctionSummaryMap(
2787         "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
2788         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2789 
2790     Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
2791 
2792     // int clock_gettime(clockid_t clock_id, struct timespec *tp);
2793     addToFunctionSummaryMap(
2794         "clock_gettime",
2795         Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
2796         Summary(NoEvalCall)
2797             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2798             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2799             .ArgConstraint(NotNull(ArgNo(1))));
2800 
2801     Optional<QualType> StructItimervalTy = lookupTy("itimerval");
2802     Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
2803 
2804     // int getitimer(int which, struct itimerval *curr_value);
2805     addToFunctionSummaryMap(
2806         "getitimer",
2807         Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
2808         Summary(NoEvalCall)
2809             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2810             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2811             .ArgConstraint(NotNull(ArgNo(1))));
2812 
2813     Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
2814     Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy);
2815     Optional<QualType> Pthread_tTy = lookupTy("pthread_t");
2816     Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
2817     Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy);
2818     Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
2819     Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy);
2820     Optional<QualType> Pthread_mutex_tPtrRestrictTy =
2821         getRestrictTy(Pthread_mutex_tPtrTy);
2822     Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
2823     Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy);
2824     Optional<QualType> ConstPthread_attr_tPtrTy =
2825         getPointerTy(getConstTy(Pthread_attr_tTy));
2826     Optional<QualType> ConstPthread_attr_tPtrRestrictTy =
2827         getRestrictTy(ConstPthread_attr_tPtrTy);
2828     Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t");
2829     Optional<QualType> ConstPthread_mutexattr_tPtrTy =
2830         getPointerTy(getConstTy(Pthread_mutexattr_tTy));
2831     Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
2832         getRestrictTy(ConstPthread_mutexattr_tPtrTy);
2833 
2834     QualType PthreadStartRoutineTy = getPointerTy(
2835         ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
2836                              FunctionProtoType::ExtProtoInfo()));
2837 
2838     // int pthread_cond_signal(pthread_cond_t *cond);
2839     // int pthread_cond_broadcast(pthread_cond_t *cond);
2840     addToFunctionSummaryMap(
2841         {"pthread_cond_signal", "pthread_cond_broadcast"},
2842         Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
2843         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2844 
2845     // int pthread_create(pthread_t *restrict thread,
2846     //                    const pthread_attr_t *restrict attr,
2847     //                    void *(*start_routine)(void*), void *restrict arg);
2848     addToFunctionSummaryMap(
2849         "pthread_create",
2850         Signature(ArgTypes{Pthread_tPtrRestrictTy,
2851                            ConstPthread_attr_tPtrRestrictTy,
2852                            PthreadStartRoutineTy, VoidPtrRestrictTy},
2853                   RetType{IntTy}),
2854         Summary(NoEvalCall)
2855             .ArgConstraint(NotNull(ArgNo(0)))
2856             .ArgConstraint(NotNull(ArgNo(2))));
2857 
2858     // int pthread_attr_destroy(pthread_attr_t *attr);
2859     // int pthread_attr_init(pthread_attr_t *attr);
2860     addToFunctionSummaryMap(
2861         {"pthread_attr_destroy", "pthread_attr_init"},
2862         Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
2863         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2864 
2865     // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
2866     //                               size_t *restrict stacksize);
2867     // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
2868     //                               size_t *restrict guardsize);
2869     addToFunctionSummaryMap(
2870         {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
2871         Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
2872                   RetType{IntTy}),
2873         Summary(NoEvalCall)
2874             .ArgConstraint(NotNull(ArgNo(0)))
2875             .ArgConstraint(NotNull(ArgNo(1))));
2876 
2877     // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
2878     // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
2879     addToFunctionSummaryMap(
2880         {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
2881         Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
2882         Summary(NoEvalCall)
2883             .ArgConstraint(NotNull(ArgNo(0)))
2884             .ArgConstraint(
2885                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2886 
2887     // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
2888     //                        pthread_mutexattr_t *restrict attr);
2889     addToFunctionSummaryMap(
2890         "pthread_mutex_init",
2891         Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
2892                            ConstPthread_mutexattr_tPtrRestrictTy},
2893                   RetType{IntTy}),
2894         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2895 
2896     // int pthread_mutex_destroy(pthread_mutex_t *mutex);
2897     // int pthread_mutex_lock(pthread_mutex_t *mutex);
2898     // int pthread_mutex_trylock(pthread_mutex_t *mutex);
2899     // int pthread_mutex_unlock(pthread_mutex_t *mutex);
2900     addToFunctionSummaryMap(
2901         {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
2902          "pthread_mutex_unlock"},
2903         Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
2904         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2905   }
2906 
2907   // Functions for testing.
2908   if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
2909     addToFunctionSummaryMap(
2910         "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2911         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
2912 
2913     // Test range values.
2914     addToFunctionSummaryMap(
2915         "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2916         Summary(EvalCallAsPure)
2917             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
2918     addToFunctionSummaryMap(
2919         "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2920         Summary(EvalCallAsPure)
2921             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
2922     addToFunctionSummaryMap(
2923         "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2924         Summary(EvalCallAsPure)
2925             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
2926     addToFunctionSummaryMap("__range_1_2__4_5",
2927                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
2928                             Summary(EvalCallAsPure)
2929                                 .ArgConstraint(ArgumentCondition(
2930                                     0U, WithinRange, Range({1, 2}, {4, 5}))));
2931 
2932     // Test range kind.
2933     addToFunctionSummaryMap(
2934         "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2935         Summary(EvalCallAsPure)
2936             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
2937     addToFunctionSummaryMap(
2938         "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2939         Summary(EvalCallAsPure)
2940             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
2941 
2942     addToFunctionSummaryMap(
2943         "__two_constrained_args",
2944         Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2945         Summary(EvalCallAsPure)
2946             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
2947             .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
2948     addToFunctionSummaryMap(
2949         "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2950         Summary(EvalCallAsPure)
2951             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
2952             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
2953     addToFunctionSummaryMap(
2954         "__defaultparam",
2955         Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
2956         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
2957     addToFunctionSummaryMap(
2958         "__variadic",
2959         Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2960         Summary(EvalCallAsPure)
2961             .ArgConstraint(NotNull(ArgNo(0)))
2962             .ArgConstraint(NotNull(ArgNo(1))));
2963     addToFunctionSummaryMap(
2964         "__buf_size_arg_constraint",
2965         Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
2966         Summary(EvalCallAsPure)
2967             .ArgConstraint(
2968                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
2969     addToFunctionSummaryMap(
2970         "__buf_size_arg_constraint_mul",
2971         Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
2972         Summary(EvalCallAsPure)
2973             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2974                                       /*BufSizeMultiplier=*/ArgNo(2))));
2975     addToFunctionSummaryMap(
2976         "__buf_size_arg_constraint_concrete",
2977         Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
2978         Summary(EvalCallAsPure)
2979             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
2980                                       /*BufSize=*/BVF.getValue(10, IntTy))));
2981     addToFunctionSummaryMap(
2982         {"__test_restrict_param_0", "__test_restrict_param_1",
2983          "__test_restrict_param_2"},
2984         Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
2985         Summary(EvalCallAsPure));
2986   }
2987 
2988   SummariesInitialized = true;
2989 }
2990 
2991 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
2992   auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
2993   const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
2994   Checker->DisplayLoadedSummaries =
2995       Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
2996   Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
2997   Checker->ShouldAssumeControlledEnvironment =
2998       Opts.ShouldAssumeControlledEnvironment;
2999 }
3000 
3001 bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3002     const CheckerManager &mgr) {
3003   return true;
3004 }
3005 
3006 #define REGISTER_CHECKER(name)                                                 \
3007   void ento::register##name(CheckerManager &mgr) {                             \
3008     StdLibraryFunctionsChecker *checker =                                      \
3009         mgr.getChecker<StdLibraryFunctionsChecker>();                          \
3010     checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true;      \
3011     checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] =               \
3012         mgr.getCurrentCheckerName();                                           \
3013   }                                                                            \
3014                                                                                \
3015   bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
3016 
3017 REGISTER_CHECKER(StdCLibraryFunctionArgsChecker)
3018 REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker)
3019