xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp (revision f12808ab20369c85ddb602e5a78bab40d16bb83f)
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       R->markInteresting(Call.getArgSVal(ArgN));
839       // All tracked arguments are important, highlight them.
840       R->addRange(Call.getArgSourceRange(ArgN));
841     }
842 
843     C.emitReport(std::move(R));
844   }
845 
846   /// These are the errno constraints that can be passed to summary cases.
847   /// One of these should fit for a single summary case.
848   /// Usually if a failure return value exists for function, that function
849   /// needs different cases for success and failure with different errno
850   /// constraints (and different return value constraints).
851   const NoErrnoConstraint ErrnoUnchanged{};
852   const ResetErrnoConstraint ErrnoIrrelevant{};
853   const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
854   const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
855   const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
856 };
857 
858 int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
859 
860 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
861     std::numeric_limits<ArgNo>::max();
862 
863 static BasicValueFactory &getBVF(ProgramStateRef State) {
864   ProgramStateManager &Mgr = State->getStateManager();
865   SValBuilder &SVB = Mgr.getSValBuilder();
866   return SVB.getBasicValueFactory();
867 }
868 
869 } // end of anonymous namespace
870 
871 void StdLibraryFunctionsChecker::printArgDesc(
872     StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
873   Out << std::to_string(ArgN + 1);
874   Out << llvm::getOrdinalSuffix(ArgN + 1);
875   Out << " argument";
876 }
877 
878 void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
879                                                    ProgramStateRef State,
880                                                    const CallEvent &Call,
881                                                    llvm::raw_ostream &Out) {
882   if (const llvm::APSInt *Val =
883           State->getStateManager().getSValBuilder().getKnownValue(
884               State, getArgSVal(Call, ArgN)))
885     Out << " (which is " << *Val << ")";
886 }
887 
888 void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
889                                                        llvm::APSInt RMax,
890                                                        QualType ArgT,
891                                                        BasicValueFactory &BVF,
892                                                        llvm::raw_ostream &Out) {
893   if (RMin.isZero() && RMax.isZero())
894     Out << "zero";
895   else if (RMin == RMax)
896     Out << RMin;
897   else if (RMin == BVF.getMinValue(ArgT)) {
898     if (RMax == -1)
899       Out << "< 0";
900     else
901       Out << "<= " << RMax;
902   } else if (RMax == BVF.getMaxValue(ArgT)) {
903     if (RMin.isOne())
904       Out << "> 0";
905     else
906       Out << ">= " << RMin;
907   } else if (RMin.isNegative() == RMax.isNegative() &&
908              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
909     Out << RMin << " or " << RMax;
910   } else {
911     Out << "between " << RMin << " and " << RMax;
912   }
913 }
914 
915 void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
916                                                       llvm::APSInt RMax,
917                                                       QualType ArgT,
918                                                       BasicValueFactory &BVF,
919                                                       llvm::raw_ostream &Out) {
920   if (RMin.isZero() && RMax.isZero())
921     Out << "nonzero";
922   else if (RMin == RMax) {
923     Out << "not equal to " << RMin;
924   } else if (RMin == BVF.getMinValue(ArgT)) {
925     if (RMax == -1)
926       Out << ">= 0";
927     else
928       Out << "> " << RMax;
929   } else if (RMax == BVF.getMaxValue(ArgT)) {
930     if (RMin.isOne())
931       Out << "<= 0";
932     else
933       Out << "< " << RMin;
934   } else if (RMin.isNegative() == RMax.isNegative() &&
935              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
936     Out << "not " << RMin << " and not " << RMax;
937   } else {
938     Out << "not between " << RMin << " and " << RMax;
939   }
940 }
941 
942 void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
943     BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
944   if (Ranges.empty())
945     return;
946 
947   for (auto [Start, End] : getRanges()) {
948     const llvm::APSInt &Min = BVF.getValue(Start, ArgT);
949     const llvm::APSInt &Max = BVF.getValue(End, ArgT);
950     assert(Min <= Max);
951     if (!F(Min, Max))
952       return;
953   }
954 }
955 
956 void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
957     BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
958   if (Ranges.empty())
959     return;
960 
961   const IntRangeVector &R = getRanges();
962   size_t E = R.size();
963 
964   const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);
965   const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);
966 
967   const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);
968   const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);
969 
970   // Iterate over the "holes" between intervals.
971   for (size_t I = 1; I != E; ++I) {
972     const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);
973     const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);
974     if (Min <= Max) {
975       if (!F(Min, Max))
976         return;
977     }
978   }
979   // Check the interval [T_MIN, min(R) - 1].
980   if (RangeLeft != PlusInf) {
981     assert(MinusInf <= RangeLeft);
982     if (!F(MinusInf, RangeLeft))
983       return;
984   }
985   // Check the interval [max(R) + 1, T_MAX],
986   if (RangeRight != MinusInf) {
987     assert(RangeRight <= PlusInf);
988     if (!F(RangeRight, PlusInf))
989       return;
990   }
991 }
992 
993 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
994     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
995     CheckerContext &C) const {
996   ConstraintManager &CM = C.getConstraintManager();
997   SVal V = getArgSVal(Call, getArgNo());
998   QualType T = Summary.getArgType(getArgNo());
999 
1000   if (auto N = V.getAs<NonLoc>()) {
1001     auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,
1002                                    const llvm::APSInt &Max) {
1003       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
1004       return static_cast<bool>(State);
1005     };
1006     // "OutOfRange R" is handled by excluding all ranges in R.
1007     // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
1008     applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,
1009                  ExcludeRangeFromArg);
1010   }
1011 
1012   return State;
1013 }
1014 
1015 void StdLibraryFunctionsChecker::RangeConstraint::describe(
1016     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1017     const Summary &Summary, llvm::raw_ostream &Out) const {
1018 
1019   BasicValueFactory &BVF = getBVF(State);
1020   QualType T = Summary.getArgType(getArgNo());
1021 
1022   Out << ((DK == Violation) ? "should be " : "is ");
1023   if (!Description.empty()) {
1024     Out << Description;
1025   } else {
1026     unsigned I = Ranges.size();
1027     if (Kind == WithinRange) {
1028       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1029         appendInsideRangeDesc(BVF.getValue(R.first, T),
1030                               BVF.getValue(R.second, T), T, BVF, Out);
1031         if (--I > 0)
1032           Out << " or ";
1033       }
1034     } else {
1035       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1036         appendOutOfRangeDesc(BVF.getValue(R.first, T),
1037                              BVF.getValue(R.second, T), T, BVF, Out);
1038         if (--I > 0)
1039           Out << " and ";
1040       }
1041     }
1042   }
1043 }
1044 
1045 bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
1046     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1047     llvm::raw_ostream &Out) const {
1048   unsigned int NRanges = 0;
1049   bool HaveAllRanges = true;
1050 
1051   ProgramStateManager &Mgr = State->getStateManager();
1052   BasicValueFactory &BVF = Mgr.getSValBuilder().getBasicValueFactory();
1053   ConstraintManager &CM = Mgr.getConstraintManager();
1054   SVal V = getArgSVal(Call, getArgNo());
1055 
1056   if (auto N = V.getAs<NonLoc>()) {
1057     if (const llvm::APSInt *Int = N->getAsInteger()) {
1058       Out << "is ";
1059       Out << *Int;
1060       return true;
1061     }
1062     QualType T = Summary.getArgType(getArgNo());
1063     SmallString<128> MoreInfo;
1064     llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
1065     auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
1066       if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
1067         if (NRanges > 0)
1068           MoreInfoOs << " or ";
1069         appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
1070         ++NRanges;
1071       } else {
1072         HaveAllRanges = false;
1073       }
1074       return true;
1075     };
1076 
1077     applyOnRange(Kind, BVF, T, ApplyF);
1078     assert(NRanges > 0);
1079     if (!HaveAllRanges || NRanges == 1) {
1080       Out << "is ";
1081       Out << MoreInfo;
1082       return true;
1083     }
1084   }
1085   return false;
1086 }
1087 
1088 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
1089     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1090     CheckerContext &C) const {
1091 
1092   ProgramStateManager &Mgr = State->getStateManager();
1093   SValBuilder &SVB = Mgr.getSValBuilder();
1094   QualType CondT = SVB.getConditionType();
1095   QualType T = Summary.getArgType(getArgNo());
1096   SVal V = getArgSVal(Call, getArgNo());
1097 
1098   BinaryOperator::Opcode Op = getOpcode();
1099   ArgNo OtherArg = getOtherArgNo();
1100   SVal OtherV = getArgSVal(Call, OtherArg);
1101   QualType OtherT = Summary.getArgType(OtherArg);
1102   // Note: we avoid integral promotion for comparison.
1103   OtherV = SVB.evalCast(OtherV, T, OtherT);
1104   if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
1105                        .getAs<DefinedOrUnknownSVal>())
1106     State = State->assume(*CompV, true);
1107   return State;
1108 }
1109 
1110 ProgramStateRef StdLibraryFunctionsChecker::NotNullConstraint::apply(
1111     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1112     CheckerContext &C) const {
1113   SVal V = getArgSVal(Call, getArgNo());
1114   if (V.isUndef())
1115     return State;
1116 
1117   DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1118   if (!isa<Loc>(L))
1119     return State;
1120 
1121   return State->assume(L, CannotBeNull);
1122 }
1123 
1124 void StdLibraryFunctionsChecker::NotNullConstraint::describe(
1125     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1126     const Summary &Summary, llvm::raw_ostream &Out) const {
1127   assert(CannotBeNull &&
1128          "Describe should not be used when the value must be NULL");
1129   if (DK == Violation)
1130     Out << "should not be NULL";
1131   else
1132     Out << "is not NULL";
1133 }
1134 
1135 bool StdLibraryFunctionsChecker::NotNullConstraint::describeArgumentValue(
1136     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1137     llvm::raw_ostream &Out) const {
1138   assert(!CannotBeNull && "This function is used when the value is NULL");
1139   Out << "is NULL";
1140   return true;
1141 }
1142 
1143 ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
1144     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1145     CheckerContext &C) const {
1146   SValBuilder &SvalBuilder = C.getSValBuilder();
1147   // The buffer argument.
1148   SVal BufV = getArgSVal(Call, getArgNo());
1149 
1150   // Get the size constraint.
1151   const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
1152     if (ConcreteSize) {
1153       return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
1154     }
1155     assert(SizeArgN && "The constraint must be either a concrete value or "
1156                        "encoded in an argument.");
1157     // The size argument.
1158     SVal SizeV = getArgSVal(Call, *SizeArgN);
1159     // Multiply with another argument if given.
1160     if (SizeMultiplierArgN) {
1161       SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
1162       SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
1163                                     Summary.getArgType(*SizeArgN));
1164     }
1165     return SizeV;
1166   }();
1167 
1168   // The dynamic size of the buffer argument, got from the analyzer engine.
1169   SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1170 
1171   SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
1172                                         SvalBuilder.getContext().BoolTy);
1173   if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
1174     return State->assume(*F, true);
1175 
1176   // We can get here only if the size argument or the dynamic size is
1177   // undefined. But the dynamic size should never be undefined, only
1178   // unknown. So, here, the size of the argument is undefined, i.e. we
1179   // cannot apply the constraint. Actually, other checkers like
1180   // CallAndMessage should catch this situation earlier, because we call a
1181   // function with an uninitialized argument.
1182   llvm_unreachable("Size argument or the dynamic size is Undefined");
1183 }
1184 
1185 void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
1186     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1187     const Summary &Summary, llvm::raw_ostream &Out) const {
1188   Out << ((DK == Violation) ? "should be " : "is ");
1189   Out << "a buffer with size equal to or greater than ";
1190   if (ConcreteSize) {
1191     Out << *ConcreteSize;
1192   } else if (SizeArgN) {
1193     Out << "the value of the ";
1194     printArgDesc(*SizeArgN, Out);
1195     printArgValueInfo(*SizeArgN, State, Call, Out);
1196     if (SizeMultiplierArgN) {
1197       Out << " times the ";
1198       printArgDesc(*SizeMultiplierArgN, Out);
1199       printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
1200     }
1201   }
1202 }
1203 
1204 bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
1205     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1206     llvm::raw_ostream &Out) const {
1207   SVal BufV = getArgSVal(Call, getArgNo());
1208   SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1209   if (const llvm::APSInt *Val =
1210           State->getStateManager().getSValBuilder().getKnownValue(State,
1211                                                                   BufDynSize)) {
1212     Out << "is a buffer with size " << *Val;
1213     return true;
1214   }
1215   return false;
1216 }
1217 
1218 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
1219                                               CheckerContext &C) const {
1220   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1221   if (!FoundSummary)
1222     return;
1223 
1224   const Summary &Summary = *FoundSummary;
1225   ProgramStateRef State = C.getState();
1226 
1227   ProgramStateRef NewState = State;
1228   ExplodedNode *NewNode = C.getPredecessor();
1229   for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
1230     ValueConstraintPtr NegatedConstraint = Constraint->negate();
1231     ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
1232     ProgramStateRef FailureSt =
1233         NegatedConstraint->apply(NewState, Call, Summary, C);
1234     // The argument constraint is not satisfied.
1235     if (FailureSt && !SuccessSt) {
1236       if (ExplodedNode *N = C.generateErrorNode(State, NewNode))
1237         reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,
1238                   C);
1239       break;
1240     }
1241     // We will apply the constraint even if we cannot reason about the
1242     // argument. This means both SuccessSt and FailureSt can be true. If we
1243     // weren't applying the constraint that would mean that symbolic
1244     // execution continues on a code whose behaviour is undefined.
1245     assert(SuccessSt);
1246     NewState = SuccessSt;
1247     if (NewState != State) {
1248       SmallString<128> Msg;
1249       llvm::raw_svector_ostream Os(Msg);
1250       Os << "Assuming that the ";
1251       printArgDesc(Constraint->getArgNo(), Os);
1252       Os << " to '";
1253       Os << getFunctionName(Call);
1254       Os << "' ";
1255       Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
1256                            Os);
1257       const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
1258       NewNode = C.addTransition(
1259           NewState, NewNode,
1260           C.getNoteTag([Msg = std::move(Msg), ArgSVal](
1261                            PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1262             if (BR.isInteresting(ArgSVal))
1263               OS << Msg;
1264           }));
1265     }
1266   }
1267 }
1268 
1269 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
1270                                                CheckerContext &C) const {
1271   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1272   if (!FoundSummary)
1273     return;
1274 
1275   // Now apply the constraints.
1276   const Summary &Summary = *FoundSummary;
1277   ProgramStateRef State = C.getState();
1278   ExplodedNode *Node = C.getPredecessor();
1279 
1280   // Apply case/branch specifications.
1281   for (const SummaryCase &Case : Summary.getCases()) {
1282     ProgramStateRef NewState = State;
1283     for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
1284       NewState = Constraint->apply(NewState, Call, Summary, C);
1285       if (!NewState)
1286         break;
1287     }
1288 
1289     if (NewState)
1290       NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
1291 
1292     if (!NewState)
1293       continue;
1294 
1295     // It is possible that NewState == State is true.
1296     // It can occur if another checker has applied the state before us.
1297     // Still add these note tags, the other checker should add only its
1298     // specialized note tags. These general note tags are handled always by
1299     // StdLibraryFunctionsChecker.
1300     ExplodedNode *Pred = Node;
1301     if (!Case.getNote().empty()) {
1302       const SVal RV = Call.getReturnValue();
1303       // If there is a description for this execution branch (summary case),
1304       // use it as a note tag.
1305       std::string Note =
1306           llvm::formatv(Case.getNote().str().c_str(),
1307                         cast<NamedDecl>(Call.getDecl())->getDeclName());
1308       if (Summary.getInvalidationKd() == EvalCallAsPure) {
1309         const NoteTag *Tag = C.getNoteTag(
1310             [Node, Note, RV](PathSensitiveBugReport &BR) -> std::string {
1311               // Try to omit the note if we know in advance which branch is
1312               // taken (this means, only one branch exists).
1313               // This check is performed inside the lambda, after other
1314               // (or this) checkers had a chance to add other successors.
1315               // Dereferencing the saved node object is valid because it's part
1316               // of a bug report call sequence.
1317               // FIXME: This check is not exact. We may be here after a state
1318               // split that was performed by another checker (and can not find
1319               // the successors). This is why this check is only used in the
1320               // EvalCallAsPure case.
1321               if (BR.isInteresting(RV) && Node->succ_size() > 1)
1322                 return Note;
1323               return "";
1324             });
1325         Pred = C.addTransition(NewState, Pred, Tag);
1326       } else {
1327         const NoteTag *Tag =
1328             C.getNoteTag([Note, RV](PathSensitiveBugReport &BR) -> std::string {
1329               if (BR.isInteresting(RV))
1330                 return Note;
1331               return "";
1332             });
1333         Pred = C.addTransition(NewState, Pred, Tag);
1334       }
1335       if (!Pred)
1336         continue;
1337     }
1338 
1339     // If we can get a note tag for the errno change, add this additionally to
1340     // the previous. This note is only about value of 'errno' and is displayed
1341     // if 'errno' is interesting.
1342     if (const auto *D = dyn_cast<FunctionDecl>(Call.getDecl()))
1343       if (const NoteTag *NT =
1344               Case.getErrnoConstraint().describe(C, D->getNameAsString()))
1345         Pred = C.addTransition(NewState, Pred, NT);
1346 
1347     // Add the transition if no note tag could be added.
1348     if (Pred == Node && NewState != State)
1349       C.addTransition(NewState);
1350   }
1351 }
1352 
1353 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
1354                                           CheckerContext &C) const {
1355   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1356   if (!FoundSummary)
1357     return false;
1358 
1359   const Summary &Summary = *FoundSummary;
1360   switch (Summary.getInvalidationKd()) {
1361   case EvalCallAsPure: {
1362     ProgramStateRef State = C.getState();
1363     const LocationContext *LC = C.getLocationContext();
1364     const auto *CE = cast<CallExpr>(Call.getOriginExpr());
1365     SVal V = C.getSValBuilder().conjureSymbolVal(
1366         CE, LC, CE->getType().getCanonicalType(), C.blockCount());
1367     State = State->BindExpr(CE, LC, V);
1368 
1369     C.addTransition(State);
1370 
1371     return true;
1372   }
1373   case NoEvalCall:
1374     // Summary tells us to avoid performing eval::Call. The function is possibly
1375     // evaluated by another checker, or evaluated conservatively.
1376     return false;
1377   }
1378   llvm_unreachable("Unknown invalidation kind!");
1379 }
1380 
1381 bool StdLibraryFunctionsChecker::Signature::matches(
1382     const FunctionDecl *FD) const {
1383   assert(!isInvalid());
1384   // Check the number of arguments.
1385   if (FD->param_size() != ArgTys.size())
1386     return false;
1387 
1388   // The "restrict" keyword is illegal in C++, however, many libc
1389   // implementations use the "__restrict" compiler intrinsic in functions
1390   // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1391   // even in C++.
1392   // In case of any non-C99 languages, we don't want to match based on the
1393   // restrict qualifier because we cannot know if the given libc implementation
1394   // qualifies the paramter type or not.
1395   auto RemoveRestrict = [&FD](QualType T) {
1396     if (!FD->getASTContext().getLangOpts().C99)
1397       T.removeLocalRestrict();
1398     return T;
1399   };
1400 
1401   // Check the return type.
1402   if (!isIrrelevant(RetTy)) {
1403     QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1404     if (RetTy != FDRetTy)
1405       return false;
1406   }
1407 
1408   // Check the argument types.
1409   for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {
1410     if (isIrrelevant(ArgTy))
1411       continue;
1412     QualType FDArgTy =
1413         RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());
1414     if (ArgTy != FDArgTy)
1415       return false;
1416   }
1417 
1418   return true;
1419 }
1420 
1421 std::optional<StdLibraryFunctionsChecker::Summary>
1422 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1423                                                 CheckerContext &C) const {
1424   if (!FD)
1425     return std::nullopt;
1426 
1427   initFunctionSummaries(C);
1428 
1429   auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
1430   if (FSMI == FunctionSummaryMap.end())
1431     return std::nullopt;
1432   return FSMI->second;
1433 }
1434 
1435 std::optional<StdLibraryFunctionsChecker::Summary>
1436 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
1437                                                 CheckerContext &C) const {
1438   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1439   if (!FD)
1440     return std::nullopt;
1441   return findFunctionSummary(FD, C);
1442 }
1443 
1444 void StdLibraryFunctionsChecker::initFunctionSummaries(
1445     CheckerContext &C) const {
1446   if (SummariesInitialized)
1447     return;
1448   SummariesInitialized = true;
1449 
1450   SValBuilder &SVB = C.getSValBuilder();
1451   BasicValueFactory &BVF = SVB.getBasicValueFactory();
1452   const ASTContext &ACtx = BVF.getContext();
1453   Preprocessor &PP = C.getPreprocessor();
1454 
1455   // Helper class to lookup a type by its name.
1456   class LookupType {
1457     const ASTContext &ACtx;
1458 
1459   public:
1460     LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1461 
1462     // Find the type. If not found then the optional is not set.
1463     std::optional<QualType> operator()(StringRef Name) {
1464       IdentifierInfo &II = ACtx.Idents.get(Name);
1465       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1466       if (LookupRes.empty())
1467         return std::nullopt;
1468 
1469       // Prioritze typedef declarations.
1470       // This is needed in case of C struct typedefs. E.g.:
1471       //   typedef struct FILE FILE;
1472       // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1473       // and we have a TypedefDecl with the name 'FILE'.
1474       for (Decl *D : LookupRes)
1475         if (auto *TD = dyn_cast<TypedefNameDecl>(D))
1476           return ACtx.getTypeDeclType(TD).getCanonicalType();
1477 
1478       // Find the first TypeDecl.
1479       // There maybe cases when a function has the same name as a struct.
1480       // E.g. in POSIX: `struct stat` and the function `stat()`:
1481       //   int stat(const char *restrict path, struct stat *restrict buf);
1482       for (Decl *D : LookupRes)
1483         if (auto *TD = dyn_cast<TypeDecl>(D))
1484           return ACtx.getTypeDeclType(TD).getCanonicalType();
1485       return std::nullopt;
1486     }
1487   } lookupTy(ACtx);
1488 
1489   // Below are auxiliary classes to handle optional types that we get as a
1490   // result of the lookup.
1491   class GetRestrictTy {
1492     const ASTContext &ACtx;
1493 
1494   public:
1495     GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1496     QualType operator()(QualType Ty) {
1497       return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1498     }
1499     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1500       if (Ty)
1501         return operator()(*Ty);
1502       return std::nullopt;
1503     }
1504   } getRestrictTy(ACtx);
1505   class GetPointerTy {
1506     const ASTContext &ACtx;
1507 
1508   public:
1509     GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1510     QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1511     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1512       if (Ty)
1513         return operator()(*Ty);
1514       return std::nullopt;
1515     }
1516   } getPointerTy(ACtx);
1517   class {
1518   public:
1519     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1520       return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1521     }
1522     QualType operator()(QualType Ty) { return Ty.withConst(); }
1523   } getConstTy;
1524   class GetMaxValue {
1525     BasicValueFactory &BVF;
1526 
1527   public:
1528     GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1529     std::optional<RangeInt> operator()(QualType Ty) {
1530       return BVF.getMaxValue(Ty).getLimitedValue();
1531     }
1532     std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1533       if (Ty) {
1534         return operator()(*Ty);
1535       }
1536       return std::nullopt;
1537     }
1538   } getMaxValue(BVF);
1539 
1540   // These types are useful for writing specifications quickly,
1541   // New specifications should probably introduce more types.
1542   // Some types are hard to obtain from the AST, eg. "ssize_t".
1543   // In such cases it should be possible to provide multiple variants
1544   // of function summary for common cases (eg. ssize_t could be int or long
1545   // or long long, so three summary variants would be enough).
1546   // Of course, function variants are also useful for C++ overloads.
1547   const QualType VoidTy = ACtx.VoidTy;
1548   const QualType CharTy = ACtx.CharTy;
1549   const QualType WCharTy = ACtx.WCharTy;
1550   const QualType IntTy = ACtx.IntTy;
1551   const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1552   const QualType LongTy = ACtx.LongTy;
1553   const QualType SizeTy = ACtx.getSizeType();
1554 
1555   const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1556   const QualType IntPtrTy = getPointerTy(IntTy);   // int *
1557   const QualType UnsignedIntPtrTy =
1558       getPointerTy(UnsignedIntTy); // unsigned int *
1559   const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1560   const QualType ConstVoidPtrTy =
1561       getPointerTy(getConstTy(VoidTy));            // const void *
1562   const QualType CharPtrTy = getPointerTy(CharTy); // char *
1563   const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
1564   const QualType ConstCharPtrTy =
1565       getPointerTy(getConstTy(CharTy)); // const char *
1566   const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1567   const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1568   const QualType ConstWchar_tPtrTy =
1569       getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1570   const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1571   const QualType SizePtrTy = getPointerTy(SizeTy);
1572   const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1573 
1574   const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
1575   const RangeInt UnsignedIntMax =
1576       BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
1577   const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
1578   const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
1579 
1580   // Set UCharRangeMax to min of int or uchar maximum value.
1581   // The C standard states that the arguments of functions like isalpha must
1582   // be representable as an unsigned char. Their type is 'int', so the max
1583   // value of the argument should be min(UCharMax, IntMax). This just happen
1584   // to be true for commonly used and well tested instruction set
1585   // architectures, but not for others.
1586   const RangeInt UCharRangeMax =
1587       std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
1588 
1589   // Get platform dependent values of some macros.
1590   // Try our best to parse this from the Preprocessor, otherwise fallback to a
1591   // default value (what is found in a library header).
1592   const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
1593   const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
1594 
1595   // Auxiliary class to aid adding summaries to the summary map.
1596   struct AddToFunctionSummaryMap {
1597     const ASTContext &ACtx;
1598     FunctionSummaryMapType &Map;
1599     bool DisplayLoadedSummaries;
1600     AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1601                             bool DisplayLoadedSummaries)
1602         : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1603     }
1604 
1605     // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1606     // by the given Name, and in the global scope. The summary will be attached
1607     // to the found FunctionDecl only if the signatures match.
1608     //
1609     // Returns true if the summary has been added, false otherwise.
1610     bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1611       if (Sign.isInvalid())
1612         return false;
1613       IdentifierInfo &II = ACtx.Idents.get(Name);
1614       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1615       if (LookupRes.empty())
1616         return false;
1617       for (Decl *D : LookupRes) {
1618         if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1619           if (Sum.matchesAndSet(Sign, FD)) {
1620             auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
1621             assert(Res.second && "Function already has a summary set!");
1622             (void)Res;
1623             if (DisplayLoadedSummaries) {
1624               llvm::errs() << "Loaded summary for: ";
1625               FD->print(llvm::errs());
1626               llvm::errs() << "\n";
1627             }
1628             return true;
1629           }
1630         }
1631       }
1632       return false;
1633     }
1634     // Add the same summary for different names with the Signature explicitly
1635     // given.
1636     void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1637       for (StringRef Name : Names)
1638         operator()(Name, Sign, Sum);
1639     }
1640   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1641 
1642   // Below are helpers functions to create the summaries.
1643   auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
1644                               StringRef Desc = "") {
1645     return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
1646   };
1647   auto BufferSize = [](auto... Args) {
1648     return std::make_shared<BufferSizeConstraint>(Args...);
1649   };
1650   struct {
1651     auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1652       return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1653     }
1654     auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1655       return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1656     }
1657   } ReturnValueCondition;
1658   struct {
1659     auto operator()(RangeInt b, RangeInt e) {
1660       return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1661     }
1662     auto operator()(RangeInt b, std::optional<RangeInt> e) {
1663       if (e)
1664         return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1665       return IntRangeVector{};
1666     }
1667     auto operator()(std::pair<RangeInt, RangeInt> i0,
1668                     std::pair<RangeInt, std::optional<RangeInt>> i1) {
1669       if (i1.second)
1670         return IntRangeVector{i0, {i1.first, *(i1.second)}};
1671       return IntRangeVector{i0};
1672     }
1673   } Range;
1674   auto SingleValue = [](RangeInt v) {
1675     return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1676   };
1677   auto LessThanOrEq = BO_LE;
1678   auto NotNull = [&](ArgNo ArgN) {
1679     return std::make_shared<NotNullConstraint>(ArgN);
1680   };
1681   auto IsNull = [&](ArgNo ArgN) {
1682     return std::make_shared<NotNullConstraint>(ArgN, false);
1683   };
1684 
1685   std::optional<QualType> FileTy = lookupTy("FILE");
1686   std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
1687   std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1688 
1689   std::optional<QualType> FPosTTy = lookupTy("fpos_t");
1690   std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
1691   std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
1692   std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
1693 
1694   constexpr llvm::StringLiteral GenericSuccessMsg(
1695       "Assuming that '{0}' is successful");
1696   constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");
1697 
1698   // We are finally ready to define specifications for all supported functions.
1699   //
1700   // Argument ranges should always cover all variants. If return value
1701   // is completely unknown, omit it from the respective range set.
1702   //
1703   // Every item in the list of range sets represents a particular
1704   // execution path the analyzer would need to explore once
1705   // the call is modeled - a new program state is constructed
1706   // for every range set, and each range line in the range set
1707   // corresponds to a specific constraint within this state.
1708 
1709   // The isascii() family of functions.
1710   // The behavior is undefined if the value of the argument is not
1711   // representable as unsigned char or is not equal to EOF. See e.g. C99
1712   // 7.4.1.2 The isalpha function (p: 181-182).
1713   addToFunctionSummaryMap(
1714       "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1715       Summary(EvalCallAsPure)
1716           // Boils down to isupper() or islower() or isdigit().
1717           .Case({ArgumentCondition(0U, WithinRange,
1718                                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1719                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1720                 ErrnoIrrelevant, "Assuming the character is alphanumeric")
1721           // The locale-specific range.
1722           // No post-condition. We are completely unaware of
1723           // locale-specific return values.
1724           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1725                 ErrnoIrrelevant)
1726           .Case(
1727               {ArgumentCondition(
1728                    0U, OutOfRange,
1729                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1730                ReturnValueCondition(WithinRange, SingleValue(0))},
1731               ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
1732           .ArgConstraint(ArgumentCondition(0U, WithinRange,
1733                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
1734                                            "an unsigned char value or EOF")));
1735   addToFunctionSummaryMap(
1736       "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1737       Summary(EvalCallAsPure)
1738           .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1739                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1740                 ErrnoIrrelevant, "Assuming the character is alphabetical")
1741           // The locale-specific range.
1742           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1743                 ErrnoIrrelevant)
1744           .Case({ArgumentCondition(
1745                      0U, OutOfRange,
1746                      {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1747                  ReturnValueCondition(WithinRange, SingleValue(0))},
1748                 ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
1749   addToFunctionSummaryMap(
1750       "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1751       Summary(EvalCallAsPure)
1752           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1753                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1754                 ErrnoIrrelevant, "Assuming the character is an ASCII character")
1755           .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1756                  ReturnValueCondition(WithinRange, SingleValue(0))},
1757                 ErrnoIrrelevant,
1758                 "Assuming the character is not an ASCII character"));
1759   addToFunctionSummaryMap(
1760       "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1761       Summary(EvalCallAsPure)
1762           .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1763                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1764                 ErrnoIrrelevant, "Assuming the character is a blank character")
1765           .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1766                  ReturnValueCondition(WithinRange, SingleValue(0))},
1767                 ErrnoIrrelevant,
1768                 "Assuming the character is not a blank character"));
1769   addToFunctionSummaryMap(
1770       "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1771       Summary(EvalCallAsPure)
1772           .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1773                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1774                 ErrnoIrrelevant,
1775                 "Assuming the character is a control character")
1776           .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1777                  ReturnValueCondition(WithinRange, SingleValue(0))},
1778                 ErrnoIrrelevant,
1779                 "Assuming the character is not a control character"));
1780   addToFunctionSummaryMap(
1781       "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1782       Summary(EvalCallAsPure)
1783           .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1784                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1785                 ErrnoIrrelevant, "Assuming the character is a digit")
1786           .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1787                  ReturnValueCondition(WithinRange, SingleValue(0))},
1788                 ErrnoIrrelevant, "Assuming the character is not a digit"));
1789   addToFunctionSummaryMap(
1790       "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1791       Summary(EvalCallAsPure)
1792           .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1793                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1794                 ErrnoIrrelevant,
1795                 "Assuming the character has graphical representation")
1796           .Case(
1797               {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1798                ReturnValueCondition(WithinRange, SingleValue(0))},
1799               ErrnoIrrelevant,
1800               "Assuming the character does not have graphical representation"));
1801   addToFunctionSummaryMap(
1802       "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1803       Summary(EvalCallAsPure)
1804           // Is certainly lowercase.
1805           .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1806                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1807                 ErrnoIrrelevant, "Assuming the character is a lowercase letter")
1808           // Is ascii but not lowercase.
1809           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1810                  ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1811                  ReturnValueCondition(WithinRange, SingleValue(0))},
1812                 ErrnoIrrelevant,
1813                 "Assuming the character is not a lowercase letter")
1814           // The locale-specific range.
1815           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1816                 ErrnoIrrelevant)
1817           // Is not an unsigned char.
1818           .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1819                  ReturnValueCondition(WithinRange, SingleValue(0))},
1820                 ErrnoIrrelevant));
1821   addToFunctionSummaryMap(
1822       "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1823       Summary(EvalCallAsPure)
1824           .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1825                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1826                 ErrnoIrrelevant, "Assuming the character is printable")
1827           .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1828                  ReturnValueCondition(WithinRange, SingleValue(0))},
1829                 ErrnoIrrelevant, "Assuming the character is non-printable"));
1830   addToFunctionSummaryMap(
1831       "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1832       Summary(EvalCallAsPure)
1833           .Case({ArgumentCondition(
1834                      0U, WithinRange,
1835                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1836                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1837                 ErrnoIrrelevant, "Assuming the character is a punctuation mark")
1838           .Case({ArgumentCondition(
1839                      0U, OutOfRange,
1840                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1841                  ReturnValueCondition(WithinRange, SingleValue(0))},
1842                 ErrnoIrrelevant,
1843                 "Assuming the character is not a punctuation mark"));
1844   addToFunctionSummaryMap(
1845       "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1846       Summary(EvalCallAsPure)
1847           // Space, '\f', '\n', '\r', '\t', '\v'.
1848           .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1849                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1850                 ErrnoIrrelevant,
1851                 "Assuming the character is a whitespace character")
1852           // The locale-specific range.
1853           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1854                 ErrnoIrrelevant)
1855           .Case({ArgumentCondition(0U, OutOfRange,
1856                                    {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1857                  ReturnValueCondition(WithinRange, SingleValue(0))},
1858                 ErrnoIrrelevant,
1859                 "Assuming the character is not a whitespace character"));
1860   addToFunctionSummaryMap(
1861       "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1862       Summary(EvalCallAsPure)
1863           // Is certainly uppercase.
1864           .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1865                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1866                 ErrnoIrrelevant,
1867                 "Assuming the character is an uppercase letter")
1868           // The locale-specific range.
1869           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1870                 ErrnoIrrelevant)
1871           // Other.
1872           .Case({ArgumentCondition(0U, OutOfRange,
1873                                    {{'A', 'Z'}, {128, UCharRangeMax}}),
1874                  ReturnValueCondition(WithinRange, SingleValue(0))},
1875                 ErrnoIrrelevant,
1876                 "Assuming the character is not an uppercase letter"));
1877   addToFunctionSummaryMap(
1878       "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1879       Summary(EvalCallAsPure)
1880           .Case({ArgumentCondition(0U, WithinRange,
1881                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1882                  ReturnValueCondition(OutOfRange, SingleValue(0))},
1883                 ErrnoIrrelevant,
1884                 "Assuming the character is a hexadecimal digit")
1885           .Case({ArgumentCondition(0U, OutOfRange,
1886                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1887                  ReturnValueCondition(WithinRange, SingleValue(0))},
1888                 ErrnoIrrelevant,
1889                 "Assuming the character is not a hexadecimal digit"));
1890   addToFunctionSummaryMap(
1891       "toupper", 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       "tolower", 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   addToFunctionSummaryMap(
1903       "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1904       Summary(EvalCallAsPure)
1905           .ArgConstraint(ArgumentCondition(0U, WithinRange,
1906                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
1907                                            "an unsigned char value or EOF")));
1908 
1909   // The getc() family of functions that returns either a char or an EOF.
1910   addToFunctionSummaryMap(
1911       {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
1912       Summary(NoEvalCall)
1913           .Case({ReturnValueCondition(WithinRange,
1914                                       {{EOFv, EOFv}, {0, UCharRangeMax}})},
1915                 ErrnoIrrelevant));
1916   addToFunctionSummaryMap(
1917       "getchar", Signature(ArgTypes{}, RetType{IntTy}),
1918       Summary(NoEvalCall)
1919           .Case({ReturnValueCondition(WithinRange,
1920                                       {{EOFv, EOFv}, {0, UCharRangeMax}})},
1921                 ErrnoIrrelevant));
1922 
1923   // read()-like functions that never return more than buffer size.
1924   auto FreadSummary =
1925       Summary(NoEvalCall)
1926           .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
1927                  ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
1928                  ReturnValueCondition(BO_LT, ArgNo(2)),
1929                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
1930                 ErrnoNEZeroIrrelevant, GenericFailureMsg)
1931           .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
1932                  ReturnValueCondition(BO_EQ, ArgNo(2)),
1933                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
1934                 ErrnoMustNotBeChecked, GenericSuccessMsg)
1935           .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
1936                  ReturnValueCondition(WithinRange, SingleValue(0))},
1937                 ErrnoMustNotBeChecked, GenericSuccessMsg)
1938           .ArgConstraint(NotNull(ArgNo(0)))
1939           .ArgConstraint(NotNull(ArgNo(3)))
1940           // FIXME: It should be allowed to have a null buffer if any of
1941           // args 1 or 2 are zero. Remove NotNull check of arg 0, add a check
1942           // for non-null buffer if non-zero size to BufferSizeConstraint?
1943           .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
1944                                     /*BufSizeMultiplier=*/ArgNo(2)));
1945 
1946   // size_t fread(void *restrict ptr, size_t size, size_t nitems,
1947   //              FILE *restrict stream);
1948   addToFunctionSummaryMap(
1949       "fread",
1950       Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
1951                 RetType{SizeTy}),
1952       FreadSummary);
1953   // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
1954   //               FILE *restrict stream);
1955   addToFunctionSummaryMap("fwrite",
1956                           Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
1957                                              SizeTy, FilePtrRestrictTy},
1958                                     RetType{SizeTy}),
1959                           FreadSummary);
1960 
1961   std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
1962   std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
1963 
1964   auto ReadSummary =
1965       Summary(NoEvalCall)
1966           .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1967                  ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
1968                 ErrnoIrrelevant);
1969 
1970   // FIXME these are actually defined by POSIX and not by the C standard, we
1971   // should handle them together with the rest of the POSIX functions.
1972   // ssize_t read(int fildes, void *buf, size_t nbyte);
1973   addToFunctionSummaryMap(
1974       "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
1975       ReadSummary);
1976   // ssize_t write(int fildes, const void *buf, size_t nbyte);
1977   addToFunctionSummaryMap(
1978       "write",
1979       Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
1980       ReadSummary);
1981 
1982   auto GetLineSummary =
1983       Summary(NoEvalCall)
1984           .Case({ReturnValueCondition(WithinRange,
1985                                       Range({-1, -1}, {1, Ssize_tMax}))},
1986                 ErrnoIrrelevant);
1987 
1988   QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
1989 
1990   // getline()-like functions either fail or read at least the delimiter.
1991   // FIXME these are actually defined by POSIX and not by the C standard, we
1992   // should handle them together with the rest of the POSIX functions.
1993   // ssize_t getline(char **restrict lineptr, size_t *restrict n,
1994   //                 FILE *restrict stream);
1995   addToFunctionSummaryMap(
1996       "getline",
1997       Signature(
1998           ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
1999           RetType{Ssize_tTy}),
2000       GetLineSummary);
2001   // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2002   //                  int delimiter, FILE *restrict stream);
2003   addToFunctionSummaryMap(
2004       "getdelim",
2005       Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2006                          FilePtrRestrictTy},
2007                 RetType{Ssize_tTy}),
2008       GetLineSummary);
2009 
2010   {
2011     Summary GetenvSummary =
2012         Summary(NoEvalCall)
2013             .ArgConstraint(NotNull(ArgNo(0)))
2014             .Case({NotNull(Ret)}, ErrnoIrrelevant,
2015                   "Assuming the environment variable exists");
2016     // In untrusted environments the envvar might not exist.
2017     if (!ShouldAssumeControlledEnvironment)
2018       GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
2019                          "Assuming the environment variable does not exist");
2020 
2021     // char *getenv(const char *name);
2022     addToFunctionSummaryMap(
2023         "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2024         std::move(GetenvSummary));
2025   }
2026 
2027   if (ModelPOSIX) {
2028     const auto ReturnsZeroOrMinusOne =
2029         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
2030     const auto ReturnsZero =
2031         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2032     const auto ReturnsMinusOne =
2033         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
2034     const auto ReturnsNonnegative =
2035         ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2036     const auto ReturnsNonZero =
2037         ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2038     const auto ReturnsFileDescriptor =
2039         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
2040     const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2041 
2042     auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
2043       return std::make_shared<RangeConstraint>(
2044           ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
2045           "a valid file descriptor or AT_FDCWD");
2046     };
2047 
2048     // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2049     addToFunctionSummaryMap(
2050         "fopen",
2051         Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2052                   RetType{FilePtrTy}),
2053         Summary(NoEvalCall)
2054             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2055             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2056             .ArgConstraint(NotNull(ArgNo(0)))
2057             .ArgConstraint(NotNull(ArgNo(1))));
2058 
2059     // FILE *tmpfile(void);
2060     addToFunctionSummaryMap(
2061         "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2062         Summary(NoEvalCall)
2063             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2064             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2065 
2066     // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2067     //               FILE *restrict stream);
2068     addToFunctionSummaryMap(
2069         "freopen",
2070         Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2071                            FilePtrRestrictTy},
2072                   RetType{FilePtrTy}),
2073         Summary(NoEvalCall)
2074             .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
2075                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2076             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2077             .ArgConstraint(NotNull(ArgNo(1)))
2078             .ArgConstraint(NotNull(ArgNo(2))));
2079 
2080     // int fclose(FILE *stream);
2081     addToFunctionSummaryMap(
2082         "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2083         Summary(NoEvalCall)
2084             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2085             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2086                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2087             .ArgConstraint(NotNull(ArgNo(0))));
2088 
2089     // int fseek(FILE *stream, long offset, int whence);
2090     // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2091     // these for condition of arg 2.
2092     // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2093     addToFunctionSummaryMap(
2094         "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2095         Summary(NoEvalCall)
2096             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2097             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2098             .ArgConstraint(NotNull(ArgNo(0)))
2099             .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2100 
2101     // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2102     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2103     // "The fgetpos() function shall not change the setting of errno if
2104     // successful."
2105     addToFunctionSummaryMap(
2106         "fgetpos",
2107         Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2108                   RetType{IntTy}),
2109         Summary(NoEvalCall)
2110             .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2111             .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2112             .ArgConstraint(NotNull(ArgNo(0)))
2113             .ArgConstraint(NotNull(ArgNo(1))));
2114 
2115     // int fsetpos(FILE *stream, const fpos_t *pos);
2116     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2117     // "The fsetpos() function shall not change the setting of errno if
2118     // successful."
2119     addToFunctionSummaryMap(
2120         "fsetpos",
2121         Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2122         Summary(NoEvalCall)
2123             .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2124             .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2125             .ArgConstraint(NotNull(ArgNo(0)))
2126             .ArgConstraint(NotNull(ArgNo(1))));
2127 
2128     // long ftell(FILE *stream);
2129     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2130     // "The ftell() function shall not change the setting of errno if
2131     // successful."
2132     addToFunctionSummaryMap(
2133         "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2134         Summary(NoEvalCall)
2135             .Case({ReturnValueCondition(WithinRange, Range(1, LongMax))},
2136                   ErrnoUnchanged, GenericSuccessMsg)
2137             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2138             .ArgConstraint(NotNull(ArgNo(0))));
2139 
2140     // int fileno(FILE *stream);
2141     addToFunctionSummaryMap(
2142         "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2143         Summary(NoEvalCall)
2144             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2145                   GenericSuccessMsg)
2146             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2147             .ArgConstraint(NotNull(ArgNo(0))));
2148 
2149     // void rewind(FILE *stream);
2150     // This function indicates error only by setting of 'errno'.
2151     addToFunctionSummaryMap("rewind",
2152                             Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2153                             Summary(NoEvalCall)
2154                                 .Case({}, ErrnoMustBeChecked)
2155                                 .ArgConstraint(NotNull(ArgNo(0))));
2156 
2157     // void clearerr(FILE *stream);
2158     addToFunctionSummaryMap(
2159         "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2160         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2161 
2162     // int feof(FILE *stream);
2163     addToFunctionSummaryMap(
2164         "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2165         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2166 
2167     // int ferror(FILE *stream);
2168     addToFunctionSummaryMap(
2169         "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2170         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2171 
2172     // long a64l(const char *str64);
2173     addToFunctionSummaryMap(
2174         "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2175         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2176 
2177     // char *l64a(long value);
2178     addToFunctionSummaryMap("l64a",
2179                             Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2180                             Summary(NoEvalCall)
2181                                 .ArgConstraint(ArgumentCondition(
2182                                     0, WithinRange, Range(0, LongMax))));
2183 
2184     // int access(const char *pathname, int amode);
2185     addToFunctionSummaryMap(
2186         "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2187         Summary(NoEvalCall)
2188             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2189             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2190             .ArgConstraint(NotNull(ArgNo(0))));
2191 
2192     // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2193     addToFunctionSummaryMap(
2194         "faccessat",
2195         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2196                   RetType{IntTy}),
2197         Summary(NoEvalCall)
2198             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2199             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2200             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2201             .ArgConstraint(NotNull(ArgNo(1))));
2202 
2203     // int dup(int fildes);
2204     addToFunctionSummaryMap(
2205         "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2206         Summary(NoEvalCall)
2207             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2208             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2209             .ArgConstraint(
2210                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2211 
2212     // int dup2(int fildes1, int filedes2);
2213     addToFunctionSummaryMap(
2214         "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2215         Summary(NoEvalCall)
2216             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2217             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2218             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2219             .ArgConstraint(
2220                 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
2221 
2222     // int fdatasync(int fildes);
2223     addToFunctionSummaryMap("fdatasync",
2224                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
2225                             Summary(NoEvalCall)
2226                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2227                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2228                                 .ArgConstraint(ArgumentCondition(
2229                                     0, WithinRange, Range(0, IntMax))));
2230 
2231     // int fnmatch(const char *pattern, const char *string, int flags);
2232     addToFunctionSummaryMap(
2233         "fnmatch",
2234         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2235                   RetType{IntTy}),
2236         Summary(NoEvalCall)
2237             .ArgConstraint(NotNull(ArgNo(0)))
2238             .ArgConstraint(NotNull(ArgNo(1))));
2239 
2240     // int fsync(int fildes);
2241     addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2242                             Summary(NoEvalCall)
2243                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2244                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2245                                 .ArgConstraint(ArgumentCondition(
2246                                     0, WithinRange, Range(0, IntMax))));
2247 
2248     std::optional<QualType> Off_tTy = lookupTy("off_t");
2249 
2250     // int truncate(const char *path, off_t length);
2251     addToFunctionSummaryMap(
2252         "truncate",
2253         Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2254         Summary(NoEvalCall)
2255             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2256             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2257             .ArgConstraint(NotNull(ArgNo(0))));
2258 
2259     // int symlink(const char *oldpath, const char *newpath);
2260     addToFunctionSummaryMap(
2261         "symlink",
2262         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2263         Summary(NoEvalCall)
2264             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2265             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2266             .ArgConstraint(NotNull(ArgNo(0)))
2267             .ArgConstraint(NotNull(ArgNo(1))));
2268 
2269     // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2270     addToFunctionSummaryMap(
2271         "symlinkat",
2272         Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2273                   RetType{IntTy}),
2274         Summary(NoEvalCall)
2275             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2276             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2277             .ArgConstraint(NotNull(ArgNo(0)))
2278             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
2279             .ArgConstraint(NotNull(ArgNo(2))));
2280 
2281     // int lockf(int fd, int cmd, off_t len);
2282     addToFunctionSummaryMap(
2283         "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2284         Summary(NoEvalCall)
2285             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2286             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2287             .ArgConstraint(
2288                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2289 
2290     std::optional<QualType> Mode_tTy = lookupTy("mode_t");
2291 
2292     // int creat(const char *pathname, mode_t mode);
2293     addToFunctionSummaryMap(
2294         "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2295         Summary(NoEvalCall)
2296             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2297             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2298             .ArgConstraint(NotNull(ArgNo(0))));
2299 
2300     // unsigned int sleep(unsigned int seconds);
2301     addToFunctionSummaryMap(
2302         "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2303         Summary(NoEvalCall)
2304             .ArgConstraint(
2305                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2306 
2307     std::optional<QualType> DirTy = lookupTy("DIR");
2308     std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
2309 
2310     // int dirfd(DIR *dirp);
2311     addToFunctionSummaryMap(
2312         "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2313         Summary(NoEvalCall)
2314             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2315             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2316             .ArgConstraint(NotNull(ArgNo(0))));
2317 
2318     // unsigned int alarm(unsigned int seconds);
2319     addToFunctionSummaryMap(
2320         "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2321         Summary(NoEvalCall)
2322             .ArgConstraint(
2323                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2324 
2325     // int closedir(DIR *dir);
2326     addToFunctionSummaryMap("closedir",
2327                             Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2328                             Summary(NoEvalCall)
2329                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2330                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2331                                 .ArgConstraint(NotNull(ArgNo(0))));
2332 
2333     // char *strdup(const char *s);
2334     addToFunctionSummaryMap(
2335         "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2336         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2337 
2338     // char *strndup(const char *s, size_t n);
2339     addToFunctionSummaryMap(
2340         "strndup",
2341         Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
2342         Summary(NoEvalCall)
2343             .ArgConstraint(NotNull(ArgNo(0)))
2344             .ArgConstraint(
2345                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2346 
2347     // wchar_t *wcsdup(const wchar_t *s);
2348     addToFunctionSummaryMap(
2349         "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2350         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2351 
2352     // int mkstemp(char *template);
2353     addToFunctionSummaryMap(
2354         "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2355         Summary(NoEvalCall)
2356             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2357             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2358             .ArgConstraint(NotNull(ArgNo(0))));
2359 
2360     // char *mkdtemp(char *template);
2361     // FIXME: Improve for errno modeling.
2362     addToFunctionSummaryMap(
2363         "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
2364         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2365 
2366     // char *getcwd(char *buf, size_t size);
2367     // FIXME: Improve for errno modeling.
2368     addToFunctionSummaryMap(
2369         "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
2370         Summary(NoEvalCall)
2371             .ArgConstraint(
2372                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2373 
2374     // int mkdir(const char *pathname, mode_t mode);
2375     addToFunctionSummaryMap(
2376         "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2377         Summary(NoEvalCall)
2378             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2379             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2380             .ArgConstraint(NotNull(ArgNo(0))));
2381 
2382     // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2383     addToFunctionSummaryMap(
2384         "mkdirat",
2385         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2386         Summary(NoEvalCall)
2387             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2388             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2389             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2390             .ArgConstraint(NotNull(ArgNo(1))));
2391 
2392     std::optional<QualType> Dev_tTy = lookupTy("dev_t");
2393 
2394     // int mknod(const char *pathname, mode_t mode, dev_t dev);
2395     addToFunctionSummaryMap(
2396         "mknod",
2397         Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2398         Summary(NoEvalCall)
2399             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2400             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2401             .ArgConstraint(NotNull(ArgNo(0))));
2402 
2403     // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2404     addToFunctionSummaryMap(
2405         "mknodat",
2406         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2407                   RetType{IntTy}),
2408         Summary(NoEvalCall)
2409             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2410             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2411             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2412             .ArgConstraint(NotNull(ArgNo(1))));
2413 
2414     // int chmod(const char *path, mode_t mode);
2415     addToFunctionSummaryMap(
2416         "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2417         Summary(NoEvalCall)
2418             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2419             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2420             .ArgConstraint(NotNull(ArgNo(0))));
2421 
2422     // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2423     addToFunctionSummaryMap(
2424         "fchmodat",
2425         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2426                   RetType{IntTy}),
2427         Summary(NoEvalCall)
2428             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2429             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2430             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2431             .ArgConstraint(NotNull(ArgNo(1))));
2432 
2433     // int fchmod(int fildes, mode_t mode);
2434     addToFunctionSummaryMap(
2435         "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2436         Summary(NoEvalCall)
2437             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2438             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2439             .ArgConstraint(
2440                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2441 
2442     std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2443     std::optional<QualType> Gid_tTy = lookupTy("gid_t");
2444 
2445     // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2446     //              int flags);
2447     addToFunctionSummaryMap(
2448         "fchownat",
2449         Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2450                   RetType{IntTy}),
2451         Summary(NoEvalCall)
2452             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2453             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2454             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2455             .ArgConstraint(NotNull(ArgNo(1))));
2456 
2457     // int chown(const char *path, uid_t owner, gid_t group);
2458     addToFunctionSummaryMap(
2459         "chown",
2460         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2461         Summary(NoEvalCall)
2462             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2463             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2464             .ArgConstraint(NotNull(ArgNo(0))));
2465 
2466     // int lchown(const char *path, uid_t owner, gid_t group);
2467     addToFunctionSummaryMap(
2468         "lchown",
2469         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2470         Summary(NoEvalCall)
2471             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2472             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2473             .ArgConstraint(NotNull(ArgNo(0))));
2474 
2475     // int fchown(int fildes, uid_t owner, gid_t group);
2476     addToFunctionSummaryMap(
2477         "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2478         Summary(NoEvalCall)
2479             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2480             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2481             .ArgConstraint(
2482                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2483 
2484     // int rmdir(const char *pathname);
2485     addToFunctionSummaryMap("rmdir",
2486                             Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2487                             Summary(NoEvalCall)
2488                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2489                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2490                                 .ArgConstraint(NotNull(ArgNo(0))));
2491 
2492     // int chdir(const char *path);
2493     addToFunctionSummaryMap("chdir",
2494                             Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2495                             Summary(NoEvalCall)
2496                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2497                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2498                                 .ArgConstraint(NotNull(ArgNo(0))));
2499 
2500     // int link(const char *oldpath, const char *newpath);
2501     addToFunctionSummaryMap(
2502         "link",
2503         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2504         Summary(NoEvalCall)
2505             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2506             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2507             .ArgConstraint(NotNull(ArgNo(0)))
2508             .ArgConstraint(NotNull(ArgNo(1))));
2509 
2510     // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2511     //            int flag);
2512     addToFunctionSummaryMap(
2513         "linkat",
2514         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2515                   RetType{IntTy}),
2516         Summary(NoEvalCall)
2517             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2518             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2519             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2520             .ArgConstraint(NotNull(ArgNo(1)))
2521             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2522             .ArgConstraint(NotNull(ArgNo(3))));
2523 
2524     // int unlink(const char *pathname);
2525     addToFunctionSummaryMap("unlink",
2526                             Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2527                             Summary(NoEvalCall)
2528                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2529                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2530                                 .ArgConstraint(NotNull(ArgNo(0))));
2531 
2532     // int unlinkat(int fd, const char *path, int flag);
2533     addToFunctionSummaryMap(
2534         "unlinkat",
2535         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2536         Summary(NoEvalCall)
2537             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2538             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2539             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2540             .ArgConstraint(NotNull(ArgNo(1))));
2541 
2542     std::optional<QualType> StructStatTy = lookupTy("stat");
2543     std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2544     std::optional<QualType> StructStatPtrRestrictTy =
2545         getRestrictTy(StructStatPtrTy);
2546 
2547     // int fstat(int fd, struct stat *statbuf);
2548     addToFunctionSummaryMap(
2549         "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2550         Summary(NoEvalCall)
2551             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2552             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2553             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2554             .ArgConstraint(NotNull(ArgNo(1))));
2555 
2556     // int stat(const char *restrict path, struct stat *restrict buf);
2557     addToFunctionSummaryMap(
2558         "stat",
2559         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2560                   RetType{IntTy}),
2561         Summary(NoEvalCall)
2562             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2563             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2564             .ArgConstraint(NotNull(ArgNo(0)))
2565             .ArgConstraint(NotNull(ArgNo(1))));
2566 
2567     // int lstat(const char *restrict path, struct stat *restrict buf);
2568     addToFunctionSummaryMap(
2569         "lstat",
2570         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2571                   RetType{IntTy}),
2572         Summary(NoEvalCall)
2573             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2574             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2575             .ArgConstraint(NotNull(ArgNo(0)))
2576             .ArgConstraint(NotNull(ArgNo(1))));
2577 
2578     // int fstatat(int fd, const char *restrict path,
2579     //             struct stat *restrict buf, int flag);
2580     addToFunctionSummaryMap(
2581         "fstatat",
2582         Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2583                            StructStatPtrRestrictTy, IntTy},
2584                   RetType{IntTy}),
2585         Summary(NoEvalCall)
2586             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2587             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2588             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2589             .ArgConstraint(NotNull(ArgNo(1)))
2590             .ArgConstraint(NotNull(ArgNo(2))));
2591 
2592     // DIR *opendir(const char *name);
2593     // FIXME: Improve for errno modeling.
2594     addToFunctionSummaryMap(
2595         "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
2596         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2597 
2598     // DIR *fdopendir(int fd);
2599     // FIXME: Improve for errno modeling.
2600     addToFunctionSummaryMap("fdopendir",
2601                             Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2602                             Summary(NoEvalCall)
2603                                 .ArgConstraint(ArgumentCondition(
2604                                     0, WithinRange, Range(0, IntMax))));
2605 
2606     // int isatty(int fildes);
2607     addToFunctionSummaryMap(
2608         "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2609         Summary(NoEvalCall)
2610             .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
2611                   ErrnoIrrelevant)
2612             .ArgConstraint(
2613                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2614 
2615     // FILE *popen(const char *command, const char *type);
2616     // FIXME: Improve for errno modeling.
2617     addToFunctionSummaryMap(
2618         "popen",
2619         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2620         Summary(NoEvalCall)
2621             .ArgConstraint(NotNull(ArgNo(0)))
2622             .ArgConstraint(NotNull(ArgNo(1))));
2623 
2624     // int pclose(FILE *stream);
2625     // FIXME: Improve for errno modeling.
2626     addToFunctionSummaryMap(
2627         "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2628         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2629 
2630     // int close(int fildes);
2631     addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2632                             Summary(NoEvalCall)
2633                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2634                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2635                                 .ArgConstraint(ArgumentCondition(
2636                                     0, WithinRange, Range(-1, IntMax))));
2637 
2638     // long fpathconf(int fildes, int name);
2639     addToFunctionSummaryMap("fpathconf",
2640                             Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2641                             Summary(NoEvalCall)
2642                                 .ArgConstraint(ArgumentCondition(
2643                                     0, WithinRange, Range(0, IntMax))));
2644 
2645     // long pathconf(const char *path, int name);
2646     addToFunctionSummaryMap(
2647         "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2648         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2649 
2650     // FILE *fdopen(int fd, const char *mode);
2651     // FIXME: Improve for errno modeling.
2652     addToFunctionSummaryMap(
2653         "fdopen",
2654         Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2655         Summary(NoEvalCall)
2656             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2657             .ArgConstraint(NotNull(ArgNo(1))));
2658 
2659     // void rewinddir(DIR *dir);
2660     addToFunctionSummaryMap(
2661         "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2662         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2663 
2664     // void seekdir(DIR *dirp, long loc);
2665     addToFunctionSummaryMap(
2666         "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2667         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2668 
2669     // int rand_r(unsigned int *seedp);
2670     addToFunctionSummaryMap(
2671         "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2672         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2673 
2674     // int fseeko(FILE *stream, off_t offset, int whence);
2675     addToFunctionSummaryMap(
2676         "fseeko",
2677         Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2678         Summary(NoEvalCall)
2679             .Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant)
2680             .ArgConstraint(NotNull(ArgNo(0))));
2681 
2682     // off_t ftello(FILE *stream);
2683     addToFunctionSummaryMap(
2684         "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2685         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2686 
2687     // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2688     // off_t offset);
2689     // FIXME: Improve for errno modeling.
2690     addToFunctionSummaryMap(
2691         "mmap",
2692         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
2693                   RetType{VoidPtrTy}),
2694         Summary(NoEvalCall)
2695             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2696             .ArgConstraint(
2697                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2698 
2699     std::optional<QualType> Off64_tTy = lookupTy("off64_t");
2700     // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2701     // off64_t offset);
2702     // FIXME: Improve for errno modeling.
2703     addToFunctionSummaryMap(
2704         "mmap64",
2705         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
2706                   RetType{VoidPtrTy}),
2707         Summary(NoEvalCall)
2708             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2709             .ArgConstraint(
2710                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2711 
2712     // int pipe(int fildes[2]);
2713     addToFunctionSummaryMap("pipe",
2714                             Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2715                             Summary(NoEvalCall)
2716                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2717                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2718                                 .ArgConstraint(NotNull(ArgNo(0))));
2719 
2720     // off_t lseek(int fildes, off_t offset, int whence);
2721     // In the first case we can not tell for sure if it failed or not.
2722     // A return value different from of the expected offset (that is unknown
2723     // here) may indicate failure. For this reason we do not enforce the errno
2724     // check (can cause false positive).
2725     addToFunctionSummaryMap(
2726         "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2727         Summary(NoEvalCall)
2728             .Case(ReturnsNonnegative, ErrnoIrrelevant)
2729             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2730             .ArgConstraint(
2731                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2732 
2733     // ssize_t readlink(const char *restrict path, char *restrict buf,
2734     //                  size_t bufsize);
2735     addToFunctionSummaryMap(
2736         "readlink",
2737         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2738                   RetType{Ssize_tTy}),
2739         Summary(NoEvalCall)
2740             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2741                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2742                   ErrnoMustNotBeChecked)
2743             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2744             .ArgConstraint(NotNull(ArgNo(0)))
2745             .ArgConstraint(NotNull(ArgNo(1)))
2746             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2747                                       /*BufSize=*/ArgNo(2)))
2748             .ArgConstraint(
2749                 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
2750 
2751     // ssize_t readlinkat(int fd, const char *restrict path,
2752     //                    char *restrict buf, size_t bufsize);
2753     addToFunctionSummaryMap(
2754         "readlinkat",
2755         Signature(
2756             ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2757             RetType{Ssize_tTy}),
2758         Summary(NoEvalCall)
2759             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)),
2760                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2761                   ErrnoMustNotBeChecked)
2762             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2763             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2764             .ArgConstraint(NotNull(ArgNo(1)))
2765             .ArgConstraint(NotNull(ArgNo(2)))
2766             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
2767                                       /*BufSize=*/ArgNo(3)))
2768             .ArgConstraint(
2769                 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
2770 
2771     // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
2772     // *newpath);
2773     addToFunctionSummaryMap(
2774         "renameat",
2775         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
2776                   RetType{IntTy}),
2777         Summary(NoEvalCall)
2778             .Case(ReturnsZero, ErrnoMustNotBeChecked)
2779             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2780             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2781             .ArgConstraint(NotNull(ArgNo(1)))
2782             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2783             .ArgConstraint(NotNull(ArgNo(3))));
2784 
2785     // char *realpath(const char *restrict file_name,
2786     //                char *restrict resolved_name);
2787     // FIXME: Improve for errno modeling.
2788     addToFunctionSummaryMap(
2789         "realpath",
2790         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
2791                   RetType{CharPtrTy}),
2792         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2793 
2794     QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
2795 
2796     // int execv(const char *path, char *const argv[]);
2797     addToFunctionSummaryMap(
2798         "execv",
2799         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2800         Summary(NoEvalCall)
2801             .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
2802                   ErrnoIrrelevant)
2803             .ArgConstraint(NotNull(ArgNo(0))));
2804 
2805     // int execvp(const char *file, char *const argv[]);
2806     addToFunctionSummaryMap(
2807         "execvp",
2808         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2809         Summary(NoEvalCall)
2810             .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
2811                   ErrnoIrrelevant)
2812             .ArgConstraint(NotNull(ArgNo(0))));
2813 
2814     // int getopt(int argc, char * const argv[], const char *optstring);
2815     addToFunctionSummaryMap(
2816         "getopt",
2817         Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
2818                   RetType{IntTy}),
2819         Summary(NoEvalCall)
2820             .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
2821                   ErrnoIrrelevant)
2822             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2823             .ArgConstraint(NotNull(ArgNo(1)))
2824             .ArgConstraint(NotNull(ArgNo(2))));
2825 
2826     std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
2827     std::optional<QualType> StructSockaddrPtrTy =
2828         getPointerTy(StructSockaddrTy);
2829     std::optional<QualType> ConstStructSockaddrPtrTy =
2830         getPointerTy(getConstTy(StructSockaddrTy));
2831     std::optional<QualType> StructSockaddrPtrRestrictTy =
2832         getRestrictTy(StructSockaddrPtrTy);
2833     std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
2834         getRestrictTy(ConstStructSockaddrPtrTy);
2835     std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
2836     std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
2837     std::optional<QualType> Socklen_tPtrRestrictTy =
2838         getRestrictTy(Socklen_tPtrTy);
2839     std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
2840 
2841     // In 'socket.h' of some libc implementations with C99, sockaddr parameter
2842     // is a transparent union of the underlying sockaddr_ family of pointers
2843     // instead of being a pointer to struct sockaddr. In these cases, the
2844     // standardized signature will not match, thus we try to match with another
2845     // signature that has the joker Irrelevant type. We also remove those
2846     // constraints which require pointer types for the sockaddr param.
2847     auto Accept =
2848         Summary(NoEvalCall)
2849             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2850             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2851             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
2852     if (!addToFunctionSummaryMap(
2853             "accept",
2854             // int accept(int socket, struct sockaddr *restrict address,
2855             //            socklen_t *restrict address_len);
2856             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2857                                Socklen_tPtrRestrictTy},
2858                       RetType{IntTy}),
2859             Accept))
2860       addToFunctionSummaryMap(
2861           "accept",
2862           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
2863                     RetType{IntTy}),
2864           Accept);
2865 
2866     // int bind(int socket, const struct sockaddr *address, socklen_t
2867     //          address_len);
2868     if (!addToFunctionSummaryMap(
2869             "bind",
2870             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
2871                       RetType{IntTy}),
2872             Summary(NoEvalCall)
2873                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2874                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2875                 .ArgConstraint(
2876                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2877                 .ArgConstraint(NotNull(ArgNo(1)))
2878                 .ArgConstraint(
2879                     BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
2880                 .ArgConstraint(
2881                     ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
2882       // Do not add constraints on sockaddr.
2883       addToFunctionSummaryMap(
2884           "bind",
2885           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
2886           Summary(NoEvalCall)
2887               .Case(ReturnsZero, ErrnoMustNotBeChecked)
2888               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2889               .ArgConstraint(
2890                   ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2891               .ArgConstraint(
2892                   ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
2893 
2894     // int getpeername(int socket, struct sockaddr *restrict address,
2895     //                 socklen_t *restrict address_len);
2896     if (!addToFunctionSummaryMap(
2897             "getpeername",
2898             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2899                                Socklen_tPtrRestrictTy},
2900                       RetType{IntTy}),
2901             Summary(NoEvalCall)
2902                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2903                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2904                 .ArgConstraint(
2905                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2906                 .ArgConstraint(NotNull(ArgNo(1)))
2907                 .ArgConstraint(NotNull(ArgNo(2)))))
2908       addToFunctionSummaryMap(
2909           "getpeername",
2910           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
2911                     RetType{IntTy}),
2912           Summary(NoEvalCall)
2913               .Case(ReturnsZero, ErrnoMustNotBeChecked)
2914               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2915               .ArgConstraint(
2916                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2917 
2918     // int getsockname(int socket, struct sockaddr *restrict address,
2919     //                 socklen_t *restrict address_len);
2920     if (!addToFunctionSummaryMap(
2921             "getsockname",
2922             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2923                                Socklen_tPtrRestrictTy},
2924                       RetType{IntTy}),
2925             Summary(NoEvalCall)
2926                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2927                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2928                 .ArgConstraint(
2929                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2930                 .ArgConstraint(NotNull(ArgNo(1)))
2931                 .ArgConstraint(NotNull(ArgNo(2)))))
2932       addToFunctionSummaryMap(
2933           "getsockname",
2934           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
2935                     RetType{IntTy}),
2936           Summary(NoEvalCall)
2937               .Case(ReturnsZero, ErrnoMustNotBeChecked)
2938               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2939               .ArgConstraint(
2940                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2941 
2942     // int connect(int socket, const struct sockaddr *address, socklen_t
2943     //             address_len);
2944     if (!addToFunctionSummaryMap(
2945             "connect",
2946             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
2947                       RetType{IntTy}),
2948             Summary(NoEvalCall)
2949                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
2950                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2951                 .ArgConstraint(
2952                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2953                 .ArgConstraint(NotNull(ArgNo(1)))))
2954       addToFunctionSummaryMap(
2955           "connect",
2956           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
2957           Summary(NoEvalCall)
2958               .Case(ReturnsZero, ErrnoMustNotBeChecked)
2959               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2960               .ArgConstraint(
2961                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2962 
2963     auto Recvfrom =
2964         Summary(NoEvalCall)
2965             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2966                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2967                   ErrnoMustNotBeChecked)
2968             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2969             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2970             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2971                                       /*BufSize=*/ArgNo(2)));
2972     if (!addToFunctionSummaryMap(
2973             "recvfrom",
2974             // ssize_t recvfrom(int socket, void *restrict buffer,
2975             //                  size_t length,
2976             //                  int flags, struct sockaddr *restrict address,
2977             //                  socklen_t *restrict address_len);
2978             Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
2979                                StructSockaddrPtrRestrictTy,
2980                                Socklen_tPtrRestrictTy},
2981                       RetType{Ssize_tTy}),
2982             Recvfrom))
2983       addToFunctionSummaryMap(
2984           "recvfrom",
2985           Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
2986                              Irrelevant, Socklen_tPtrRestrictTy},
2987                     RetType{Ssize_tTy}),
2988           Recvfrom);
2989 
2990     auto Sendto =
2991         Summary(NoEvalCall)
2992             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2993                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2994                   ErrnoMustNotBeChecked)
2995             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2996             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2997             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2998                                       /*BufSize=*/ArgNo(2)));
2999     if (!addToFunctionSummaryMap(
3000             "sendto",
3001             // ssize_t sendto(int socket, const void *message, size_t length,
3002             //                int flags, const struct sockaddr *dest_addr,
3003             //                socklen_t dest_len);
3004             Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
3005                                ConstStructSockaddrPtrTy, Socklen_tTy},
3006                       RetType{Ssize_tTy}),
3007             Sendto))
3008       addToFunctionSummaryMap(
3009           "sendto",
3010           Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
3011                              Socklen_tTy},
3012                     RetType{Ssize_tTy}),
3013           Sendto);
3014 
3015     // int listen(int sockfd, int backlog);
3016     addToFunctionSummaryMap("listen",
3017                             Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3018                             Summary(NoEvalCall)
3019                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
3020                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3021                                 .ArgConstraint(ArgumentCondition(
3022                                     0, WithinRange, Range(0, IntMax))));
3023 
3024     // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3025     addToFunctionSummaryMap(
3026         "recv",
3027         Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
3028                   RetType{Ssize_tTy}),
3029         Summary(NoEvalCall)
3030             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3031                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3032                   ErrnoMustNotBeChecked)
3033             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3034             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3035             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3036                                       /*BufSize=*/ArgNo(2))));
3037 
3038     std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3039     std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3040     std::optional<QualType> ConstStructMsghdrPtrTy =
3041         getPointerTy(getConstTy(StructMsghdrTy));
3042 
3043     // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3044     addToFunctionSummaryMap(
3045         "recvmsg",
3046         Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3047                   RetType{Ssize_tTy}),
3048         Summary(NoEvalCall)
3049             .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3050                   ErrnoMustNotBeChecked)
3051             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3052             .ArgConstraint(
3053                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3054 
3055     // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3056     addToFunctionSummaryMap(
3057         "sendmsg",
3058         Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3059                   RetType{Ssize_tTy}),
3060         Summary(NoEvalCall)
3061             .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3062                   ErrnoMustNotBeChecked)
3063             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3064             .ArgConstraint(
3065                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3066 
3067     // int setsockopt(int socket, int level, int option_name,
3068     //                const void *option_value, socklen_t option_len);
3069     addToFunctionSummaryMap(
3070         "setsockopt",
3071         Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3072                   RetType{IntTy}),
3073         Summary(NoEvalCall)
3074             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3075             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3076             .ArgConstraint(NotNull(ArgNo(3)))
3077             .ArgConstraint(
3078                 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3079             .ArgConstraint(
3080                 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3081 
3082     // int getsockopt(int socket, int level, int option_name,
3083     //                void *restrict option_value,
3084     //                socklen_t *restrict option_len);
3085     addToFunctionSummaryMap(
3086         "getsockopt",
3087         Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3088                            Socklen_tPtrRestrictTy},
3089                   RetType{IntTy}),
3090         Summary(NoEvalCall)
3091             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3092             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3093             .ArgConstraint(NotNull(ArgNo(3)))
3094             .ArgConstraint(NotNull(ArgNo(4))));
3095 
3096     // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3097     addToFunctionSummaryMap(
3098         "send",
3099         Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
3100                   RetType{Ssize_tTy}),
3101         Summary(NoEvalCall)
3102             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3103                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3104                   ErrnoMustNotBeChecked)
3105             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3106             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3107             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3108                                       /*BufSize=*/ArgNo(2))));
3109 
3110     // int socketpair(int domain, int type, int protocol, int sv[2]);
3111     addToFunctionSummaryMap(
3112         "socketpair",
3113         Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3114         Summary(NoEvalCall)
3115             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3116             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3117             .ArgConstraint(NotNull(ArgNo(3))));
3118 
3119     // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3120     //                 char *restrict node, socklen_t nodelen,
3121     //                 char *restrict service,
3122     //                 socklen_t servicelen, int flags);
3123     //
3124     // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3125     // parameter is never handled as a transparent union in netdb.h
3126     addToFunctionSummaryMap(
3127         "getnameinfo",
3128         Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3129                            CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3130                            Socklen_tTy, IntTy},
3131                   RetType{IntTy}),
3132         Summary(NoEvalCall)
3133             .ArgConstraint(
3134                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3135             .ArgConstraint(
3136                 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3137             .ArgConstraint(
3138                 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3139             .ArgConstraint(
3140                 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3141             .ArgConstraint(
3142                 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3143             .ArgConstraint(
3144                 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3145 
3146     std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3147     std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3148 
3149     // int utime(const char *filename, struct utimbuf *buf);
3150     addToFunctionSummaryMap(
3151         "utime",
3152         Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3153         Summary(NoEvalCall)
3154             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3155             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3156             .ArgConstraint(NotNull(ArgNo(0))));
3157 
3158     std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3159     std::optional<QualType> StructTimespecPtrTy =
3160         getPointerTy(StructTimespecTy);
3161     std::optional<QualType> ConstStructTimespecPtrTy =
3162         getPointerTy(getConstTy(StructTimespecTy));
3163 
3164     // int futimens(int fd, const struct timespec times[2]);
3165     addToFunctionSummaryMap(
3166         "futimens",
3167         Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3168         Summary(NoEvalCall)
3169             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3170             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3171             .ArgConstraint(
3172                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3173 
3174     // int utimensat(int dirfd, const char *pathname,
3175     //               const struct timespec times[2], int flags);
3176     addToFunctionSummaryMap("utimensat",
3177                             Signature(ArgTypes{IntTy, ConstCharPtrTy,
3178                                                ConstStructTimespecPtrTy, IntTy},
3179                                       RetType{IntTy}),
3180                             Summary(NoEvalCall)
3181                                 .Case(ReturnsZero, ErrnoMustNotBeChecked)
3182                                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3183                                 .ArgConstraint(NotNull(ArgNo(1))));
3184 
3185     std::optional<QualType> StructTimevalTy = lookupTy("timeval");
3186     std::optional<QualType> ConstStructTimevalPtrTy =
3187         getPointerTy(getConstTy(StructTimevalTy));
3188 
3189     // int utimes(const char *filename, const struct timeval times[2]);
3190     addToFunctionSummaryMap(
3191         "utimes",
3192         Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3193                   RetType{IntTy}),
3194         Summary(NoEvalCall)
3195             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3196             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3197             .ArgConstraint(NotNull(ArgNo(0))));
3198 
3199     // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3200     addToFunctionSummaryMap(
3201         "nanosleep",
3202         Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3203                   RetType{IntTy}),
3204         Summary(NoEvalCall)
3205             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3206             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3207             .ArgConstraint(NotNull(ArgNo(0))));
3208 
3209     std::optional<QualType> Time_tTy = lookupTy("time_t");
3210     std::optional<QualType> ConstTime_tPtrTy =
3211         getPointerTy(getConstTy(Time_tTy));
3212     std::optional<QualType> ConstTime_tPtrRestrictTy =
3213         getRestrictTy(ConstTime_tPtrTy);
3214 
3215     std::optional<QualType> StructTmTy = lookupTy("tm");
3216     std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3217     std::optional<QualType> StructTmPtrRestrictTy =
3218         getRestrictTy(StructTmPtrTy);
3219     std::optional<QualType> ConstStructTmPtrTy =
3220         getPointerTy(getConstTy(StructTmTy));
3221     std::optional<QualType> ConstStructTmPtrRestrictTy =
3222         getRestrictTy(ConstStructTmPtrTy);
3223 
3224     // struct tm * localtime(const time_t *tp);
3225     addToFunctionSummaryMap(
3226         "localtime",
3227         Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3228         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3229 
3230     // struct tm *localtime_r(const time_t *restrict timer,
3231     //                        struct tm *restrict result);
3232     addToFunctionSummaryMap(
3233         "localtime_r",
3234         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3235                   RetType{StructTmPtrTy}),
3236         Summary(NoEvalCall)
3237             .ArgConstraint(NotNull(ArgNo(0)))
3238             .ArgConstraint(NotNull(ArgNo(1))));
3239 
3240     // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3241     addToFunctionSummaryMap(
3242         "asctime_r",
3243         Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3244                   RetType{CharPtrTy}),
3245         Summary(NoEvalCall)
3246             .ArgConstraint(NotNull(ArgNo(0)))
3247             .ArgConstraint(NotNull(ArgNo(1)))
3248             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3249                                       /*MinBufSize=*/BVF.getValue(26, IntTy))));
3250 
3251     // char *ctime_r(const time_t *timep, char *buf);
3252     addToFunctionSummaryMap(
3253         "ctime_r",
3254         Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3255         Summary(NoEvalCall)
3256             .ArgConstraint(NotNull(ArgNo(0)))
3257             .ArgConstraint(NotNull(ArgNo(1)))
3258             .ArgConstraint(BufferSize(
3259                 /*Buffer=*/ArgNo(1),
3260                 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3261 
3262     // struct tm *gmtime_r(const time_t *restrict timer,
3263     //                     struct tm *restrict result);
3264     addToFunctionSummaryMap(
3265         "gmtime_r",
3266         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3267                   RetType{StructTmPtrTy}),
3268         Summary(NoEvalCall)
3269             .ArgConstraint(NotNull(ArgNo(0)))
3270             .ArgConstraint(NotNull(ArgNo(1))));
3271 
3272     // struct tm * gmtime(const time_t *tp);
3273     addToFunctionSummaryMap(
3274         "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3275         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3276 
3277     std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3278 
3279     // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3280     addToFunctionSummaryMap(
3281         "clock_gettime",
3282         Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3283         Summary(NoEvalCall)
3284             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3285             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3286             .ArgConstraint(NotNull(ArgNo(1))));
3287 
3288     std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3289     std::optional<QualType> StructItimervalPtrTy =
3290         getPointerTy(StructItimervalTy);
3291 
3292     // int getitimer(int which, struct itimerval *curr_value);
3293     addToFunctionSummaryMap(
3294         "getitimer",
3295         Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3296         Summary(NoEvalCall)
3297             .Case(ReturnsZero, ErrnoMustNotBeChecked)
3298             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3299             .ArgConstraint(NotNull(ArgNo(1))));
3300 
3301     std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3302     std::optional<QualType> Pthread_cond_tPtrTy =
3303         getPointerTy(Pthread_cond_tTy);
3304     std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3305     std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3306     std::optional<QualType> Pthread_tPtrRestrictTy =
3307         getRestrictTy(Pthread_tPtrTy);
3308     std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3309     std::optional<QualType> Pthread_mutex_tPtrTy =
3310         getPointerTy(Pthread_mutex_tTy);
3311     std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3312         getRestrictTy(Pthread_mutex_tPtrTy);
3313     std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3314     std::optional<QualType> Pthread_attr_tPtrTy =
3315         getPointerTy(Pthread_attr_tTy);
3316     std::optional<QualType> ConstPthread_attr_tPtrTy =
3317         getPointerTy(getConstTy(Pthread_attr_tTy));
3318     std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3319         getRestrictTy(ConstPthread_attr_tPtrTy);
3320     std::optional<QualType> Pthread_mutexattr_tTy =
3321         lookupTy("pthread_mutexattr_t");
3322     std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3323         getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3324     std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3325         getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3326 
3327     QualType PthreadStartRoutineTy = getPointerTy(
3328         ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3329                              FunctionProtoType::ExtProtoInfo()));
3330 
3331     // int pthread_cond_signal(pthread_cond_t *cond);
3332     // int pthread_cond_broadcast(pthread_cond_t *cond);
3333     addToFunctionSummaryMap(
3334         {"pthread_cond_signal", "pthread_cond_broadcast"},
3335         Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3336         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3337 
3338     // int pthread_create(pthread_t *restrict thread,
3339     //                    const pthread_attr_t *restrict attr,
3340     //                    void *(*start_routine)(void*), void *restrict arg);
3341     addToFunctionSummaryMap(
3342         "pthread_create",
3343         Signature(ArgTypes{Pthread_tPtrRestrictTy,
3344                            ConstPthread_attr_tPtrRestrictTy,
3345                            PthreadStartRoutineTy, VoidPtrRestrictTy},
3346                   RetType{IntTy}),
3347         Summary(NoEvalCall)
3348             .ArgConstraint(NotNull(ArgNo(0)))
3349             .ArgConstraint(NotNull(ArgNo(2))));
3350 
3351     // int pthread_attr_destroy(pthread_attr_t *attr);
3352     // int pthread_attr_init(pthread_attr_t *attr);
3353     addToFunctionSummaryMap(
3354         {"pthread_attr_destroy", "pthread_attr_init"},
3355         Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3356         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3357 
3358     // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3359     //                               size_t *restrict stacksize);
3360     // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3361     //                               size_t *restrict guardsize);
3362     addToFunctionSummaryMap(
3363         {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3364         Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3365                   RetType{IntTy}),
3366         Summary(NoEvalCall)
3367             .ArgConstraint(NotNull(ArgNo(0)))
3368             .ArgConstraint(NotNull(ArgNo(1))));
3369 
3370     // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3371     // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3372     addToFunctionSummaryMap(
3373         {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3374         Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
3375         Summary(NoEvalCall)
3376             .ArgConstraint(NotNull(ArgNo(0)))
3377             .ArgConstraint(
3378                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3379 
3380     // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3381     //                        pthread_mutexattr_t *restrict attr);
3382     addToFunctionSummaryMap(
3383         "pthread_mutex_init",
3384         Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3385                            ConstPthread_mutexattr_tPtrRestrictTy},
3386                   RetType{IntTy}),
3387         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3388 
3389     // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3390     // int pthread_mutex_lock(pthread_mutex_t *mutex);
3391     // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3392     // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3393     addToFunctionSummaryMap(
3394         {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3395          "pthread_mutex_unlock"},
3396         Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3397         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3398   }
3399 
3400   // Functions for testing.
3401   if (AddTestFunctions) {
3402     const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue();
3403 
3404     addToFunctionSummaryMap(
3405         "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3406         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3407 
3408     // Test inside range constraints.
3409     addToFunctionSummaryMap(
3410         "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3411         Summary(EvalCallAsPure)
3412             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
3413     addToFunctionSummaryMap(
3414         "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3415         Summary(EvalCallAsPure)
3416             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3417     addToFunctionSummaryMap(
3418         "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3419         Summary(EvalCallAsPure)
3420             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
3421     addToFunctionSummaryMap(
3422         "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3423         Summary(EvalCallAsPure)
3424             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
3425     addToFunctionSummaryMap(
3426         "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3427         Summary(EvalCallAsPure)
3428             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
3429     addToFunctionSummaryMap(
3430         "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3431         Summary(EvalCallAsPure)
3432             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
3433     addToFunctionSummaryMap("__range_m1_inf",
3434                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3435                             Summary(EvalCallAsPure)
3436                                 .ArgConstraint(ArgumentCondition(
3437                                     0U, WithinRange, Range(-1, IntMax))));
3438     addToFunctionSummaryMap("__range_0_inf",
3439                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3440                             Summary(EvalCallAsPure)
3441                                 .ArgConstraint(ArgumentCondition(
3442                                     0U, WithinRange, Range(0, IntMax))));
3443     addToFunctionSummaryMap("__range_1_inf",
3444                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3445                             Summary(EvalCallAsPure)
3446                                 .ArgConstraint(ArgumentCondition(
3447                                     0U, WithinRange, Range(1, IntMax))));
3448     addToFunctionSummaryMap("__range_minf_m1",
3449                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3450                             Summary(EvalCallAsPure)
3451                                 .ArgConstraint(ArgumentCondition(
3452                                     0U, WithinRange, Range(IntMin, -1))));
3453     addToFunctionSummaryMap("__range_minf_0",
3454                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3455                             Summary(EvalCallAsPure)
3456                                 .ArgConstraint(ArgumentCondition(
3457                                     0U, WithinRange, Range(IntMin, 0))));
3458     addToFunctionSummaryMap("__range_minf_1",
3459                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3460                             Summary(EvalCallAsPure)
3461                                 .ArgConstraint(ArgumentCondition(
3462                                     0U, WithinRange, Range(IntMin, 1))));
3463     addToFunctionSummaryMap("__range_1_2__4_6",
3464                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3465                             Summary(EvalCallAsPure)
3466                                 .ArgConstraint(ArgumentCondition(
3467                                     0U, WithinRange, Range({1, 2}, {4, 6}))));
3468     addToFunctionSummaryMap(
3469         "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3470         Summary(EvalCallAsPure)
3471             .ArgConstraint(ArgumentCondition(0U, WithinRange,
3472                                              Range({1, 2}, {4, IntMax}))));
3473 
3474     // Test out of range constraints.
3475     addToFunctionSummaryMap(
3476         "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3477         Summary(EvalCallAsPure)
3478             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
3479     addToFunctionSummaryMap(
3480         "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3481         Summary(EvalCallAsPure)
3482             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3483     addToFunctionSummaryMap(
3484         "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3485         Summary(EvalCallAsPure)
3486             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
3487     addToFunctionSummaryMap(
3488         "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3489         Summary(EvalCallAsPure)
3490             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
3491     addToFunctionSummaryMap(
3492         "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3493         Summary(EvalCallAsPure)
3494             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
3495     addToFunctionSummaryMap(
3496         "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3497         Summary(EvalCallAsPure)
3498             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
3499     addToFunctionSummaryMap("__range_out_m1_inf",
3500                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3501                             Summary(EvalCallAsPure)
3502                                 .ArgConstraint(ArgumentCondition(
3503                                     0U, OutOfRange, Range(-1, IntMax))));
3504     addToFunctionSummaryMap("__range_out_0_inf",
3505                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3506                             Summary(EvalCallAsPure)
3507                                 .ArgConstraint(ArgumentCondition(
3508                                     0U, OutOfRange, Range(0, IntMax))));
3509     addToFunctionSummaryMap("__range_out_1_inf",
3510                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3511                             Summary(EvalCallAsPure)
3512                                 .ArgConstraint(ArgumentCondition(
3513                                     0U, OutOfRange, Range(1, IntMax))));
3514     addToFunctionSummaryMap("__range_out_minf_m1",
3515                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3516                             Summary(EvalCallAsPure)
3517                                 .ArgConstraint(ArgumentCondition(
3518                                     0U, OutOfRange, Range(IntMin, -1))));
3519     addToFunctionSummaryMap("__range_out_minf_0",
3520                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3521                             Summary(EvalCallAsPure)
3522                                 .ArgConstraint(ArgumentCondition(
3523                                     0U, OutOfRange, Range(IntMin, 0))));
3524     addToFunctionSummaryMap("__range_out_minf_1",
3525                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3526                             Summary(EvalCallAsPure)
3527                                 .ArgConstraint(ArgumentCondition(
3528                                     0U, OutOfRange, Range(IntMin, 1))));
3529     addToFunctionSummaryMap("__range_out_1_2__4_6",
3530                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3531                             Summary(EvalCallAsPure)
3532                                 .ArgConstraint(ArgumentCondition(
3533                                     0U, OutOfRange, Range({1, 2}, {4, 6}))));
3534     addToFunctionSummaryMap(
3535         "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3536         Summary(EvalCallAsPure)
3537             .ArgConstraint(
3538                 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3539 
3540     // Test range kind.
3541     addToFunctionSummaryMap(
3542         "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3543         Summary(EvalCallAsPure)
3544             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3545     addToFunctionSummaryMap(
3546         "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3547         Summary(EvalCallAsPure)
3548             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3549 
3550     addToFunctionSummaryMap(
3551         "__two_constrained_args",
3552         Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3553         Summary(EvalCallAsPure)
3554             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
3555             .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
3556     addToFunctionSummaryMap(
3557         "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3558         Summary(EvalCallAsPure)
3559             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
3560             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
3561     addToFunctionSummaryMap(
3562         "__defaultparam",
3563         Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3564         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3565     addToFunctionSummaryMap(
3566         "__variadic",
3567         Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3568         Summary(EvalCallAsPure)
3569             .ArgConstraint(NotNull(ArgNo(0)))
3570             .ArgConstraint(NotNull(ArgNo(1))));
3571     addToFunctionSummaryMap(
3572         "__buf_size_arg_constraint",
3573         Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
3574         Summary(EvalCallAsPure)
3575             .ArgConstraint(
3576                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
3577     addToFunctionSummaryMap(
3578         "__buf_size_arg_constraint_mul",
3579         Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
3580         Summary(EvalCallAsPure)
3581             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
3582                                       /*BufSizeMultiplier=*/ArgNo(2))));
3583     addToFunctionSummaryMap(
3584         "__buf_size_arg_constraint_concrete",
3585         Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3586         Summary(EvalCallAsPure)
3587             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3588                                       /*BufSize=*/BVF.getValue(10, IntTy))));
3589     addToFunctionSummaryMap(
3590         {"__test_restrict_param_0", "__test_restrict_param_1",
3591          "__test_restrict_param_2"},
3592         Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3593         Summary(EvalCallAsPure));
3594 
3595     // Test the application of cases.
3596     addToFunctionSummaryMap(
3597         "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3598         Summary(EvalCallAsPure)
3599             .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
3600                   ErrnoIrrelevant, "Function returns 0")
3601             .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
3602                   ErrnoIrrelevant, "Function returns 1"));
3603     addToFunctionSummaryMap(
3604         "__test_case_range_1_2__4_6",
3605         Signature(ArgTypes{IntTy}, RetType{IntTy}),
3606         Summary(EvalCallAsPure)
3607             .Case({ArgumentCondition(0U, WithinRange,
3608                                      IntRangeVector{{IntMin, 0}, {3, 3}}),
3609                    ReturnValueCondition(WithinRange, SingleValue(1))},
3610                   ErrnoIrrelevant)
3611             .Case({ArgumentCondition(0U, WithinRange,
3612                                      IntRangeVector{{3, 3}, {7, IntMax}}),
3613                    ReturnValueCondition(WithinRange, SingleValue(2))},
3614                   ErrnoIrrelevant)
3615             .Case({ArgumentCondition(0U, WithinRange,
3616                                      IntRangeVector{{IntMin, 0}, {7, IntMax}}),
3617                    ReturnValueCondition(WithinRange, SingleValue(3))},
3618                   ErrnoIrrelevant)
3619             .Case({ArgumentCondition(
3620                        0U, WithinRange,
3621                        IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
3622                    ReturnValueCondition(WithinRange, SingleValue(4))},
3623                   ErrnoIrrelevant));
3624   }
3625 }
3626 
3627 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
3628   auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
3629   Checker->CheckName = mgr.getCurrentCheckerName();
3630   const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
3631   Checker->DisplayLoadedSummaries =
3632       Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3633   Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3634   Checker->ShouldAssumeControlledEnvironment =
3635       Opts.ShouldAssumeControlledEnvironment;
3636 }
3637 
3638 bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3639     const CheckerManager &mgr) {
3640   return true;
3641 }
3642 
3643 void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
3644   auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
3645   Checker->AddTestFunctions = true;
3646 }
3647 
3648 bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3649     const CheckerManager &mgr) {
3650   return true;
3651 }
3652