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