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