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