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