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