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