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