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