xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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 effects), 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 NullnessConstraint : 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     NullnessConstraint(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       NullnessConstraint Tmp(*this);
393       Tmp.CannotBeNull = !this->CannotBeNull;
394       return std::make_shared<NullnessConstraint>(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. Otherwise, the buffer pointer must be non-null. This is useful
411   /// for functions like `fread` which have this special property.
412   class BufferNullnessConstraint : 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     BufferNullnessConstraint(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       BufferNullnessConstraint Tmp(*this);
440       Tmp.CannotBeNull = !this->CannotBeNull;
441       return std::make_shared<BufferNullnessConstraint>(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 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 = SVB.conjureSymbolVal(Call, C.getASTContext().IntTy,
588                                               C.blockCount(), &Tag)
589                              .castAs<NonLoc>();
590       return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
591     }
592   };
593 
594   /// Set errno constraint at success cases of standard functions.
595   /// Success case: 'errno' is not allowed to be used because the value is
596   /// undefined after successful call.
597   /// \c ErrnoChecker can emit bug report after such a function call if errno
598   /// is used.
599   class SuccessErrnoConstraint : public ErrnoConstraintBase {
600   public:
601     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
602                           const Summary &Summary,
603                           CheckerContext &C) const override {
604       return errno_modeling::setErrnoForStdSuccess(State, C);
605     }
606 
607     std::string describe(CheckerContext &C) const override {
608       return "'errno' becomes undefined after the call";
609     }
610   };
611 
612   /// Set errno constraint at functions that indicate failure only with 'errno'.
613   /// In this case 'errno' is required to be observed.
614   /// \c ErrnoChecker can emit bug report after such a function call if errno
615   /// is overwritten without a read before.
616   class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
617   public:
618     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
619                           const Summary &Summary,
620                           CheckerContext &C) const override {
621       return errno_modeling::setErrnoStdMustBeChecked(State, C,
622                                                       Call.getCFGElementRef());
623     }
624 
625     std::string describe(CheckerContext &C) const override {
626       return "reading 'errno' is required to find out if the call has failed";
627     }
628   };
629 
630   /// A single branch of a function summary.
631   ///
632   /// A branch is defined by a series of constraints - "assumptions" -
633   /// that together form a single possible outcome of invoking the function.
634   /// When static analyzer considers a branch, it tries to introduce
635   /// a child node in the Exploded Graph. The child node has to include
636   /// constraints that define the branch. If the constraints contradict
637   /// existing constraints in the state, the node is not created and the branch
638   /// is dropped; otherwise it's queued for future exploration.
639   /// The branch is accompanied by a note text that may be displayed
640   /// to the user when a bug is found on a path that takes this branch.
641   ///
642   /// For example, consider the branches in `isalpha(x)`:
643   ///   Branch 1)
644   ///     x is in range ['A', 'Z'] or in ['a', 'z']
645   ///     then the return value is not 0. (I.e. out-of-range [0, 0])
646   ///     and the note may say "Assuming the character is alphabetical"
647   ///   Branch 2)
648   ///     x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
649   ///     then the return value is 0
650   ///     and the note may say "Assuming the character is non-alphabetical".
651   class SummaryCase {
652     ConstraintSet Constraints;
653     const ErrnoConstraintBase &ErrnoConstraint;
654     StringRef Note;
655 
656   public:
657     SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,
658                 StringRef Note)
659         : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),
660           Note(Note) {}
661 
662     SummaryCase(const ConstraintSet &Constraints,
663                 const ErrnoConstraintBase &ErrnoC, StringRef Note)
664         : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}
665 
666     const ConstraintSet &getConstraints() const { return Constraints; }
667     const ErrnoConstraintBase &getErrnoConstraint() const {
668       return ErrnoConstraint;
669     }
670     StringRef getNote() const { return Note; }
671   };
672 
673   using ArgTypes = ArrayRef<std::optional<QualType>>;
674   using RetType = std::optional<QualType>;
675 
676   // A placeholder type, we use it whenever we do not care about the concrete
677   // type in a Signature.
678   const QualType Irrelevant{};
679   bool static isIrrelevant(QualType T) { return T.isNull(); }
680 
681   // The signature of a function we want to describe with a summary. This is a
682   // concessive signature, meaning there may be irrelevant types in the
683   // signature which we do not check against a function with concrete types.
684   // All types in the spec need to be canonical.
685   class Signature {
686     using ArgQualTypes = std::vector<QualType>;
687     ArgQualTypes ArgTys;
688     QualType RetTy;
689     // True if any component type is not found by lookup.
690     bool Invalid = false;
691 
692   public:
693     // Construct a signature from optional types. If any of the optional types
694     // are not set then the signature will be invalid.
695     Signature(ArgTypes ArgTys, RetType RetTy) {
696       for (std::optional<QualType> Arg : ArgTys) {
697         if (!Arg) {
698           Invalid = true;
699           return;
700         } else {
701           assertArgTypeSuitableForSignature(*Arg);
702           this->ArgTys.push_back(*Arg);
703         }
704       }
705       if (!RetTy) {
706         Invalid = true;
707         return;
708       } else {
709         assertRetTypeSuitableForSignature(*RetTy);
710         this->RetTy = *RetTy;
711       }
712     }
713 
714     bool isInvalid() const { return Invalid; }
715     bool matches(const FunctionDecl *FD) const;
716 
717   private:
718     static void assertArgTypeSuitableForSignature(QualType T) {
719       assert((T.isNull() || !T->isVoidType()) &&
720              "We should have no void types in the spec");
721       assert((T.isNull() || T.isCanonical()) &&
722              "We should only have canonical types in the spec");
723     }
724     static void assertRetTypeSuitableForSignature(QualType T) {
725       assert((T.isNull() || T.isCanonical()) &&
726              "We should only have canonical types in the spec");
727     }
728   };
729 
730   static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
731     assert(FD && "Function must be set");
732     QualType T = (ArgN == Ret)
733                      ? FD->getReturnType().getCanonicalType()
734                      : FD->getParamDecl(ArgN)->getType().getCanonicalType();
735     return T;
736   }
737 
738   using SummaryCases = std::vector<SummaryCase>;
739 
740   /// A summary includes information about
741   ///   * function prototype (signature)
742   ///   * approach to invalidation,
743   ///   * a list of branches - so, a list of list of ranges,
744   ///   * a list of argument constraints, that must be true on every branch.
745   ///     If these constraints are not satisfied that means a fatal error
746   ///     usually resulting in undefined behaviour.
747   ///
748   /// Application of a summary:
749   ///   The signature and argument constraints together contain information
750   ///   about which functions are handled by the summary. The signature can use
751   ///   "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
752   ///   a signature means that type is not compared to the type of the parameter
753   ///   in the found FunctionDecl. Argument constraints may specify additional
754   ///   rules for the given parameter's type, those rules are checked once the
755   ///   signature is matched.
756   class Summary {
757     const InvalidationKind InvalidationKd;
758     SummaryCases Cases;
759     ConstraintSet ArgConstraints;
760 
761     // The function to which the summary applies. This is set after lookup and
762     // match to the signature.
763     const FunctionDecl *FD = nullptr;
764 
765   public:
766     Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
767 
768     Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,
769                   StringRef Note = "") {
770       Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));
771       return *this;
772     }
773     Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,
774                   StringRef Note = "") {
775       Cases.push_back(SummaryCase(CS, ErrnoC, Note));
776       return *this;
777     }
778     Summary &ArgConstraint(ValueConstraintPtr VC) {
779       assert(VC->getArgNo() != Ret &&
780              "Arg constraint should not refer to the return value");
781       ArgConstraints.push_back(VC);
782       return *this;
783     }
784 
785     InvalidationKind getInvalidationKd() const { return InvalidationKd; }
786     const SummaryCases &getCases() const { return Cases; }
787     const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
788 
789     QualType getArgType(ArgNo ArgN) const {
790       return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
791     }
792 
793     // Returns true if the summary should be applied to the given function.
794     // And if yes then store the function declaration.
795     bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
796       bool Result = Sign.matches(FD) && validateByConstraints(FD);
797       if (Result) {
798         assert(!this->FD && "FD must not be set more than once");
799         this->FD = FD;
800       }
801       return Result;
802     }
803 
804   private:
805     // Once we know the exact type of the function then do validation check on
806     // all the given constraints.
807     bool validateByConstraints(const FunctionDecl *FD) const {
808       for (const SummaryCase &Case : Cases)
809         for (const ValueConstraintPtr &Constraint : Case.getConstraints())
810           if (!Constraint->checkValidity(FD))
811             return false;
812       for (const ValueConstraintPtr &Constraint : ArgConstraints)
813         if (!Constraint->checkValidity(FD))
814           return false;
815       return true;
816     }
817   };
818 
819   // The map of all functions supported by the checker. It is initialized
820   // lazily, and it doesn't change after initialization.
821   using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
822   mutable FunctionSummaryMapType FunctionSummaryMap;
823 
824   const BugType BT_InvalidArg{this, "Function call with invalid argument"};
825   mutable bool SummariesInitialized = false;
826 
827   static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
828     return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
829   }
830   static std::string getFunctionName(const CallEvent &Call) {
831     assert(Call.getDecl() &&
832            "Call was found by a summary, should have declaration");
833     return cast<NamedDecl>(Call.getDecl())->getNameAsString();
834   }
835 
836 public:
837   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
838   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
839   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
840 
841   CheckerNameRef CheckName;
842   bool AddTestFunctions = false;
843 
844   bool DisplayLoadedSummaries = false;
845   bool ModelPOSIX = false;
846   bool ShouldAssumeControlledEnvironment = false;
847 
848 private:
849   std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,
850                                              CheckerContext &C) const;
851   std::optional<Summary> findFunctionSummary(const CallEvent &Call,
852                                              CheckerContext &C) const;
853 
854   void initFunctionSummaries(CheckerContext &C) const;
855 
856   void reportBug(const CallEvent &Call, ExplodedNode *N,
857                  const ValueConstraint *VC, const ValueConstraint *NegatedVC,
858                  const Summary &Summary, CheckerContext &C) const {
859     assert(Call.getDecl() &&
860            "Function found in summary must have a declaration available");
861     SmallString<256> Msg;
862     llvm::raw_svector_ostream MsgOs(Msg);
863 
864     MsgOs << "The ";
865     printArgDesc(VC->getArgNo(), MsgOs);
866     MsgOs << " to '" << getFunctionName(Call) << "' ";
867     bool ValuesPrinted =
868         NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);
869     if (ValuesPrinted)
870       MsgOs << " but ";
871     else
872       MsgOs << "is out of the accepted range; It ";
873     VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,
874                  MsgOs);
875     Msg[0] = toupper(Msg[0]);
876     auto R = std::make_unique<PathSensitiveBugReport>(BT_InvalidArg, Msg, N);
877 
878     for (ArgNo ArgN : VC->getArgsToTrack()) {
879       bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
880       R->markInteresting(Call.getArgSVal(ArgN));
881       // All tracked arguments are important, highlight them.
882       R->addRange(Call.getArgSourceRange(ArgN));
883     }
884 
885     C.emitReport(std::move(R));
886   }
887 
888   /// These are the errno constraints that can be passed to summary cases.
889   /// One of these should fit for a single summary case.
890   /// Usually if a failure return value exists for function, that function
891   /// needs different cases for success and failure with different errno
892   /// constraints (and different return value constraints).
893   const NoErrnoConstraint ErrnoUnchanged{};
894   const ResetErrnoConstraint ErrnoIrrelevant{};
895   const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
896   const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
897   const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
898 };
899 
900 int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
901 
902 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
903     std::numeric_limits<ArgNo>::max();
904 
905 static BasicValueFactory &getBVF(ProgramStateRef State) {
906   ProgramStateManager &Mgr = State->getStateManager();
907   SValBuilder &SVB = Mgr.getSValBuilder();
908   return SVB.getBasicValueFactory();
909 }
910 
911 } // end of anonymous namespace
912 
913 void StdLibraryFunctionsChecker::printArgDesc(
914     StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
915   Out << std::to_string(ArgN + 1);
916   Out << llvm::getOrdinalSuffix(ArgN + 1);
917   Out << " argument";
918 }
919 
920 void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
921                                                    ProgramStateRef State,
922                                                    const CallEvent &Call,
923                                                    llvm::raw_ostream &Out) {
924   if (const llvm::APSInt *Val =
925           State->getStateManager().getSValBuilder().getKnownValue(
926               State, getArgSVal(Call, ArgN)))
927     Out << " (which is " << *Val << ")";
928 }
929 
930 void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
931                                                        llvm::APSInt RMax,
932                                                        QualType ArgT,
933                                                        BasicValueFactory &BVF,
934                                                        llvm::raw_ostream &Out) {
935   if (RMin.isZero() && RMax.isZero())
936     Out << "zero";
937   else if (RMin == RMax)
938     Out << RMin;
939   else if (RMin == BVF.getMinValue(ArgT)) {
940     if (RMax == -1)
941       Out << "< 0";
942     else
943       Out << "<= " << RMax;
944   } else if (RMax == BVF.getMaxValue(ArgT)) {
945     if (RMin.isOne())
946       Out << "> 0";
947     else
948       Out << ">= " << RMin;
949   } else if (RMin.isNegative() == RMax.isNegative() &&
950              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
951     Out << RMin << " or " << RMax;
952   } else {
953     Out << "between " << RMin << " and " << RMax;
954   }
955 }
956 
957 void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
958                                                       llvm::APSInt RMax,
959                                                       QualType ArgT,
960                                                       BasicValueFactory &BVF,
961                                                       llvm::raw_ostream &Out) {
962   if (RMin.isZero() && RMax.isZero())
963     Out << "nonzero";
964   else if (RMin == RMax) {
965     Out << "not equal to " << RMin;
966   } else if (RMin == BVF.getMinValue(ArgT)) {
967     if (RMax == -1)
968       Out << ">= 0";
969     else
970       Out << "> " << RMax;
971   } else if (RMax == BVF.getMaxValue(ArgT)) {
972     if (RMin.isOne())
973       Out << "<= 0";
974     else
975       Out << "< " << RMin;
976   } else if (RMin.isNegative() == RMax.isNegative() &&
977              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
978     Out << "not " << RMin << " and not " << RMax;
979   } else {
980     Out << "not between " << RMin << " and " << RMax;
981   }
982 }
983 
984 void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
985     BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
986   if (Ranges.empty())
987     return;
988 
989   for (auto [Start, End] : getRanges()) {
990     const llvm::APSInt &Min = BVF.getValue(Start, ArgT);
991     const llvm::APSInt &Max = BVF.getValue(End, ArgT);
992     assert(Min <= Max);
993     if (!F(Min, Max))
994       return;
995   }
996 }
997 
998 void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
999     BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
1000   if (Ranges.empty())
1001     return;
1002 
1003   const IntRangeVector &R = getRanges();
1004   size_t E = R.size();
1005 
1006   const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);
1007   const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);
1008 
1009   const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);
1010   const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);
1011 
1012   // Iterate over the "holes" between intervals.
1013   for (size_t I = 1; I != E; ++I) {
1014     const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);
1015     const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);
1016     if (Min <= Max) {
1017       if (!F(Min, Max))
1018         return;
1019     }
1020   }
1021   // Check the interval [T_MIN, min(R) - 1].
1022   if (RangeLeft != PlusInf) {
1023     assert(MinusInf <= RangeLeft);
1024     if (!F(MinusInf, RangeLeft))
1025       return;
1026   }
1027   // Check the interval [max(R) + 1, T_MAX],
1028   if (RangeRight != MinusInf) {
1029     assert(RangeRight <= PlusInf);
1030     if (!F(RangeRight, PlusInf))
1031       return;
1032   }
1033 }
1034 
1035 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
1036     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1037     CheckerContext &C) const {
1038   ConstraintManager &CM = C.getConstraintManager();
1039   SVal V = getArgSVal(Call, getArgNo());
1040   QualType T = Summary.getArgType(getArgNo());
1041 
1042   if (auto N = V.getAs<NonLoc>()) {
1043     auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,
1044                                    const llvm::APSInt &Max) {
1045       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
1046       return static_cast<bool>(State);
1047     };
1048     // "OutOfRange R" is handled by excluding all ranges in R.
1049     // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
1050     applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,
1051                  ExcludeRangeFromArg);
1052   }
1053 
1054   return State;
1055 }
1056 
1057 void StdLibraryFunctionsChecker::RangeConstraint::describe(
1058     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1059     const Summary &Summary, llvm::raw_ostream &Out) const {
1060 
1061   BasicValueFactory &BVF = getBVF(State);
1062   QualType T = Summary.getArgType(getArgNo());
1063 
1064   Out << ((DK == Violation) ? "should be " : "is ");
1065   if (!Description.empty()) {
1066     Out << Description;
1067   } else {
1068     unsigned I = Ranges.size();
1069     if (Kind == WithinRange) {
1070       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1071         appendInsideRangeDesc(BVF.getValue(R.first, T),
1072                               BVF.getValue(R.second, T), T, BVF, Out);
1073         if (--I > 0)
1074           Out << " or ";
1075       }
1076     } else {
1077       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1078         appendOutOfRangeDesc(BVF.getValue(R.first, T),
1079                              BVF.getValue(R.second, T), T, BVF, Out);
1080         if (--I > 0)
1081           Out << " and ";
1082       }
1083     }
1084   }
1085 }
1086 
1087 bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
1088     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1089     llvm::raw_ostream &Out) const {
1090   unsigned int NRanges = 0;
1091   bool HaveAllRanges = true;
1092 
1093   ProgramStateManager &Mgr = State->getStateManager();
1094   BasicValueFactory &BVF = Mgr.getSValBuilder().getBasicValueFactory();
1095   ConstraintManager &CM = Mgr.getConstraintManager();
1096   SVal V = getArgSVal(Call, getArgNo());
1097 
1098   if (auto N = V.getAs<NonLoc>()) {
1099     if (const llvm::APSInt *Int = N->getAsInteger()) {
1100       Out << "is ";
1101       Out << *Int;
1102       return true;
1103     }
1104     QualType T = Summary.getArgType(getArgNo());
1105     SmallString<128> MoreInfo;
1106     llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
1107     auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
1108       if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
1109         if (NRanges > 0)
1110           MoreInfoOs << " or ";
1111         appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
1112         ++NRanges;
1113       } else {
1114         HaveAllRanges = false;
1115       }
1116       return true;
1117     };
1118 
1119     applyOnRange(Kind, BVF, T, ApplyF);
1120     assert(NRanges > 0);
1121     if (!HaveAllRanges || NRanges == 1) {
1122       Out << "is ";
1123       Out << MoreInfo;
1124       return true;
1125     }
1126   }
1127   return false;
1128 }
1129 
1130 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
1131     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1132     CheckerContext &C) const {
1133 
1134   ProgramStateManager &Mgr = State->getStateManager();
1135   SValBuilder &SVB = Mgr.getSValBuilder();
1136   QualType CondT = SVB.getConditionType();
1137   QualType T = Summary.getArgType(getArgNo());
1138   SVal V = getArgSVal(Call, getArgNo());
1139 
1140   BinaryOperator::Opcode Op = getOpcode();
1141   ArgNo OtherArg = getOtherArgNo();
1142   SVal OtherV = getArgSVal(Call, OtherArg);
1143   QualType OtherT = Summary.getArgType(OtherArg);
1144   // Note: we avoid integral promotion for comparison.
1145   OtherV = SVB.evalCast(OtherV, T, OtherT);
1146   if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
1147                        .getAs<DefinedOrUnknownSVal>())
1148     State = State->assume(*CompV, true);
1149   return State;
1150 }
1151 
1152 ProgramStateRef StdLibraryFunctionsChecker::NullnessConstraint::apply(
1153     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1154     CheckerContext &C) const {
1155   SVal V = getArgSVal(Call, getArgNo());
1156   if (V.isUndef())
1157     return State;
1158 
1159   DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1160   if (!isa<Loc>(L))
1161     return State;
1162 
1163   return State->assume(L, CannotBeNull);
1164 }
1165 
1166 void StdLibraryFunctionsChecker::NullnessConstraint::describe(
1167     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1168     const Summary &Summary, llvm::raw_ostream &Out) const {
1169   assert(CannotBeNull &&
1170          "'describe' is not implemented when the value must be NULL");
1171   if (DK == Violation)
1172     Out << "should not be NULL";
1173   else
1174     Out << "is not NULL";
1175 }
1176 
1177 bool StdLibraryFunctionsChecker::NullnessConstraint::describeArgumentValue(
1178     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1179     llvm::raw_ostream &Out) const {
1180   assert(!CannotBeNull && "'describeArgumentValue' is not implemented when the "
1181                           "value must be non-NULL");
1182   Out << "is NULL";
1183   return true;
1184 }
1185 
1186 ProgramStateRef StdLibraryFunctionsChecker::BufferNullnessConstraint::apply(
1187     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1188     CheckerContext &C) const {
1189   SVal V = getArgSVal(Call, getArgNo());
1190   if (V.isUndef())
1191     return State;
1192   DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1193   if (!isa<Loc>(L))
1194     return State;
1195 
1196   std::optional<DefinedOrUnknownSVal> SizeArg1 =
1197       getArgSVal(Call, SizeArg1N).getAs<DefinedOrUnknownSVal>();
1198   std::optional<DefinedOrUnknownSVal> SizeArg2;
1199   if (SizeArg2N)
1200     SizeArg2 = getArgSVal(Call, *SizeArg2N).getAs<DefinedOrUnknownSVal>();
1201 
1202   auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {
1203     if (!Val)
1204       return false;
1205     auto [IsNonNull, IsNull] = State->assume(*Val);
1206     return IsNull && !IsNonNull;
1207   };
1208 
1209   if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))
1210     return State;
1211 
1212   return State->assume(L, CannotBeNull);
1213 }
1214 
1215 void StdLibraryFunctionsChecker::BufferNullnessConstraint::describe(
1216     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1217     const Summary &Summary, llvm::raw_ostream &Out) const {
1218   assert(CannotBeNull &&
1219          "'describe' is not implemented when the buffer must be NULL");
1220   if (DK == Violation)
1221     Out << "should not be NULL";
1222   else
1223     Out << "is not NULL";
1224 }
1225 
1226 bool StdLibraryFunctionsChecker::BufferNullnessConstraint::
1227     describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
1228                           const Summary &Summary,
1229                           llvm::raw_ostream &Out) const {
1230   assert(!CannotBeNull && "'describeArgumentValue' is not implemented when the "
1231                           "buffer must be non-NULL");
1232   Out << "is NULL";
1233   return true;
1234 }
1235 
1236 ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
1237     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1238     CheckerContext &C) const {
1239   SValBuilder &SvalBuilder = C.getSValBuilder();
1240   // The buffer argument.
1241   SVal BufV = getArgSVal(Call, getArgNo());
1242 
1243   // Get the size constraint.
1244   const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
1245     if (ConcreteSize) {
1246       return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
1247     }
1248     assert(SizeArgN && "The constraint must be either a concrete value or "
1249                        "encoded in an argument.");
1250     // The size argument.
1251     SVal SizeV = getArgSVal(Call, *SizeArgN);
1252     // Multiply with another argument if given.
1253     if (SizeMultiplierArgN) {
1254       SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
1255       SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
1256                                     Summary.getArgType(*SizeArgN));
1257     }
1258     return SizeV;
1259   }();
1260 
1261   // The dynamic size of the buffer argument, got from the analyzer engine.
1262   SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1263 
1264   SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
1265                                         SvalBuilder.getContext().BoolTy);
1266   if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
1267     return State->assume(*F, true);
1268 
1269   // We can get here only if the size argument or the dynamic size is
1270   // undefined. But the dynamic size should never be undefined, only
1271   // unknown. So, here, the size of the argument is undefined, i.e. we
1272   // cannot apply the constraint. Actually, other checkers like
1273   // CallAndMessage should catch this situation earlier, because we call a
1274   // function with an uninitialized argument.
1275   llvm_unreachable("Size argument or the dynamic size is Undefined");
1276 }
1277 
1278 void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
1279     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1280     const Summary &Summary, llvm::raw_ostream &Out) const {
1281   Out << ((DK == Violation) ? "should be " : "is ");
1282   Out << "a buffer with size equal to or greater than ";
1283   if (ConcreteSize) {
1284     Out << *ConcreteSize;
1285   } else if (SizeArgN) {
1286     Out << "the value of the ";
1287     printArgDesc(*SizeArgN, Out);
1288     printArgValueInfo(*SizeArgN, State, Call, Out);
1289     if (SizeMultiplierArgN) {
1290       Out << " times the ";
1291       printArgDesc(*SizeMultiplierArgN, Out);
1292       printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
1293     }
1294   }
1295 }
1296 
1297 bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
1298     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1299     llvm::raw_ostream &Out) const {
1300   SVal BufV = getArgSVal(Call, getArgNo());
1301   SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1302   if (const llvm::APSInt *Val =
1303           State->getStateManager().getSValBuilder().getKnownValue(State,
1304                                                                   BufDynSize)) {
1305     Out << "is a buffer with size " << *Val;
1306     return true;
1307   }
1308   return false;
1309 }
1310 
1311 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
1312                                               CheckerContext &C) const {
1313   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1314   if (!FoundSummary)
1315     return;
1316 
1317   const Summary &Summary = *FoundSummary;
1318   ProgramStateRef State = C.getState();
1319 
1320   ProgramStateRef NewState = State;
1321   ExplodedNode *NewNode = C.getPredecessor();
1322   for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
1323     ValueConstraintPtr NegatedConstraint = Constraint->negate();
1324     ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
1325     ProgramStateRef FailureSt =
1326         NegatedConstraint->apply(NewState, Call, Summary, C);
1327     // The argument constraint is not satisfied.
1328     if (FailureSt && !SuccessSt) {
1329       if (ExplodedNode *N = C.generateErrorNode(State, NewNode))
1330         reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,
1331                   C);
1332       break;
1333     }
1334     // We will apply the constraint even if we cannot reason about the
1335     // argument. This means both SuccessSt and FailureSt can be true. If we
1336     // weren't applying the constraint that would mean that symbolic
1337     // execution continues on a code whose behaviour is undefined.
1338     assert(SuccessSt);
1339     NewState = SuccessSt;
1340     if (NewState != State) {
1341       SmallString<128> Msg;
1342       llvm::raw_svector_ostream Os(Msg);
1343       Os << "Assuming that the ";
1344       printArgDesc(Constraint->getArgNo(), Os);
1345       Os << " to '";
1346       Os << getFunctionName(Call);
1347       Os << "' ";
1348       Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
1349                            Os);
1350       const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
1351       NewNode = C.addTransition(
1352           NewState, NewNode,
1353           C.getNoteTag([Msg = std::move(Msg), ArgSVal](
1354                            PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1355             if (BR.isInteresting(ArgSVal))
1356               OS << Msg;
1357           }));
1358     }
1359   }
1360 }
1361 
1362 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
1363                                                CheckerContext &C) const {
1364   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1365   if (!FoundSummary)
1366     return;
1367 
1368   // Now apply the constraints.
1369   const Summary &Summary = *FoundSummary;
1370   ProgramStateRef State = C.getState();
1371   ExplodedNode *Node = C.getPredecessor();
1372 
1373   // Apply case/branch specifications.
1374   for (const SummaryCase &Case : Summary.getCases()) {
1375     ProgramStateRef NewState = State;
1376     for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
1377       NewState = Constraint->apply(NewState, Call, Summary, C);
1378       if (!NewState)
1379         break;
1380     }
1381 
1382     if (NewState)
1383       NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
1384 
1385     if (!NewState)
1386       continue;
1387 
1388     // Here it's possible that NewState == State, e.g. when other checkers
1389     // already applied the same constraints (or stricter ones).
1390     // Still add these note tags, the other checker should add only its
1391     // specialized note tags. These general note tags are handled always by
1392     // StdLibraryFunctionsChecker.
1393 
1394     ExplodedNode *Pred = Node;
1395     DeclarationName FunctionName =
1396         cast<NamedDecl>(Call.getDecl())->getDeclName();
1397 
1398     std::string ErrnoNote = Case.getErrnoConstraint().describe(C);
1399     std::string CaseNote;
1400     if (Case.getNote().empty()) {
1401       if (!ErrnoNote.empty())
1402         ErrnoNote =
1403             llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);
1404     } else {
1405       // Disable formatv() validation as the case note may not always have the
1406       // {0} placeholder for function name.
1407       CaseNote =
1408           llvm::formatv(false, 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(Call, C.blockCount());
1483     State = State->BindExpr(CE, LC, V);
1484 
1485     C.addTransition(State);
1486 
1487     return true;
1488   }
1489   case NoEvalCall:
1490     // Summary tells us to avoid performing eval::Call. The function is possibly
1491     // evaluated by another checker, or evaluated conservatively.
1492     return false;
1493   }
1494   llvm_unreachable("Unknown invalidation kind!");
1495 }
1496 
1497 bool StdLibraryFunctionsChecker::Signature::matches(
1498     const FunctionDecl *FD) const {
1499   assert(!isInvalid());
1500   // Check the number of arguments.
1501   if (FD->param_size() != ArgTys.size())
1502     return false;
1503 
1504   // The "restrict" keyword is illegal in C++, however, many libc
1505   // implementations use the "__restrict" compiler intrinsic in functions
1506   // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1507   // even in C++.
1508   // In case of any non-C99 languages, we don't want to match based on the
1509   // restrict qualifier because we cannot know if the given libc implementation
1510   // qualifies the paramter type or not.
1511   auto RemoveRestrict = [&FD](QualType T) {
1512     if (!FD->getASTContext().getLangOpts().C99)
1513       T.removeLocalRestrict();
1514     return T;
1515   };
1516 
1517   // Check the return type.
1518   if (!isIrrelevant(RetTy)) {
1519     QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1520     if (RetTy != FDRetTy)
1521       return false;
1522   }
1523 
1524   // Check the argument types.
1525   for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {
1526     if (isIrrelevant(ArgTy))
1527       continue;
1528     QualType FDArgTy =
1529         RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());
1530     if (ArgTy != FDArgTy)
1531       return false;
1532   }
1533 
1534   return true;
1535 }
1536 
1537 std::optional<StdLibraryFunctionsChecker::Summary>
1538 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1539                                                 CheckerContext &C) const {
1540   if (!FD)
1541     return std::nullopt;
1542 
1543   initFunctionSummaries(C);
1544 
1545   auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
1546   if (FSMI == FunctionSummaryMap.end())
1547     return std::nullopt;
1548   return FSMI->second;
1549 }
1550 
1551 std::optional<StdLibraryFunctionsChecker::Summary>
1552 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
1553                                                 CheckerContext &C) const {
1554   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1555   if (!FD)
1556     return std::nullopt;
1557   return findFunctionSummary(FD, C);
1558 }
1559 
1560 void StdLibraryFunctionsChecker::initFunctionSummaries(
1561     CheckerContext &C) const {
1562   if (SummariesInitialized)
1563     return;
1564   SummariesInitialized = true;
1565 
1566   SValBuilder &SVB = C.getSValBuilder();
1567   BasicValueFactory &BVF = SVB.getBasicValueFactory();
1568   const ASTContext &ACtx = BVF.getContext();
1569   Preprocessor &PP = C.getPreprocessor();
1570 
1571   // Helper class to lookup a type by its name.
1572   class LookupType {
1573     const ASTContext &ACtx;
1574 
1575   public:
1576     LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1577 
1578     // Find the type. If not found then the optional is not set.
1579     std::optional<QualType> operator()(StringRef Name) {
1580       IdentifierInfo &II = ACtx.Idents.get(Name);
1581       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1582       if (LookupRes.empty())
1583         return std::nullopt;
1584 
1585       // Prioritize typedef declarations.
1586       // This is needed in case of C struct typedefs. E.g.:
1587       //   typedef struct FILE FILE;
1588       // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1589       // and we have a TypedefDecl with the name 'FILE'.
1590       for (Decl *D : LookupRes)
1591         if (auto *TD = dyn_cast<TypedefNameDecl>(D))
1592           return ACtx.getTypeDeclType(TD).getCanonicalType();
1593 
1594       // Find the first TypeDecl.
1595       // There maybe cases when a function has the same name as a struct.
1596       // E.g. in POSIX: `struct stat` and the function `stat()`:
1597       //   int stat(const char *restrict path, struct stat *restrict buf);
1598       for (Decl *D : LookupRes)
1599         if (auto *TD = dyn_cast<TypeDecl>(D))
1600           return ACtx.getTypeDeclType(TD).getCanonicalType();
1601       return std::nullopt;
1602     }
1603   } lookupTy(ACtx);
1604 
1605   // Below are auxiliary classes to handle optional types that we get as a
1606   // result of the lookup.
1607   class GetRestrictTy {
1608     const ASTContext &ACtx;
1609 
1610   public:
1611     GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1612     QualType operator()(QualType Ty) {
1613       return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1614     }
1615     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1616       if (Ty)
1617         return operator()(*Ty);
1618       return std::nullopt;
1619     }
1620   } getRestrictTy(ACtx);
1621   class GetPointerTy {
1622     const ASTContext &ACtx;
1623 
1624   public:
1625     GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1626     QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1627     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1628       if (Ty)
1629         return operator()(*Ty);
1630       return std::nullopt;
1631     }
1632   } getPointerTy(ACtx);
1633   class {
1634   public:
1635     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1636       return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1637     }
1638     QualType operator()(QualType Ty) { return Ty.withConst(); }
1639   } getConstTy;
1640   class GetMaxValue {
1641     BasicValueFactory &BVF;
1642 
1643   public:
1644     GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1645     std::optional<RangeInt> operator()(QualType Ty) {
1646       return BVF.getMaxValue(Ty)->getLimitedValue();
1647     }
1648     std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1649       if (Ty) {
1650         return operator()(*Ty);
1651       }
1652       return std::nullopt;
1653     }
1654   } getMaxValue(BVF);
1655 
1656   // These types are useful for writing specifications quickly,
1657   // New specifications should probably introduce more types.
1658   // Some types are hard to obtain from the AST, eg. "ssize_t".
1659   // In such cases it should be possible to provide multiple variants
1660   // of function summary for common cases (eg. ssize_t could be int or long
1661   // or long long, so three summary variants would be enough).
1662   // Of course, function variants are also useful for C++ overloads.
1663   const QualType VoidTy = ACtx.VoidTy;
1664   const QualType CharTy = ACtx.CharTy;
1665   const QualType WCharTy = ACtx.WCharTy;
1666   const QualType IntTy = ACtx.IntTy;
1667   const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1668   const QualType LongTy = ACtx.LongTy;
1669   const QualType SizeTy = ACtx.getSizeType();
1670 
1671   const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1672   const QualType IntPtrTy = getPointerTy(IntTy);   // int *
1673   const QualType UnsignedIntPtrTy =
1674       getPointerTy(UnsignedIntTy); // unsigned int *
1675   const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1676   const QualType ConstVoidPtrTy =
1677       getPointerTy(getConstTy(VoidTy));            // const void *
1678   const QualType CharPtrTy = getPointerTy(CharTy); // char *
1679   const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
1680   const QualType ConstCharPtrTy =
1681       getPointerTy(getConstTy(CharTy)); // const char *
1682   const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1683   const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1684   const QualType ConstWchar_tPtrTy =
1685       getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1686   const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1687   const QualType SizePtrTy = getPointerTy(SizeTy);
1688   const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1689 
1690   const RangeInt IntMax = BVF.getMaxValue(IntTy)->getLimitedValue();
1691   const RangeInt UnsignedIntMax =
1692       BVF.getMaxValue(UnsignedIntTy)->getLimitedValue();
1693   const RangeInt LongMax = BVF.getMaxValue(LongTy)->getLimitedValue();
1694   const RangeInt SizeMax = BVF.getMaxValue(SizeTy)->getLimitedValue();
1695 
1696   // Set UCharRangeMax to min of int or uchar maximum value.
1697   // The C standard states that the arguments of functions like isalpha must
1698   // be representable as an unsigned char. Their type is 'int', so the max
1699   // value of the argument should be min(UCharMax, IntMax). This just happen
1700   // to be true for commonly used and well tested instruction set
1701   // architectures, but not for others.
1702   const RangeInt UCharRangeMax =
1703       std::min(BVF.getMaxValue(ACtx.UnsignedCharTy)->getLimitedValue(), IntMax);
1704 
1705   // Get platform dependent values of some macros.
1706   // Try our best to parse this from the Preprocessor, otherwise fallback to a
1707   // default value (what is found in a library header).
1708   const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
1709   const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
1710 
1711   // Auxiliary class to aid adding summaries to the summary map.
1712   struct AddToFunctionSummaryMap {
1713     const ASTContext &ACtx;
1714     FunctionSummaryMapType &Map;
1715     bool DisplayLoadedSummaries;
1716     AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1717                             bool DisplayLoadedSummaries)
1718         : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1719     }
1720 
1721     // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1722     // by the given Name, and in the global scope. The summary will be attached
1723     // to the found FunctionDecl only if the signatures match.
1724     //
1725     // Returns true if the summary has been added, false otherwise.
1726     bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1727       if (Sign.isInvalid())
1728         return false;
1729       IdentifierInfo &II = ACtx.Idents.get(Name);
1730       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1731       if (LookupRes.empty())
1732         return false;
1733       for (Decl *D : LookupRes) {
1734         if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1735           if (Sum.matchesAndSet(Sign, FD)) {
1736             auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
1737             assert(Res.second && "Function already has a summary set!");
1738             (void)Res;
1739             if (DisplayLoadedSummaries) {
1740               llvm::errs() << "Loaded summary for: ";
1741               FD->print(llvm::errs());
1742               llvm::errs() << "\n";
1743             }
1744             return true;
1745           }
1746         }
1747       }
1748       return false;
1749     }
1750     // Add the same summary for different names with the Signature explicitly
1751     // given.
1752     void operator()(ArrayRef<StringRef> Names, Signature Sign, Summary Sum) {
1753       for (StringRef Name : Names)
1754         operator()(Name, Sign, Sum);
1755     }
1756   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1757 
1758   // Below are helpers functions to create the summaries.
1759   auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
1760                               StringRef Desc = "") {
1761     return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
1762   };
1763   auto BufferSize = [](auto... Args) {
1764     return std::make_shared<BufferSizeConstraint>(Args...);
1765   };
1766   struct {
1767     auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1768       return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1769     }
1770     auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1771       return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1772     }
1773   } ReturnValueCondition;
1774   struct {
1775     auto operator()(RangeInt b, RangeInt e) {
1776       return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1777     }
1778     auto operator()(RangeInt b, std::optional<RangeInt> e) {
1779       if (e)
1780         return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1781       return IntRangeVector{};
1782     }
1783     auto operator()(std::pair<RangeInt, RangeInt> i0,
1784                     std::pair<RangeInt, std::optional<RangeInt>> i1) {
1785       if (i1.second)
1786         return IntRangeVector{i0, {i1.first, *(i1.second)}};
1787       return IntRangeVector{i0};
1788     }
1789   } Range;
1790   auto SingleValue = [](RangeInt v) {
1791     return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1792   };
1793   auto LessThanOrEq = BO_LE;
1794   auto NotNull = [&](ArgNo ArgN) {
1795     return std::make_shared<NullnessConstraint>(ArgN);
1796   };
1797   auto IsNull = [&](ArgNo ArgN) {
1798     return std::make_shared<NullnessConstraint>(ArgN, false);
1799   };
1800   auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N,
1801                            std::optional<ArgNo> SizeArg2N = std::nullopt) {
1802     return std::make_shared<BufferNullnessConstraint>(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   addToFunctionSummaryMap(
2031       "getchar", Signature(ArgTypes{}, RetType{IntTy}),
2032       Summary(NoEvalCall)
2033           .Case({ReturnValueCondition(WithinRange,
2034                                       {{EOFv, EOFv}, {0, UCharRangeMax}})},
2035                 ErrnoIrrelevant));
2036 
2037   // read()-like functions that never return more than buffer size.
2038   auto FreadSummary =
2039       Summary(NoEvalCall)
2040           .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2041                  ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
2042                  ReturnValueCondition(BO_LT, ArgNo(2)),
2043                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2044                 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2045           .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2046                  ReturnValueCondition(BO_EQ, ArgNo(2)),
2047                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2048                 ErrnoMustNotBeChecked, GenericSuccessMsg)
2049           .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
2050                  ReturnValueCondition(WithinRange, SingleValue(0))},
2051                 ErrnoMustNotBeChecked,
2052                 "Assuming that argument 'size' to '{0}' is 0")
2053           .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2054           .ArgConstraint(NotNull(ArgNo(3)))
2055           .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2056                                     /*BufSizeMultiplier=*/ArgNo(2)));
2057 
2058   // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2059   //              FILE *restrict stream);
2060   addToFunctionSummaryMap(
2061       "fread",
2062       Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
2063                 RetType{SizeTy}),
2064       FreadSummary);
2065   // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2066   //               FILE *restrict stream);
2067   addToFunctionSummaryMap("fwrite",
2068                           Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
2069                                              SizeTy, FilePtrRestrictTy},
2070                                     RetType{SizeTy}),
2071                           FreadSummary);
2072 
2073   std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
2074   std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
2075 
2076   auto ReadSummary =
2077       Summary(NoEvalCall)
2078           .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2079                  ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
2080                 ErrnoIrrelevant);
2081 
2082   // FIXME these are actually defined by POSIX and not by the C standard, we
2083   // should handle them together with the rest of the POSIX functions.
2084   // ssize_t read(int fildes, void *buf, size_t nbyte);
2085   addToFunctionSummaryMap(
2086       "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2087       ReadSummary);
2088   // ssize_t write(int fildes, const void *buf, size_t nbyte);
2089   addToFunctionSummaryMap(
2090       "write",
2091       Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2092       ReadSummary);
2093 
2094   auto GetLineSummary =
2095       Summary(NoEvalCall)
2096           .Case({ReturnValueCondition(WithinRange,
2097                                       Range({-1, -1}, {1, Ssize_tMax}))},
2098                 ErrnoIrrelevant);
2099 
2100   QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
2101 
2102   // getline()-like functions either fail or read at least the delimiter.
2103   // FIXME these are actually defined by POSIX and not by the C standard, we
2104   // should handle them together with the rest of the POSIX functions.
2105   // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2106   //                 FILE *restrict stream);
2107   addToFunctionSummaryMap(
2108       "getline",
2109       Signature(
2110           ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
2111           RetType{Ssize_tTy}),
2112       GetLineSummary);
2113   // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2114   //                  int delimiter, FILE *restrict stream);
2115   addToFunctionSummaryMap(
2116       "getdelim",
2117       Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2118                          FilePtrRestrictTy},
2119                 RetType{Ssize_tTy}),
2120       GetLineSummary);
2121 
2122   {
2123     Summary GetenvSummary =
2124         Summary(NoEvalCall)
2125             .ArgConstraint(NotNull(ArgNo(0)))
2126             .Case({NotNull(Ret)}, ErrnoIrrelevant,
2127                   "Assuming the environment variable exists");
2128     // In untrusted environments the envvar might not exist.
2129     if (!ShouldAssumeControlledEnvironment)
2130       GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
2131                          "Assuming the environment variable does not exist");
2132 
2133     // char *getenv(const char *name);
2134     addToFunctionSummaryMap(
2135         "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2136         std::move(GetenvSummary));
2137   }
2138 
2139   if (!ModelPOSIX) {
2140     // Without POSIX use of 'errno' is not specified (in these cases).
2141     // Add these functions without 'errno' checks.
2142     addToFunctionSummaryMap(
2143         {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2144         Summary(NoEvalCall)
2145             .Case({ReturnValueCondition(WithinRange,
2146                                         {{EOFv, EOFv}, {0, UCharRangeMax}})},
2147                   ErrnoIrrelevant)
2148             .ArgConstraint(NotNull(ArgNo(0))));
2149   } else {
2150     const auto ReturnsZeroOrMinusOne =
2151         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
2152     const auto ReturnsZero =
2153         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2154     const auto ReturnsMinusOne =
2155         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
2156     const auto ReturnsEOF =
2157         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(EOFv))};
2158     const auto ReturnsNonnegative =
2159         ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2160     const auto ReturnsNonZero =
2161         ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2162     const auto ReturnsFileDescriptor =
2163         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
2164     const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2165 
2166     auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
2167       return std::make_shared<RangeConstraint>(
2168           ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
2169           "a valid file descriptor or AT_FDCWD");
2170     };
2171 
2172     // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2173     addToFunctionSummaryMap(
2174         "fopen",
2175         Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2176                   RetType{FilePtrTy}),
2177         Summary(NoEvalCall)
2178             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2179             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2180             .ArgConstraint(NotNull(ArgNo(0)))
2181             .ArgConstraint(NotNull(ArgNo(1))));
2182 
2183     // FILE *fdopen(int fd, const char *mode);
2184     addToFunctionSummaryMap(
2185         "fdopen",
2186         Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2187         Summary(NoEvalCall)
2188             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2189             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2190             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2191             .ArgConstraint(NotNull(ArgNo(1))));
2192 
2193     // FILE *tmpfile(void);
2194     addToFunctionSummaryMap(
2195         "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2196         Summary(NoEvalCall)
2197             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2198             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2199 
2200     // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2201     //               FILE *restrict stream);
2202     addToFunctionSummaryMap(
2203         "freopen",
2204         Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2205                            FilePtrRestrictTy},
2206                   RetType{FilePtrTy}),
2207         Summary(NoEvalCall)
2208             .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
2209                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2210             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2211             .ArgConstraint(NotNull(ArgNo(1)))
2212             .ArgConstraint(NotNull(ArgNo(2))));
2213 
2214     // FILE *popen(const char *command, const char *type);
2215     addToFunctionSummaryMap(
2216         "popen",
2217         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2218         Summary(NoEvalCall)
2219             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2220             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2221             .ArgConstraint(NotNull(ArgNo(0)))
2222             .ArgConstraint(NotNull(ArgNo(1))));
2223 
2224     // int fclose(FILE *stream);
2225     addToFunctionSummaryMap(
2226         "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2227         Summary(NoEvalCall)
2228             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2229             .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2230             .ArgConstraint(NotNull(ArgNo(0))));
2231 
2232     // int pclose(FILE *stream);
2233     addToFunctionSummaryMap(
2234         "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2235         Summary(NoEvalCall)
2236             .Case({ReturnValueCondition(WithinRange, {{0, IntMax}})},
2237                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2238             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2239             .ArgConstraint(NotNull(ArgNo(0))));
2240 
2241     std::optional<QualType> Off_tTy = lookupTy("off_t");
2242     std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
2243 
2244     // int fgetc(FILE *stream);
2245     // 'getc' is the same as 'fgetc' but may be a macro
2246     addToFunctionSummaryMap(
2247         {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2248         Summary(NoEvalCall)
2249             .Case({ReturnValueCondition(WithinRange, {{0, UCharRangeMax}})},
2250                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2251             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2252                   ErrnoIrrelevant, GenericFailureMsg)
2253             .ArgConstraint(NotNull(ArgNo(0))));
2254 
2255     // int fputc(int c, FILE *stream);
2256     // 'putc' is the same as 'fputc' but may be a macro
2257     addToFunctionSummaryMap(
2258         {"putc", "fputc"},
2259         Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2260         Summary(NoEvalCall)
2261             .Case({ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)),
2262                    ReturnValueCondition(BO_EQ, ArgNo(0))},
2263                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2264             .Case({ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)),
2265                    ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))},
2266                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2267             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2268                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2269             .ArgConstraint(NotNull(ArgNo(1))));
2270 
2271     // char *fgets(char *restrict s, int n, FILE *restrict stream);
2272     addToFunctionSummaryMap(
2273         "fgets",
2274         Signature(ArgTypes{CharPtrRestrictTy, IntTy, FilePtrRestrictTy},
2275                   RetType{CharPtrTy}),
2276         Summary(NoEvalCall)
2277             .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},
2278                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2279             .Case({IsNull(Ret)}, ErrnoIrrelevant, GenericFailureMsg)
2280             .ArgConstraint(NotNull(ArgNo(0)))
2281             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
2282             .ArgConstraint(
2283                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2284             .ArgConstraint(NotNull(ArgNo(2))));
2285 
2286     // int fputs(const char *restrict s, FILE *restrict stream);
2287     addToFunctionSummaryMap(
2288         "fputs",
2289         Signature(ArgTypes{ConstCharPtrRestrictTy, FilePtrRestrictTy},
2290                   RetType{IntTy}),
2291         Summary(NoEvalCall)
2292             .Case(ReturnsNonnegative, ErrnoMustNotBeChecked, GenericSuccessMsg)
2293             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2294                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2295             .ArgConstraint(NotNull(ArgNo(0)))
2296             .ArgConstraint(NotNull(ArgNo(1))));
2297 
2298     // int ungetc(int c, FILE *stream);
2299     addToFunctionSummaryMap(
2300         "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2301         Summary(NoEvalCall)
2302             .Case({ReturnValueCondition(BO_EQ, ArgNo(0)),
2303                    ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2304                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2305             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2306                    ArgumentCondition(0, WithinRange, SingleValue(EOFv))},
2307                   ErrnoNEZeroIrrelevant,
2308                   "Assuming that 'ungetc' fails because EOF was passed as "
2309                   "character")
2310             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2311                    ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2312                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2313             .ArgConstraint(ArgumentCondition(
2314                 0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))
2315             .ArgConstraint(NotNull(ArgNo(1))));
2316 
2317     // int fseek(FILE *stream, long offset, int whence);
2318     // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2319     // these for condition of arg 2.
2320     // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2321     addToFunctionSummaryMap(
2322         "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2323         Summary(NoEvalCall)
2324             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2325             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2326             .ArgConstraint(NotNull(ArgNo(0)))
2327             .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2328 
2329     // int fseeko(FILE *stream, off_t offset, int whence);
2330     addToFunctionSummaryMap(
2331         "fseeko",
2332         Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2333         Summary(NoEvalCall)
2334             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2335             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2336             .ArgConstraint(NotNull(ArgNo(0)))
2337             .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2338 
2339     // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2340     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2341     // "The fgetpos() function shall not change the setting of errno if
2342     // successful."
2343     addToFunctionSummaryMap(
2344         "fgetpos",
2345         Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2346                   RetType{IntTy}),
2347         Summary(NoEvalCall)
2348             .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2349             .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2350             .ArgConstraint(NotNull(ArgNo(0)))
2351             .ArgConstraint(NotNull(ArgNo(1))));
2352 
2353     // int fsetpos(FILE *stream, const fpos_t *pos);
2354     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2355     // "The fsetpos() function shall not change the setting of errno if
2356     // successful."
2357     addToFunctionSummaryMap(
2358         "fsetpos",
2359         Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2360         Summary(NoEvalCall)
2361             .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2362             .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2363             .ArgConstraint(NotNull(ArgNo(0)))
2364             .ArgConstraint(NotNull(ArgNo(1))));
2365 
2366     // int fflush(FILE *stream);
2367     addToFunctionSummaryMap(
2368         "fflush", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2369         Summary(NoEvalCall)
2370             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2371             .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2372 
2373     // long ftell(FILE *stream);
2374     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2375     // "The ftell() function shall not change the setting of errno if
2376     // successful."
2377     addToFunctionSummaryMap(
2378         "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2379         Summary(NoEvalCall)
2380             .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))},
2381                   ErrnoUnchanged, GenericSuccessMsg)
2382             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2383             .ArgConstraint(NotNull(ArgNo(0))));
2384 
2385     // off_t ftello(FILE *stream);
2386     addToFunctionSummaryMap(
2387         "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2388         Summary(NoEvalCall)
2389             .Case({ReturnValueCondition(WithinRange, Range(0, Off_tMax))},
2390                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2391             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2392             .ArgConstraint(NotNull(ArgNo(0))));
2393 
2394     // int fileno(FILE *stream);
2395     // According to POSIX 'fileno' may fail and set 'errno'.
2396     // But in Linux it may fail only if the specified file pointer is invalid.
2397     // At many places 'fileno' is used without check for failure and a failure
2398     // case here would produce a large amount of likely false positive warnings.
2399     // To avoid this, we assume here that it does not fail.
2400     addToFunctionSummaryMap(
2401         "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2402         Summary(NoEvalCall)
2403             .Case(ReturnsValidFileDescriptor, ErrnoUnchanged, GenericSuccessMsg)
2404             .ArgConstraint(NotNull(ArgNo(0))));
2405 
2406     // void rewind(FILE *stream);
2407     // This function indicates error only by setting of 'errno'.
2408     addToFunctionSummaryMap("rewind",
2409                             Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2410                             Summary(NoEvalCall)
2411                                 .Case({}, ErrnoMustBeChecked)
2412                                 .ArgConstraint(NotNull(ArgNo(0))));
2413 
2414     // void clearerr(FILE *stream);
2415     addToFunctionSummaryMap(
2416         "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2417         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2418 
2419     // int feof(FILE *stream);
2420     addToFunctionSummaryMap(
2421         "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2422         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2423 
2424     // int ferror(FILE *stream);
2425     addToFunctionSummaryMap(
2426         "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2427         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2428 
2429     // long a64l(const char *str64);
2430     addToFunctionSummaryMap(
2431         "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2432         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2433 
2434     // char *l64a(long value);
2435     addToFunctionSummaryMap("l64a",
2436                             Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2437                             Summary(NoEvalCall)
2438                                 .ArgConstraint(ArgumentCondition(
2439                                     0, WithinRange, Range(0, LongMax))));
2440 
2441     // int open(const char *path, int oflag, ...);
2442     addToFunctionSummaryMap(
2443         "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2444         Summary(NoEvalCall)
2445             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2446                   GenericSuccessMsg)
2447             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2448             .ArgConstraint(NotNull(ArgNo(0))));
2449 
2450     // int openat(int fd, const char *path, int oflag, ...);
2451     addToFunctionSummaryMap(
2452         "openat",
2453         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2454         Summary(NoEvalCall)
2455             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2456                   GenericSuccessMsg)
2457             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2458             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2459             .ArgConstraint(NotNull(ArgNo(1))));
2460 
2461     // int access(const char *pathname, int amode);
2462     addToFunctionSummaryMap(
2463         "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2464         Summary(NoEvalCall)
2465             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2466             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2467             .ArgConstraint(NotNull(ArgNo(0))));
2468 
2469     // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2470     addToFunctionSummaryMap(
2471         "faccessat",
2472         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2473                   RetType{IntTy}),
2474         Summary(NoEvalCall)
2475             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2476             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2477             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2478             .ArgConstraint(NotNull(ArgNo(1))));
2479 
2480     // int dup(int fildes);
2481     addToFunctionSummaryMap(
2482         "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2483         Summary(NoEvalCall)
2484             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2485                   GenericSuccessMsg)
2486             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2487             .ArgConstraint(
2488                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2489 
2490     // int dup2(int fildes1, int filedes2);
2491     addToFunctionSummaryMap(
2492         "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2493         Summary(NoEvalCall)
2494             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2495                   GenericSuccessMsg)
2496             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2497             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2498             .ArgConstraint(
2499                 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
2500 
2501     // int fdatasync(int fildes);
2502     addToFunctionSummaryMap(
2503         "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2504         Summary(NoEvalCall)
2505             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2506             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2507             .ArgConstraint(
2508                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2509 
2510     // int fnmatch(const char *pattern, const char *string, int flags);
2511     addToFunctionSummaryMap(
2512         "fnmatch",
2513         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2514                   RetType{IntTy}),
2515         Summary(NoEvalCall)
2516             .ArgConstraint(NotNull(ArgNo(0)))
2517             .ArgConstraint(NotNull(ArgNo(1))));
2518 
2519     // int fsync(int fildes);
2520     addToFunctionSummaryMap(
2521         "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2522         Summary(NoEvalCall)
2523             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2524             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2525             .ArgConstraint(
2526                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2527 
2528     // int truncate(const char *path, off_t length);
2529     addToFunctionSummaryMap(
2530         "truncate",
2531         Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2532         Summary(NoEvalCall)
2533             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2534             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2535             .ArgConstraint(NotNull(ArgNo(0))));
2536 
2537     // int symlink(const char *oldpath, const char *newpath);
2538     addToFunctionSummaryMap(
2539         "symlink",
2540         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2541         Summary(NoEvalCall)
2542             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2543             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2544             .ArgConstraint(NotNull(ArgNo(0)))
2545             .ArgConstraint(NotNull(ArgNo(1))));
2546 
2547     // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2548     addToFunctionSummaryMap(
2549         "symlinkat",
2550         Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2551                   RetType{IntTy}),
2552         Summary(NoEvalCall)
2553             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2554             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2555             .ArgConstraint(NotNull(ArgNo(0)))
2556             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
2557             .ArgConstraint(NotNull(ArgNo(2))));
2558 
2559     // int lockf(int fd, int cmd, off_t len);
2560     addToFunctionSummaryMap(
2561         "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2562         Summary(NoEvalCall)
2563             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2564             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2565             .ArgConstraint(
2566                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2567 
2568     std::optional<QualType> Mode_tTy = lookupTy("mode_t");
2569 
2570     // int creat(const char *pathname, mode_t mode);
2571     addToFunctionSummaryMap(
2572         "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2573         Summary(NoEvalCall)
2574             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2575                   GenericSuccessMsg)
2576             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2577             .ArgConstraint(NotNull(ArgNo(0))));
2578 
2579     // unsigned int sleep(unsigned int seconds);
2580     addToFunctionSummaryMap(
2581         "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2582         Summary(NoEvalCall)
2583             .ArgConstraint(
2584                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2585 
2586     std::optional<QualType> DirTy = lookupTy("DIR");
2587     std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
2588 
2589     // int dirfd(DIR *dirp);
2590     addToFunctionSummaryMap(
2591         "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2592         Summary(NoEvalCall)
2593             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2594                   GenericSuccessMsg)
2595             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2596             .ArgConstraint(NotNull(ArgNo(0))));
2597 
2598     // unsigned int alarm(unsigned int seconds);
2599     addToFunctionSummaryMap(
2600         "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2601         Summary(NoEvalCall)
2602             .ArgConstraint(
2603                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2604 
2605     // int closedir(DIR *dir);
2606     addToFunctionSummaryMap(
2607         "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2608         Summary(NoEvalCall)
2609             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2610             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2611             .ArgConstraint(NotNull(ArgNo(0))));
2612 
2613     // char *strdup(const char *s);
2614     addToFunctionSummaryMap(
2615         "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2616         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2617 
2618     // char *strndup(const char *s, size_t n);
2619     addToFunctionSummaryMap(
2620         "strndup",
2621         Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
2622         Summary(NoEvalCall)
2623             .ArgConstraint(NotNull(ArgNo(0)))
2624             .ArgConstraint(
2625                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2626 
2627     // wchar_t *wcsdup(const wchar_t *s);
2628     addToFunctionSummaryMap(
2629         "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2630         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2631 
2632     // int mkstemp(char *template);
2633     addToFunctionSummaryMap(
2634         "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2635         Summary(NoEvalCall)
2636             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2637                   GenericSuccessMsg)
2638             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2639             .ArgConstraint(NotNull(ArgNo(0))));
2640 
2641     // char *mkdtemp(char *template);
2642     addToFunctionSummaryMap(
2643         "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
2644         Summary(NoEvalCall)
2645             .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},
2646                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2647             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2648             .ArgConstraint(NotNull(ArgNo(0))));
2649 
2650     // char *getcwd(char *buf, size_t size);
2651     addToFunctionSummaryMap(
2652         "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
2653         Summary(NoEvalCall)
2654             .Case({NotNull(0),
2655                    ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2656                    ReturnValueCondition(BO_EQ, ArgNo(0))},
2657                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2658             .Case({NotNull(0),
2659                    ArgumentCondition(1, WithinRange, SingleValue(0)),
2660                    IsNull(Ret)},
2661                   ErrnoNEZeroIrrelevant, "Assuming that argument 'size' is 0")
2662             .Case({NotNull(0),
2663                    ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2664                    IsNull(Ret)},
2665                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2666             .Case({IsNull(0), NotNull(Ret)}, ErrnoMustNotBeChecked,
2667                   GenericSuccessMsg)
2668             .Case({IsNull(0), IsNull(Ret)}, ErrnoNEZeroIrrelevant,
2669                   GenericFailureMsg)
2670             .ArgConstraint(
2671                 BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
2672             .ArgConstraint(
2673                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2674 
2675     // int mkdir(const char *pathname, mode_t mode);
2676     addToFunctionSummaryMap(
2677         "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2678         Summary(NoEvalCall)
2679             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2680             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2681             .ArgConstraint(NotNull(ArgNo(0))));
2682 
2683     // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2684     addToFunctionSummaryMap(
2685         "mkdirat",
2686         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2687         Summary(NoEvalCall)
2688             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2689             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2690             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2691             .ArgConstraint(NotNull(ArgNo(1))));
2692 
2693     std::optional<QualType> Dev_tTy = lookupTy("dev_t");
2694 
2695     // int mknod(const char *pathname, mode_t mode, dev_t dev);
2696     addToFunctionSummaryMap(
2697         "mknod",
2698         Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2699         Summary(NoEvalCall)
2700             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2701             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2702             .ArgConstraint(NotNull(ArgNo(0))));
2703 
2704     // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2705     addToFunctionSummaryMap(
2706         "mknodat",
2707         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2708                   RetType{IntTy}),
2709         Summary(NoEvalCall)
2710             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2711             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2712             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2713             .ArgConstraint(NotNull(ArgNo(1))));
2714 
2715     // int chmod(const char *path, mode_t mode);
2716     addToFunctionSummaryMap(
2717         "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2718         Summary(NoEvalCall)
2719             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2720             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2721             .ArgConstraint(NotNull(ArgNo(0))));
2722 
2723     // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2724     addToFunctionSummaryMap(
2725         "fchmodat",
2726         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2727                   RetType{IntTy}),
2728         Summary(NoEvalCall)
2729             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2730             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2731             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2732             .ArgConstraint(NotNull(ArgNo(1))));
2733 
2734     // int fchmod(int fildes, mode_t mode);
2735     addToFunctionSummaryMap(
2736         "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2737         Summary(NoEvalCall)
2738             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2739             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2740             .ArgConstraint(
2741                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2742 
2743     std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2744     std::optional<QualType> Gid_tTy = lookupTy("gid_t");
2745 
2746     // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2747     //              int flags);
2748     addToFunctionSummaryMap(
2749         "fchownat",
2750         Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2751                   RetType{IntTy}),
2752         Summary(NoEvalCall)
2753             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2754             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2755             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2756             .ArgConstraint(NotNull(ArgNo(1))));
2757 
2758     // int chown(const char *path, uid_t owner, gid_t group);
2759     addToFunctionSummaryMap(
2760         "chown",
2761         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2762         Summary(NoEvalCall)
2763             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2764             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2765             .ArgConstraint(NotNull(ArgNo(0))));
2766 
2767     // int lchown(const char *path, uid_t owner, gid_t group);
2768     addToFunctionSummaryMap(
2769         "lchown",
2770         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2771         Summary(NoEvalCall)
2772             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2773             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2774             .ArgConstraint(NotNull(ArgNo(0))));
2775 
2776     // int fchown(int fildes, uid_t owner, gid_t group);
2777     addToFunctionSummaryMap(
2778         "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2779         Summary(NoEvalCall)
2780             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2781             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2782             .ArgConstraint(
2783                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2784 
2785     // int rmdir(const char *pathname);
2786     addToFunctionSummaryMap(
2787         "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2788         Summary(NoEvalCall)
2789             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2790             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2791             .ArgConstraint(NotNull(ArgNo(0))));
2792 
2793     // int chdir(const char *path);
2794     addToFunctionSummaryMap(
2795         "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2796         Summary(NoEvalCall)
2797             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2798             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2799             .ArgConstraint(NotNull(ArgNo(0))));
2800 
2801     // int link(const char *oldpath, const char *newpath);
2802     addToFunctionSummaryMap(
2803         "link",
2804         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2805         Summary(NoEvalCall)
2806             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2807             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2808             .ArgConstraint(NotNull(ArgNo(0)))
2809             .ArgConstraint(NotNull(ArgNo(1))));
2810 
2811     // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2812     //            int flag);
2813     addToFunctionSummaryMap(
2814         "linkat",
2815         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2816                   RetType{IntTy}),
2817         Summary(NoEvalCall)
2818             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2819             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2820             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2821             .ArgConstraint(NotNull(ArgNo(1)))
2822             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2823             .ArgConstraint(NotNull(ArgNo(3))));
2824 
2825     // int unlink(const char *pathname);
2826     addToFunctionSummaryMap(
2827         "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2828         Summary(NoEvalCall)
2829             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2830             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2831             .ArgConstraint(NotNull(ArgNo(0))));
2832 
2833     // int unlinkat(int fd, const char *path, int flag);
2834     addToFunctionSummaryMap(
2835         "unlinkat",
2836         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2837         Summary(NoEvalCall)
2838             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2839             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2840             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2841             .ArgConstraint(NotNull(ArgNo(1))));
2842 
2843     std::optional<QualType> StructStatTy = lookupTy("stat");
2844     std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2845     std::optional<QualType> StructStatPtrRestrictTy =
2846         getRestrictTy(StructStatPtrTy);
2847 
2848     // int fstat(int fd, struct stat *statbuf);
2849     addToFunctionSummaryMap(
2850         "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2851         Summary(NoEvalCall)
2852             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2853             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2854             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2855             .ArgConstraint(NotNull(ArgNo(1))));
2856 
2857     // int stat(const char *restrict path, struct stat *restrict buf);
2858     addToFunctionSummaryMap(
2859         "stat",
2860         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2861                   RetType{IntTy}),
2862         Summary(NoEvalCall)
2863             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2864             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2865             .ArgConstraint(NotNull(ArgNo(0)))
2866             .ArgConstraint(NotNull(ArgNo(1))));
2867 
2868     // int lstat(const char *restrict path, struct stat *restrict buf);
2869     addToFunctionSummaryMap(
2870         "lstat",
2871         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2872                   RetType{IntTy}),
2873         Summary(NoEvalCall)
2874             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2875             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2876             .ArgConstraint(NotNull(ArgNo(0)))
2877             .ArgConstraint(NotNull(ArgNo(1))));
2878 
2879     // int fstatat(int fd, const char *restrict path,
2880     //             struct stat *restrict buf, int flag);
2881     addToFunctionSummaryMap(
2882         "fstatat",
2883         Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2884                            StructStatPtrRestrictTy, IntTy},
2885                   RetType{IntTy}),
2886         Summary(NoEvalCall)
2887             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2888             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2889             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2890             .ArgConstraint(NotNull(ArgNo(1)))
2891             .ArgConstraint(NotNull(ArgNo(2))));
2892 
2893     // DIR *opendir(const char *name);
2894     addToFunctionSummaryMap(
2895         "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
2896         Summary(NoEvalCall)
2897             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2898             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2899             .ArgConstraint(NotNull(ArgNo(0))));
2900 
2901     // DIR *fdopendir(int fd);
2902     addToFunctionSummaryMap(
2903         "fdopendir", Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2904         Summary(NoEvalCall)
2905             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2906             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2907             .ArgConstraint(
2908                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2909 
2910     // int isatty(int fildes);
2911     addToFunctionSummaryMap(
2912         "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2913         Summary(NoEvalCall)
2914             .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
2915                   ErrnoIrrelevant)
2916             .ArgConstraint(
2917                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2918 
2919     // int close(int fildes);
2920     addToFunctionSummaryMap(
2921         "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2922         Summary(NoEvalCall)
2923             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2924             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2925             .ArgConstraint(
2926                 ArgumentCondition(0, WithinRange, Range(-1, IntMax))));
2927 
2928     // long fpathconf(int fildes, int name);
2929     addToFunctionSummaryMap("fpathconf",
2930                             Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2931                             Summary(NoEvalCall)
2932                                 .ArgConstraint(ArgumentCondition(
2933                                     0, WithinRange, Range(0, IntMax))));
2934 
2935     // long pathconf(const char *path, int name);
2936     addToFunctionSummaryMap(
2937         "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2938         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2939 
2940     // void rewinddir(DIR *dir);
2941     addToFunctionSummaryMap(
2942         "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2943         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2944 
2945     // void seekdir(DIR *dirp, long loc);
2946     addToFunctionSummaryMap(
2947         "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2948         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2949 
2950     // int rand_r(unsigned int *seedp);
2951     addToFunctionSummaryMap(
2952         "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2953         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2954 
2955     // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2956     // off_t offset);
2957     // FIXME: Improve for errno modeling.
2958     addToFunctionSummaryMap(
2959         "mmap",
2960         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
2961                   RetType{VoidPtrTy}),
2962         Summary(NoEvalCall)
2963             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2964             .ArgConstraint(
2965                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2966 
2967     std::optional<QualType> Off64_tTy = lookupTy("off64_t");
2968     // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2969     // off64_t offset);
2970     // FIXME: Improve for errno modeling.
2971     addToFunctionSummaryMap(
2972         "mmap64",
2973         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
2974                   RetType{VoidPtrTy}),
2975         Summary(NoEvalCall)
2976             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2977             .ArgConstraint(
2978                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2979 
2980     // int pipe(int fildes[2]);
2981     addToFunctionSummaryMap(
2982         "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2983         Summary(NoEvalCall)
2984             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2985             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2986             .ArgConstraint(NotNull(ArgNo(0))));
2987 
2988     // off_t lseek(int fildes, off_t offset, int whence);
2989     // In the first case we can not tell for sure if it failed or not.
2990     // A return value different from of the expected offset (that is unknown
2991     // here) may indicate failure. For this reason we do not enforce the errno
2992     // check (can cause false positive).
2993     addToFunctionSummaryMap(
2994         "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2995         Summary(NoEvalCall)
2996             .Case(ReturnsNonnegative, ErrnoIrrelevant)
2997             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2998             .ArgConstraint(
2999                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3000 
3001     // ssize_t readlink(const char *restrict path, char *restrict buf,
3002     //                  size_t bufsize);
3003     addToFunctionSummaryMap(
3004         "readlink",
3005         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
3006                   RetType{Ssize_tTy}),
3007         Summary(NoEvalCall)
3008             .Case({ArgumentCondition(2, WithinRange, Range(1, IntMax)),
3009                    ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3010                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3011                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3012             .Case({ArgumentCondition(2, WithinRange, SingleValue(0)),
3013                    ReturnValueCondition(WithinRange, SingleValue(0))},
3014                   ErrnoMustNotBeChecked,
3015                   "Assuming that argument 'bufsize' is 0")
3016             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3017             .ArgConstraint(NotNull(ArgNo(0)))
3018             .ArgConstraint(NotNull(ArgNo(1)))
3019             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3020                                       /*BufSize=*/ArgNo(2)))
3021             .ArgConstraint(
3022                 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
3023 
3024     // ssize_t readlinkat(int fd, const char *restrict path,
3025     //                    char *restrict buf, size_t bufsize);
3026     addToFunctionSummaryMap(
3027         "readlinkat",
3028         Signature(
3029             ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
3030             RetType{Ssize_tTy}),
3031         Summary(NoEvalCall)
3032             .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)),
3033                    ReturnValueCondition(LessThanOrEq, ArgNo(3)),
3034                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3035                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3036             .Case({ArgumentCondition(3, WithinRange, SingleValue(0)),
3037                    ReturnValueCondition(WithinRange, SingleValue(0))},
3038                   ErrnoMustNotBeChecked,
3039                   "Assuming that argument 'bufsize' is 0")
3040             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3041             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3042             .ArgConstraint(NotNull(ArgNo(1)))
3043             .ArgConstraint(NotNull(ArgNo(2)))
3044             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
3045                                       /*BufSize=*/ArgNo(3)))
3046             .ArgConstraint(
3047                 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
3048 
3049     // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
3050     // *newpath);
3051     addToFunctionSummaryMap(
3052         "renameat",
3053         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
3054                   RetType{IntTy}),
3055         Summary(NoEvalCall)
3056             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3057             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3058             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3059             .ArgConstraint(NotNull(ArgNo(1)))
3060             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
3061             .ArgConstraint(NotNull(ArgNo(3))));
3062 
3063     // char *realpath(const char *restrict file_name,
3064     //                char *restrict resolved_name);
3065     // FIXME: If the argument 'resolved_name' is not NULL, macro 'PATH_MAX'
3066     //        should be defined in "limits.h" to guarrantee a success.
3067     addToFunctionSummaryMap(
3068         "realpath",
3069         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
3070                   RetType{CharPtrTy}),
3071         Summary(NoEvalCall)
3072             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
3073             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3074             .ArgConstraint(NotNull(ArgNo(0))));
3075 
3076     QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
3077 
3078     // int execv(const char *path, char *const argv[]);
3079     addToFunctionSummaryMap(
3080         "execv",
3081         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3082         Summary(NoEvalCall)
3083             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3084             .ArgConstraint(NotNull(ArgNo(0))));
3085 
3086     // int execvp(const char *file, char *const argv[]);
3087     addToFunctionSummaryMap(
3088         "execvp",
3089         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3090         Summary(NoEvalCall)
3091             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3092             .ArgConstraint(NotNull(ArgNo(0))));
3093 
3094     // int getopt(int argc, char * const argv[], const char *optstring);
3095     addToFunctionSummaryMap(
3096         "getopt",
3097         Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
3098                   RetType{IntTy}),
3099         Summary(NoEvalCall)
3100             .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
3101                   ErrnoIrrelevant)
3102             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3103             .ArgConstraint(NotNull(ArgNo(1)))
3104             .ArgConstraint(NotNull(ArgNo(2))));
3105 
3106     std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
3107     std::optional<QualType> StructSockaddrPtrTy =
3108         getPointerTy(StructSockaddrTy);
3109     std::optional<QualType> ConstStructSockaddrPtrTy =
3110         getPointerTy(getConstTy(StructSockaddrTy));
3111     std::optional<QualType> StructSockaddrPtrRestrictTy =
3112         getRestrictTy(StructSockaddrPtrTy);
3113     std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
3114         getRestrictTy(ConstStructSockaddrPtrTy);
3115     std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
3116     std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
3117     std::optional<QualType> Socklen_tPtrRestrictTy =
3118         getRestrictTy(Socklen_tPtrTy);
3119     std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
3120 
3121     // In 'socket.h' of some libc implementations with C99, sockaddr parameter
3122     // is a transparent union of the underlying sockaddr_ family of pointers
3123     // instead of being a pointer to struct sockaddr. In these cases, the
3124     // standardized signature will not match, thus we try to match with another
3125     // signature that has the joker Irrelevant type. We also remove those
3126     // constraints which require pointer types for the sockaddr param.
3127 
3128     // int socket(int domain, int type, int protocol);
3129     addToFunctionSummaryMap(
3130         "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),
3131         Summary(NoEvalCall)
3132             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
3133                   GenericSuccessMsg)
3134             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg));
3135 
3136     auto Accept =
3137         Summary(NoEvalCall)
3138             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
3139                   GenericSuccessMsg)
3140             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3141             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
3142     if (!addToFunctionSummaryMap(
3143             "accept",
3144             // int accept(int socket, struct sockaddr *restrict address,
3145             //            socklen_t *restrict address_len);
3146             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3147                                Socklen_tPtrRestrictTy},
3148                       RetType{IntTy}),
3149             Accept))
3150       addToFunctionSummaryMap(
3151           "accept",
3152           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3153                     RetType{IntTy}),
3154           Accept);
3155 
3156     // int bind(int socket, const struct sockaddr *address, socklen_t
3157     //          address_len);
3158     if (!addToFunctionSummaryMap(
3159             "bind",
3160             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3161                       RetType{IntTy}),
3162             Summary(NoEvalCall)
3163                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3164                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3165                 .ArgConstraint(
3166                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3167                 .ArgConstraint(NotNull(ArgNo(1)))
3168                 .ArgConstraint(
3169                     BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3170                 .ArgConstraint(
3171                     ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
3172       // Do not add constraints on sockaddr.
3173       addToFunctionSummaryMap(
3174           "bind",
3175           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3176           Summary(NoEvalCall)
3177               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3178               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3179               .ArgConstraint(
3180                   ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3181               .ArgConstraint(
3182                   ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
3183 
3184     // int getpeername(int socket, struct sockaddr *restrict address,
3185     //                 socklen_t *restrict address_len);
3186     if (!addToFunctionSummaryMap(
3187             "getpeername",
3188             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3189                                Socklen_tPtrRestrictTy},
3190                       RetType{IntTy}),
3191             Summary(NoEvalCall)
3192                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3193                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3194                 .ArgConstraint(
3195                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3196                 .ArgConstraint(NotNull(ArgNo(1)))
3197                 .ArgConstraint(NotNull(ArgNo(2)))))
3198       addToFunctionSummaryMap(
3199           "getpeername",
3200           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3201                     RetType{IntTy}),
3202           Summary(NoEvalCall)
3203               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3204               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3205               .ArgConstraint(
3206                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3207 
3208     // int getsockname(int socket, struct sockaddr *restrict address,
3209     //                 socklen_t *restrict address_len);
3210     if (!addToFunctionSummaryMap(
3211             "getsockname",
3212             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3213                                Socklen_tPtrRestrictTy},
3214                       RetType{IntTy}),
3215             Summary(NoEvalCall)
3216                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3217                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3218                 .ArgConstraint(
3219                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3220                 .ArgConstraint(NotNull(ArgNo(1)))
3221                 .ArgConstraint(NotNull(ArgNo(2)))))
3222       addToFunctionSummaryMap(
3223           "getsockname",
3224           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3225                     RetType{IntTy}),
3226           Summary(NoEvalCall)
3227               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3228               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3229               .ArgConstraint(
3230                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3231 
3232     // int connect(int socket, const struct sockaddr *address, socklen_t
3233     //             address_len);
3234     if (!addToFunctionSummaryMap(
3235             "connect",
3236             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3237                       RetType{IntTy}),
3238             Summary(NoEvalCall)
3239                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3240                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3241                 .ArgConstraint(
3242                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3243                 .ArgConstraint(NotNull(ArgNo(1)))))
3244       addToFunctionSummaryMap(
3245           "connect",
3246           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3247           Summary(NoEvalCall)
3248               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3249               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3250               .ArgConstraint(
3251                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3252 
3253     auto Recvfrom =
3254         Summary(NoEvalCall)
3255             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3256                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3257                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3258             .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3259                    ArgumentCondition(2, WithinRange, SingleValue(0))},
3260                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3261             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3262             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3263             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3264                                       /*BufSize=*/ArgNo(2)));
3265     if (!addToFunctionSummaryMap(
3266             "recvfrom",
3267             // ssize_t recvfrom(int socket, void *restrict buffer,
3268             //                  size_t length,
3269             //                  int flags, struct sockaddr *restrict address,
3270             //                  socklen_t *restrict address_len);
3271             Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3272                                StructSockaddrPtrRestrictTy,
3273                                Socklen_tPtrRestrictTy},
3274                       RetType{Ssize_tTy}),
3275             Recvfrom))
3276       addToFunctionSummaryMap(
3277           "recvfrom",
3278           Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3279                              Irrelevant, Socklen_tPtrRestrictTy},
3280                     RetType{Ssize_tTy}),
3281           Recvfrom);
3282 
3283     auto Sendto =
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     if (!addToFunctionSummaryMap(
3296             "sendto",
3297             // ssize_t sendto(int socket, const void *message, size_t length,
3298             //                int flags, const struct sockaddr *dest_addr,
3299             //                socklen_t dest_len);
3300             Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
3301                                ConstStructSockaddrPtrTy, Socklen_tTy},
3302                       RetType{Ssize_tTy}),
3303             Sendto))
3304       addToFunctionSummaryMap(
3305           "sendto",
3306           Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
3307                              Socklen_tTy},
3308                     RetType{Ssize_tTy}),
3309           Sendto);
3310 
3311     // int listen(int sockfd, int backlog);
3312     addToFunctionSummaryMap(
3313         "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3314         Summary(NoEvalCall)
3315             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3316             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3317             .ArgConstraint(
3318                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3319 
3320     // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3321     addToFunctionSummaryMap(
3322         "recv",
3323         Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
3324                   RetType{Ssize_tTy}),
3325         Summary(NoEvalCall)
3326             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3327                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3328                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3329             .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3330                    ArgumentCondition(2, WithinRange, SingleValue(0))},
3331                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3332             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3333             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3334             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3335                                       /*BufSize=*/ArgNo(2))));
3336 
3337     std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3338     std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3339     std::optional<QualType> ConstStructMsghdrPtrTy =
3340         getPointerTy(getConstTy(StructMsghdrTy));
3341 
3342     // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3343     addToFunctionSummaryMap(
3344         "recvmsg",
3345         Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3346                   RetType{Ssize_tTy}),
3347         Summary(NoEvalCall)
3348             .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3349                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3350             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3351             .ArgConstraint(
3352                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3353 
3354     // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3355     addToFunctionSummaryMap(
3356         "sendmsg",
3357         Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3358                   RetType{Ssize_tTy}),
3359         Summary(NoEvalCall)
3360             .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3361                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3362             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3363             .ArgConstraint(
3364                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3365 
3366     // int setsockopt(int socket, int level, int option_name,
3367     //                const void *option_value, socklen_t option_len);
3368     addToFunctionSummaryMap(
3369         "setsockopt",
3370         Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3371                   RetType{IntTy}),
3372         Summary(NoEvalCall)
3373             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3374             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3375             .ArgConstraint(NotNullBuffer(ArgNo(3), ArgNo(4)))
3376             .ArgConstraint(
3377                 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3378             .ArgConstraint(
3379                 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3380 
3381     // int getsockopt(int socket, int level, int option_name,
3382     //                void *restrict option_value,
3383     //                socklen_t *restrict option_len);
3384     addToFunctionSummaryMap(
3385         "getsockopt",
3386         Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3387                            Socklen_tPtrRestrictTy},
3388                   RetType{IntTy}),
3389         Summary(NoEvalCall)
3390             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3391             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3392             .ArgConstraint(NotNull(ArgNo(3)))
3393             .ArgConstraint(NotNull(ArgNo(4))));
3394 
3395     // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3396     addToFunctionSummaryMap(
3397         "send",
3398         Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
3399                   RetType{Ssize_tTy}),
3400         Summary(NoEvalCall)
3401             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3402                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3403                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3404             .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3405                    ArgumentCondition(2, WithinRange, SingleValue(0))},
3406                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3407             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3408             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3409             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3410                                       /*BufSize=*/ArgNo(2))));
3411 
3412     // int socketpair(int domain, int type, int protocol, int sv[2]);
3413     addToFunctionSummaryMap(
3414         "socketpair",
3415         Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3416         Summary(NoEvalCall)
3417             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3418             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3419             .ArgConstraint(NotNull(ArgNo(3))));
3420 
3421     // int shutdown(int socket, int how);
3422     addToFunctionSummaryMap(
3423         "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3424         Summary(NoEvalCall)
3425             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3426             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3427             .ArgConstraint(
3428                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3429 
3430     // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3431     //                 char *restrict node, socklen_t nodelen,
3432     //                 char *restrict service,
3433     //                 socklen_t servicelen, int flags);
3434     //
3435     // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3436     // parameter is never handled as a transparent union in netdb.h
3437     addToFunctionSummaryMap(
3438         "getnameinfo",
3439         Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3440                            CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3441                            Socklen_tTy, IntTy},
3442                   RetType{IntTy}),
3443         Summary(NoEvalCall)
3444             .ArgConstraint(
3445                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3446             .ArgConstraint(
3447                 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3448             .ArgConstraint(
3449                 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3450             .ArgConstraint(
3451                 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3452             .ArgConstraint(
3453                 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3454             .ArgConstraint(
3455                 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3456 
3457     std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3458     std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3459 
3460     // int utime(const char *filename, struct utimbuf *buf);
3461     addToFunctionSummaryMap(
3462         "utime",
3463         Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3464         Summary(NoEvalCall)
3465             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3466             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3467             .ArgConstraint(NotNull(ArgNo(0))));
3468 
3469     std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3470     std::optional<QualType> StructTimespecPtrTy =
3471         getPointerTy(StructTimespecTy);
3472     std::optional<QualType> ConstStructTimespecPtrTy =
3473         getPointerTy(getConstTy(StructTimespecTy));
3474 
3475     // int futimens(int fd, const struct timespec times[2]);
3476     addToFunctionSummaryMap(
3477         "futimens",
3478         Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3479         Summary(NoEvalCall)
3480             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3481             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3482             .ArgConstraint(
3483                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3484 
3485     // int utimensat(int dirfd, const char *pathname,
3486     //               const struct timespec times[2], int flags);
3487     addToFunctionSummaryMap(
3488         "utimensat",
3489         Signature(
3490             ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
3491             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> StructTimevalTy = lookupTy("timeval");
3498     std::optional<QualType> ConstStructTimevalPtrTy =
3499         getPointerTy(getConstTy(StructTimevalTy));
3500 
3501     // int utimes(const char *filename, const struct timeval times[2]);
3502     addToFunctionSummaryMap(
3503         "utimes",
3504         Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3505                   RetType{IntTy}),
3506         Summary(NoEvalCall)
3507             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3508             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3509             .ArgConstraint(NotNull(ArgNo(0))));
3510 
3511     // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3512     addToFunctionSummaryMap(
3513         "nanosleep",
3514         Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3515                   RetType{IntTy}),
3516         Summary(NoEvalCall)
3517             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3518             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3519             .ArgConstraint(NotNull(ArgNo(0))));
3520 
3521     std::optional<QualType> Time_tTy = lookupTy("time_t");
3522     std::optional<QualType> ConstTime_tPtrTy =
3523         getPointerTy(getConstTy(Time_tTy));
3524     std::optional<QualType> ConstTime_tPtrRestrictTy =
3525         getRestrictTy(ConstTime_tPtrTy);
3526 
3527     std::optional<QualType> StructTmTy = lookupTy("tm");
3528     std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3529     std::optional<QualType> StructTmPtrRestrictTy =
3530         getRestrictTy(StructTmPtrTy);
3531     std::optional<QualType> ConstStructTmPtrTy =
3532         getPointerTy(getConstTy(StructTmTy));
3533     std::optional<QualType> ConstStructTmPtrRestrictTy =
3534         getRestrictTy(ConstStructTmPtrTy);
3535 
3536     // struct tm * localtime(const time_t *tp);
3537     addToFunctionSummaryMap(
3538         "localtime",
3539         Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3540         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3541 
3542     // struct tm *localtime_r(const time_t *restrict timer,
3543     //                        struct tm *restrict result);
3544     addToFunctionSummaryMap(
3545         "localtime_r",
3546         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3547                   RetType{StructTmPtrTy}),
3548         Summary(NoEvalCall)
3549             .ArgConstraint(NotNull(ArgNo(0)))
3550             .ArgConstraint(NotNull(ArgNo(1))));
3551 
3552     // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3553     addToFunctionSummaryMap(
3554         "asctime_r",
3555         Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3556                   RetType{CharPtrTy}),
3557         Summary(NoEvalCall)
3558             .ArgConstraint(NotNull(ArgNo(0)))
3559             .ArgConstraint(NotNull(ArgNo(1)))
3560             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3561                                       /*MinBufSize=*/BVF.getValue(26, IntTy))));
3562 
3563     // char *ctime_r(const time_t *timep, char *buf);
3564     addToFunctionSummaryMap(
3565         "ctime_r",
3566         Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3567         Summary(NoEvalCall)
3568             .ArgConstraint(NotNull(ArgNo(0)))
3569             .ArgConstraint(NotNull(ArgNo(1)))
3570             .ArgConstraint(BufferSize(
3571                 /*Buffer=*/ArgNo(1),
3572                 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3573 
3574     // struct tm *gmtime_r(const time_t *restrict timer,
3575     //                     struct tm *restrict result);
3576     addToFunctionSummaryMap(
3577         "gmtime_r",
3578         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3579                   RetType{StructTmPtrTy}),
3580         Summary(NoEvalCall)
3581             .ArgConstraint(NotNull(ArgNo(0)))
3582             .ArgConstraint(NotNull(ArgNo(1))));
3583 
3584     // struct tm * gmtime(const time_t *tp);
3585     addToFunctionSummaryMap(
3586         "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3587         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3588 
3589     std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3590 
3591     // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3592     addToFunctionSummaryMap(
3593         "clock_gettime",
3594         Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3595         Summary(NoEvalCall)
3596             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3597             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3598             .ArgConstraint(NotNull(ArgNo(1))));
3599 
3600     std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3601     std::optional<QualType> StructItimervalPtrTy =
3602         getPointerTy(StructItimervalTy);
3603 
3604     // int getitimer(int which, struct itimerval *curr_value);
3605     addToFunctionSummaryMap(
3606         "getitimer",
3607         Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3608         Summary(NoEvalCall)
3609             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3610             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3611             .ArgConstraint(NotNull(ArgNo(1))));
3612 
3613     std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3614     std::optional<QualType> Pthread_cond_tPtrTy =
3615         getPointerTy(Pthread_cond_tTy);
3616     std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3617     std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3618     std::optional<QualType> Pthread_tPtrRestrictTy =
3619         getRestrictTy(Pthread_tPtrTy);
3620     std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3621     std::optional<QualType> Pthread_mutex_tPtrTy =
3622         getPointerTy(Pthread_mutex_tTy);
3623     std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3624         getRestrictTy(Pthread_mutex_tPtrTy);
3625     std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3626     std::optional<QualType> Pthread_attr_tPtrTy =
3627         getPointerTy(Pthread_attr_tTy);
3628     std::optional<QualType> ConstPthread_attr_tPtrTy =
3629         getPointerTy(getConstTy(Pthread_attr_tTy));
3630     std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3631         getRestrictTy(ConstPthread_attr_tPtrTy);
3632     std::optional<QualType> Pthread_mutexattr_tTy =
3633         lookupTy("pthread_mutexattr_t");
3634     std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3635         getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3636     std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3637         getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3638 
3639     QualType PthreadStartRoutineTy = getPointerTy(
3640         ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3641                              FunctionProtoType::ExtProtoInfo()));
3642 
3643     // int pthread_cond_signal(pthread_cond_t *cond);
3644     // int pthread_cond_broadcast(pthread_cond_t *cond);
3645     addToFunctionSummaryMap(
3646         {"pthread_cond_signal", "pthread_cond_broadcast"},
3647         Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3648         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3649 
3650     // int pthread_create(pthread_t *restrict thread,
3651     //                    const pthread_attr_t *restrict attr,
3652     //                    void *(*start_routine)(void*), void *restrict arg);
3653     addToFunctionSummaryMap(
3654         "pthread_create",
3655         Signature(ArgTypes{Pthread_tPtrRestrictTy,
3656                            ConstPthread_attr_tPtrRestrictTy,
3657                            PthreadStartRoutineTy, VoidPtrRestrictTy},
3658                   RetType{IntTy}),
3659         Summary(NoEvalCall)
3660             .ArgConstraint(NotNull(ArgNo(0)))
3661             .ArgConstraint(NotNull(ArgNo(2))));
3662 
3663     // int pthread_attr_destroy(pthread_attr_t *attr);
3664     // int pthread_attr_init(pthread_attr_t *attr);
3665     addToFunctionSummaryMap(
3666         {"pthread_attr_destroy", "pthread_attr_init"},
3667         Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3668         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3669 
3670     // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3671     //                               size_t *restrict stacksize);
3672     // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3673     //                               size_t *restrict guardsize);
3674     addToFunctionSummaryMap(
3675         {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3676         Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3677                   RetType{IntTy}),
3678         Summary(NoEvalCall)
3679             .ArgConstraint(NotNull(ArgNo(0)))
3680             .ArgConstraint(NotNull(ArgNo(1))));
3681 
3682     // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3683     // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3684     addToFunctionSummaryMap(
3685         {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3686         Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
3687         Summary(NoEvalCall)
3688             .ArgConstraint(NotNull(ArgNo(0)))
3689             .ArgConstraint(
3690                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3691 
3692     // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3693     //                        pthread_mutexattr_t *restrict attr);
3694     addToFunctionSummaryMap(
3695         "pthread_mutex_init",
3696         Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3697                            ConstPthread_mutexattr_tPtrRestrictTy},
3698                   RetType{IntTy}),
3699         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3700 
3701     // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3702     // int pthread_mutex_lock(pthread_mutex_t *mutex);
3703     // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3704     // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3705     addToFunctionSummaryMap(
3706         {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3707          "pthread_mutex_unlock"},
3708         Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3709         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3710   }
3711 
3712   // Functions for testing.
3713   if (AddTestFunctions) {
3714     const RangeInt IntMin = BVF.getMinValue(IntTy)->getLimitedValue();
3715 
3716     addToFunctionSummaryMap(
3717         "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3718         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3719 
3720     addToFunctionSummaryMap(
3721         "__not_null_buffer",
3722         Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),
3723         Summary(EvalCallAsPure)
3724             .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
3725 
3726     // Test inside range constraints.
3727     addToFunctionSummaryMap(
3728         "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3729         Summary(EvalCallAsPure)
3730             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
3731     addToFunctionSummaryMap(
3732         "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3733         Summary(EvalCallAsPure)
3734             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3735     addToFunctionSummaryMap(
3736         "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3737         Summary(EvalCallAsPure)
3738             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
3739     addToFunctionSummaryMap(
3740         "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3741         Summary(EvalCallAsPure)
3742             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
3743     addToFunctionSummaryMap(
3744         "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3745         Summary(EvalCallAsPure)
3746             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
3747     addToFunctionSummaryMap(
3748         "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3749         Summary(EvalCallAsPure)
3750             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
3751     addToFunctionSummaryMap("__range_m1_inf",
3752                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3753                             Summary(EvalCallAsPure)
3754                                 .ArgConstraint(ArgumentCondition(
3755                                     0U, WithinRange, Range(-1, IntMax))));
3756     addToFunctionSummaryMap("__range_0_inf",
3757                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3758                             Summary(EvalCallAsPure)
3759                                 .ArgConstraint(ArgumentCondition(
3760                                     0U, WithinRange, Range(0, IntMax))));
3761     addToFunctionSummaryMap("__range_1_inf",
3762                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3763                             Summary(EvalCallAsPure)
3764                                 .ArgConstraint(ArgumentCondition(
3765                                     0U, WithinRange, Range(1, IntMax))));
3766     addToFunctionSummaryMap("__range_minf_m1",
3767                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3768                             Summary(EvalCallAsPure)
3769                                 .ArgConstraint(ArgumentCondition(
3770                                     0U, WithinRange, Range(IntMin, -1))));
3771     addToFunctionSummaryMap("__range_minf_0",
3772                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3773                             Summary(EvalCallAsPure)
3774                                 .ArgConstraint(ArgumentCondition(
3775                                     0U, WithinRange, Range(IntMin, 0))));
3776     addToFunctionSummaryMap("__range_minf_1",
3777                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3778                             Summary(EvalCallAsPure)
3779                                 .ArgConstraint(ArgumentCondition(
3780                                     0U, WithinRange, Range(IntMin, 1))));
3781     addToFunctionSummaryMap("__range_1_2__4_6",
3782                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3783                             Summary(EvalCallAsPure)
3784                                 .ArgConstraint(ArgumentCondition(
3785                                     0U, WithinRange, Range({1, 2}, {4, 6}))));
3786     addToFunctionSummaryMap(
3787         "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3788         Summary(EvalCallAsPure)
3789             .ArgConstraint(ArgumentCondition(0U, WithinRange,
3790                                              Range({1, 2}, {4, IntMax}))));
3791 
3792     // Test out of range constraints.
3793     addToFunctionSummaryMap(
3794         "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3795         Summary(EvalCallAsPure)
3796             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
3797     addToFunctionSummaryMap(
3798         "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3799         Summary(EvalCallAsPure)
3800             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3801     addToFunctionSummaryMap(
3802         "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3803         Summary(EvalCallAsPure)
3804             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
3805     addToFunctionSummaryMap(
3806         "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3807         Summary(EvalCallAsPure)
3808             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
3809     addToFunctionSummaryMap(
3810         "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3811         Summary(EvalCallAsPure)
3812             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
3813     addToFunctionSummaryMap(
3814         "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3815         Summary(EvalCallAsPure)
3816             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
3817     addToFunctionSummaryMap("__range_out_m1_inf",
3818                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3819                             Summary(EvalCallAsPure)
3820                                 .ArgConstraint(ArgumentCondition(
3821                                     0U, OutOfRange, Range(-1, IntMax))));
3822     addToFunctionSummaryMap("__range_out_0_inf",
3823                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3824                             Summary(EvalCallAsPure)
3825                                 .ArgConstraint(ArgumentCondition(
3826                                     0U, OutOfRange, Range(0, IntMax))));
3827     addToFunctionSummaryMap("__range_out_1_inf",
3828                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3829                             Summary(EvalCallAsPure)
3830                                 .ArgConstraint(ArgumentCondition(
3831                                     0U, OutOfRange, Range(1, IntMax))));
3832     addToFunctionSummaryMap("__range_out_minf_m1",
3833                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3834                             Summary(EvalCallAsPure)
3835                                 .ArgConstraint(ArgumentCondition(
3836                                     0U, OutOfRange, Range(IntMin, -1))));
3837     addToFunctionSummaryMap("__range_out_minf_0",
3838                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3839                             Summary(EvalCallAsPure)
3840                                 .ArgConstraint(ArgumentCondition(
3841                                     0U, OutOfRange, Range(IntMin, 0))));
3842     addToFunctionSummaryMap("__range_out_minf_1",
3843                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3844                             Summary(EvalCallAsPure)
3845                                 .ArgConstraint(ArgumentCondition(
3846                                     0U, OutOfRange, Range(IntMin, 1))));
3847     addToFunctionSummaryMap("__range_out_1_2__4_6",
3848                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3849                             Summary(EvalCallAsPure)
3850                                 .ArgConstraint(ArgumentCondition(
3851                                     0U, OutOfRange, Range({1, 2}, {4, 6}))));
3852     addToFunctionSummaryMap(
3853         "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3854         Summary(EvalCallAsPure)
3855             .ArgConstraint(
3856                 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3857 
3858     // Test range kind.
3859     addToFunctionSummaryMap(
3860         "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3861         Summary(EvalCallAsPure)
3862             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3863     addToFunctionSummaryMap(
3864         "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3865         Summary(EvalCallAsPure)
3866             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3867 
3868     addToFunctionSummaryMap(
3869         "__two_constrained_args",
3870         Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3871         Summary(EvalCallAsPure)
3872             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
3873             .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
3874     addToFunctionSummaryMap(
3875         "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3876         Summary(EvalCallAsPure)
3877             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
3878             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
3879     addToFunctionSummaryMap(
3880         "__defaultparam",
3881         Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3882         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3883     addToFunctionSummaryMap(
3884         "__variadic",
3885         Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3886         Summary(EvalCallAsPure)
3887             .ArgConstraint(NotNull(ArgNo(0)))
3888             .ArgConstraint(NotNull(ArgNo(1))));
3889     addToFunctionSummaryMap(
3890         "__buf_size_arg_constraint",
3891         Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
3892         Summary(EvalCallAsPure)
3893             .ArgConstraint(
3894                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
3895     addToFunctionSummaryMap(
3896         "__buf_size_arg_constraint_mul",
3897         Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
3898         Summary(EvalCallAsPure)
3899             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
3900                                       /*BufSizeMultiplier=*/ArgNo(2))));
3901     addToFunctionSummaryMap(
3902         "__buf_size_arg_constraint_concrete",
3903         Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3904         Summary(EvalCallAsPure)
3905             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3906                                       /*BufSize=*/BVF.getValue(10, IntTy))));
3907     addToFunctionSummaryMap(
3908         {"__test_restrict_param_0", "__test_restrict_param_1",
3909          "__test_restrict_param_2"},
3910         Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3911         Summary(EvalCallAsPure));
3912 
3913     // Test the application of cases.
3914     addToFunctionSummaryMap(
3915         "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3916         Summary(EvalCallAsPure)
3917             .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
3918                   ErrnoIrrelevant, "Function returns 0")
3919             .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
3920                   ErrnoIrrelevant, "Function returns 1"));
3921     addToFunctionSummaryMap(
3922         "__test_case_range_1_2__4_6",
3923         Signature(ArgTypes{IntTy}, RetType{IntTy}),
3924         Summary(EvalCallAsPure)
3925             .Case({ArgumentCondition(0U, WithinRange,
3926                                      IntRangeVector{{IntMin, 0}, {3, 3}}),
3927                    ReturnValueCondition(WithinRange, SingleValue(1))},
3928                   ErrnoIrrelevant)
3929             .Case({ArgumentCondition(0U, WithinRange,
3930                                      IntRangeVector{{3, 3}, {7, IntMax}}),
3931                    ReturnValueCondition(WithinRange, SingleValue(2))},
3932                   ErrnoIrrelevant)
3933             .Case({ArgumentCondition(0U, WithinRange,
3934                                      IntRangeVector{{IntMin, 0}, {7, IntMax}}),
3935                    ReturnValueCondition(WithinRange, SingleValue(3))},
3936                   ErrnoIrrelevant)
3937             .Case({ArgumentCondition(
3938                        0U, WithinRange,
3939                        IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
3940                    ReturnValueCondition(WithinRange, SingleValue(4))},
3941                   ErrnoIrrelevant));
3942   }
3943 }
3944 
3945 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
3946   auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
3947   Checker->CheckName = mgr.getCurrentCheckerName();
3948   const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
3949   Checker->DisplayLoadedSummaries =
3950       Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3951   Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3952   Checker->ShouldAssumeControlledEnvironment =
3953       Opts.ShouldAssumeControlledEnvironment;
3954 }
3955 
3956 bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3957     const CheckerManager &mgr) {
3958   return true;
3959 }
3960 
3961 void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
3962   auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
3963   Checker->AddTestFunctions = true;
3964 }
3965 
3966 bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3967     const CheckerManager &mgr) {
3968   return true;
3969 }
3970