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