xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This checker improves modeling of a few simple library functions.
100b57cec5SDimitry Andric //
115ffd83dbSDimitry Andric // This checker provides a specification format - `Summary' - and
120b57cec5SDimitry Andric // contains descriptions of some library functions in this format. Each
130b57cec5SDimitry Andric // specification contains a list of branches for splitting the program state
140b57cec5SDimitry Andric // upon call, and range constraints on argument and return-value symbols that
150b57cec5SDimitry Andric // are satisfied on each branch. This spec can be expanded to include more
160b57cec5SDimitry Andric // items, like external effects of the function.
170b57cec5SDimitry Andric //
180b57cec5SDimitry Andric // The main difference between this approach and the body farms technique is
190b57cec5SDimitry Andric // in more explicit control over how many branches are produced. For example,
200b57cec5SDimitry Andric // consider standard C function `ispunct(int x)', which returns a non-zero value
210b57cec5SDimitry Andric // iff `x' is a punctuation character, that is, when `x' is in range
220b57cec5SDimitry Andric //   ['!', '/']   [':', '@']  U  ['[', '\`']  U  ['{', '~'].
235ffd83dbSDimitry Andric // `Summary' provides only two branches for this function. However,
240b57cec5SDimitry Andric // any attempt to describe this range with if-statements in the body farm
250b57cec5SDimitry Andric // would result in many more branches. Because each branch needs to be analyzed
260b57cec5SDimitry Andric // independently, this significantly reduces performance. Additionally,
270b57cec5SDimitry Andric // once we consider a branch on which `x' is in range, say, ['!', '/'],
280b57cec5SDimitry Andric // we assume that such branch is an important separate path through the program,
290b57cec5SDimitry Andric // which may lead to false positives because considering this particular path
300b57cec5SDimitry Andric // was not consciously intended, and therefore it might have been unreachable.
310b57cec5SDimitry Andric //
325ffd83dbSDimitry Andric // This checker uses eval::Call for modeling pure functions (functions without
335ffd83dbSDimitry Andric // side effets), for which their `Summary' is a precise model. This avoids
345ffd83dbSDimitry Andric // unnecessary invalidation passes. Conflicts with other checkers are unlikely
355ffd83dbSDimitry Andric // because if the function has no other effects, other checkers would probably
365ffd83dbSDimitry Andric // never want to improve upon the modeling done by this checker.
370b57cec5SDimitry Andric //
385ffd83dbSDimitry Andric // Non-pure functions, for which only partial improvement over the default
390b57cec5SDimitry Andric // behavior is expected, are modeled via check::PostCall, non-intrusively.
400b57cec5SDimitry Andric //
410b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
420b57cec5SDimitry Andric 
4381ad6265SDimitry Andric #include "ErrnoModeling.h"
440b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
455ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
460b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
470b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
480b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
490b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
505ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
51fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
52*06c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h"
53fe6060f1SDimitry Andric #include "llvm/ADT/SmallString.h"
54fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h"
55*06c3fb27SDimitry Andric #include "llvm/Support/FormatVariadic.h"
56fe6060f1SDimitry Andric 
57bdd1243dSDimitry Andric #include <optional>
58fe6060f1SDimitry Andric #include <string>
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric using namespace clang;
610b57cec5SDimitry Andric using namespace clang::ento;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric namespace {
645ffd83dbSDimitry Andric class StdLibraryFunctionsChecker
655ffd83dbSDimitry Andric     : public Checker<check::PreCall, check::PostCall, eval::Call> {
665ffd83dbSDimitry Andric 
675ffd83dbSDimitry Andric   class Summary;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   /// Specify how much the analyzer engine should entrust modeling this function
70*06c3fb27SDimitry Andric   /// to us.
71*06c3fb27SDimitry Andric   enum InvalidationKind {
72*06c3fb27SDimitry Andric     /// No \c eval::Call for the function, it can be modeled elsewhere.
73*06c3fb27SDimitry Andric     /// This checker checks only pre and post conditions.
74*06c3fb27SDimitry Andric     NoEvalCall,
75*06c3fb27SDimitry Andric     /// The function is modeled completely in this checker.
76*06c3fb27SDimitry Andric     EvalCallAsPure
77*06c3fb27SDimitry Andric   };
780b57cec5SDimitry Andric 
79*06c3fb27SDimitry Andric   /// Given a range, should the argument stay inside or outside this range?
80*06c3fb27SDimitry Andric   enum RangeKind { OutOfRange, WithinRange };
81*06c3fb27SDimitry Andric 
82*06c3fb27SDimitry Andric   static RangeKind negateKind(RangeKind K) {
83*06c3fb27SDimitry Andric     switch (K) {
84*06c3fb27SDimitry Andric     case OutOfRange:
85*06c3fb27SDimitry Andric       return WithinRange;
86*06c3fb27SDimitry Andric     case WithinRange:
87*06c3fb27SDimitry Andric       return OutOfRange;
88*06c3fb27SDimitry Andric     }
89*06c3fb27SDimitry Andric     llvm_unreachable("Unknown range kind");
90*06c3fb27SDimitry Andric   }
91*06c3fb27SDimitry Andric 
92*06c3fb27SDimitry Andric   /// The universal integral type to use in value range descriptions.
93*06c3fb27SDimitry Andric   /// Unsigned to make sure overflows are well-defined.
945ffd83dbSDimitry Andric   typedef uint64_t RangeInt;
950b57cec5SDimitry Andric 
96*06c3fb27SDimitry Andric   /// Describes a single range constraint. Eg. {{0, 1}, {3, 4}} is
97*06c3fb27SDimitry Andric   /// a non-negative integer, which less than 5 and not equal to 2.
985ffd83dbSDimitry Andric   typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   /// A reference to an argument or return value by its number.
1010b57cec5SDimitry Andric   /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
1020b57cec5SDimitry Andric   /// obviously uint32_t should be enough for all practical purposes.
1035ffd83dbSDimitry Andric   typedef uint32_t ArgNo;
104*06c3fb27SDimitry Andric   /// Special argument number for specifying the return value.
1055ffd83dbSDimitry Andric   static const ArgNo Ret;
1060b57cec5SDimitry Andric 
107*06c3fb27SDimitry Andric   /// Get a string representation of an argument index.
108fe6060f1SDimitry Andric   /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
109*06c3fb27SDimitry Andric   static void printArgDesc(ArgNo, llvm::raw_ostream &Out);
110*06c3fb27SDimitry Andric   /// Print value X of the argument in form " (which is X)",
111*06c3fb27SDimitry Andric   /// if the value is a fixed known value, otherwise print nothing.
112*06c3fb27SDimitry Andric   /// This is used as simple explanation of values if possible.
113*06c3fb27SDimitry Andric   static void printArgValueInfo(ArgNo ArgN, ProgramStateRef State,
114*06c3fb27SDimitry Andric                                 const CallEvent &Call, llvm::raw_ostream &Out);
115*06c3fb27SDimitry Andric   /// Append textual description of a numeric range [RMin,RMax] to
116*06c3fb27SDimitry Andric   /// \p Out.
117*06c3fb27SDimitry Andric   static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
118*06c3fb27SDimitry Andric                                     QualType ArgT, BasicValueFactory &BVF,
119*06c3fb27SDimitry Andric                                     llvm::raw_ostream &Out);
120*06c3fb27SDimitry Andric   /// Append textual description of a numeric range out of [RMin,RMax] to
121*06c3fb27SDimitry Andric   /// \p Out.
122*06c3fb27SDimitry Andric   static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
123*06c3fb27SDimitry Andric                                    QualType ArgT, BasicValueFactory &BVF,
124*06c3fb27SDimitry Andric                                    llvm::raw_ostream &Out);
125fe6060f1SDimitry Andric 
1265ffd83dbSDimitry Andric   class ValueConstraint;
1275ffd83dbSDimitry Andric 
128*06c3fb27SDimitry Andric   /// Pointer to the ValueConstraint. We need a copyable, polymorphic and
129*06c3fb27SDimitry Andric   /// default initializable type (vector needs that). A raw pointer was good,
130*06c3fb27SDimitry Andric   /// however, we cannot default initialize that. unique_ptr makes the Summary
131*06c3fb27SDimitry Andric   /// class non-copyable, therefore not an option. Releasing the copyability
132*06c3fb27SDimitry Andric   /// requirement would render the initialization of the Summary map infeasible.
133*06c3fb27SDimitry Andric   /// Mind that a pointer to a new value constraint is created when the negate
134*06c3fb27SDimitry Andric   /// function is used.
1355ffd83dbSDimitry Andric   using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
1365ffd83dbSDimitry Andric 
1375ffd83dbSDimitry Andric   /// Polymorphic base class that represents a constraint on a given argument
1385ffd83dbSDimitry Andric   /// (or return value) of a function. Derived classes implement different kind
1395ffd83dbSDimitry Andric   /// of constraints, e.g range constraints or correlation between two
1405ffd83dbSDimitry Andric   /// arguments.
141*06c3fb27SDimitry Andric   /// These are used as argument constraints (preconditions) of functions, in
142*06c3fb27SDimitry Andric   /// which case a bug report may be emitted if the constraint is not satisfied.
143*06c3fb27SDimitry Andric   /// Another use is as conditions for summary cases, to create different
144*06c3fb27SDimitry Andric   /// classes of behavior for a function. In this case no description of the
145*06c3fb27SDimitry Andric   /// constraint is needed because the summary cases have an own (not generated)
146*06c3fb27SDimitry Andric   /// description string.
1475ffd83dbSDimitry Andric   class ValueConstraint {
1485ffd83dbSDimitry Andric   public:
1495ffd83dbSDimitry Andric     ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
1505ffd83dbSDimitry Andric     virtual ~ValueConstraint() {}
151*06c3fb27SDimitry Andric 
1525ffd83dbSDimitry Andric     /// Apply the effects of the constraint on the given program state. If null
1535ffd83dbSDimitry Andric     /// is returned then the constraint is not feasible.
1545ffd83dbSDimitry Andric     virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
1555ffd83dbSDimitry Andric                                   const Summary &Summary,
1565ffd83dbSDimitry Andric                                   CheckerContext &C) const = 0;
157*06c3fb27SDimitry Andric 
158*06c3fb27SDimitry Andric     /// Represents that in which context do we require a description of the
159*06c3fb27SDimitry Andric     /// constraint.
160*06c3fb27SDimitry Andric     enum DescriptionKind {
161*06c3fb27SDimitry Andric       /// Describe a constraint that was violated.
162*06c3fb27SDimitry Andric       /// Description should start with something like "should be".
163*06c3fb27SDimitry Andric       Violation,
164*06c3fb27SDimitry Andric       /// Describe a constraint that was assumed to be true.
165*06c3fb27SDimitry Andric       /// This can be used when a precondition is satisfied, or when a summary
166*06c3fb27SDimitry Andric       /// case is applied.
167*06c3fb27SDimitry Andric       /// Description should start with something like "is".
168*06c3fb27SDimitry Andric       Assumption
169*06c3fb27SDimitry Andric     };
170*06c3fb27SDimitry Andric 
171*06c3fb27SDimitry Andric     /// Give a description that explains the constraint to the user. Used when
172*06c3fb27SDimitry Andric     /// a bug is reported or when the constraint is applied and displayed as a
173*06c3fb27SDimitry Andric     /// note. The description should not mention the argument (getArgNo).
174*06c3fb27SDimitry Andric     /// See StdLibraryFunctionsChecker::reportBug about how this function is
175*06c3fb27SDimitry Andric     /// used (this function is used not only there).
176*06c3fb27SDimitry Andric     virtual void describe(DescriptionKind DK, const CallEvent &Call,
177*06c3fb27SDimitry Andric                           ProgramStateRef State, const Summary &Summary,
178*06c3fb27SDimitry Andric                           llvm::raw_ostream &Out) const {
179*06c3fb27SDimitry Andric       // There are some descendant classes that are not used as argument
180*06c3fb27SDimitry Andric       // constraints, e.g. ComparisonConstraint. In that case we can safely
181*06c3fb27SDimitry Andric       // ignore the implementation of this function.
182*06c3fb27SDimitry Andric       llvm_unreachable(
183*06c3fb27SDimitry Andric           "Description not implemented for summary case constraints");
184*06c3fb27SDimitry Andric     }
185*06c3fb27SDimitry Andric 
186*06c3fb27SDimitry Andric     /// Give a description that explains the actual argument value (where the
187*06c3fb27SDimitry Andric     /// current ValueConstraint applies to) to the user. This function should be
188*06c3fb27SDimitry Andric     /// called only when the current constraint is satisfied by the argument.
189*06c3fb27SDimitry Andric     /// It should produce a more precise description than the constraint itself.
190*06c3fb27SDimitry Andric     /// The actual value of the argument and the program state can be used to
191*06c3fb27SDimitry Andric     /// make the description more precise. In the most simple case, if the
192*06c3fb27SDimitry Andric     /// argument has a fixed known value this value can be printed into \p Out,
193*06c3fb27SDimitry Andric     /// this is done by default.
194*06c3fb27SDimitry Andric     /// The function should return true if a description was printed to \p Out,
195*06c3fb27SDimitry Andric     /// otherwise false.
196*06c3fb27SDimitry Andric     /// See StdLibraryFunctionsChecker::reportBug about how this function is
197*06c3fb27SDimitry Andric     /// used.
198*06c3fb27SDimitry Andric     virtual bool describeArgumentValue(const CallEvent &Call,
199*06c3fb27SDimitry Andric                                        ProgramStateRef State,
200*06c3fb27SDimitry Andric                                        const Summary &Summary,
201*06c3fb27SDimitry Andric                                        llvm::raw_ostream &Out) const {
202*06c3fb27SDimitry Andric       if (auto N = getArgSVal(Call, getArgNo()).getAs<NonLoc>()) {
203*06c3fb27SDimitry Andric         if (const llvm::APSInt *Int = N->getAsInteger()) {
204*06c3fb27SDimitry Andric           Out << *Int;
205*06c3fb27SDimitry Andric           return true;
206*06c3fb27SDimitry Andric         }
207*06c3fb27SDimitry Andric       }
208*06c3fb27SDimitry Andric       return false;
209*06c3fb27SDimitry Andric     }
210*06c3fb27SDimitry Andric 
211*06c3fb27SDimitry Andric     /// Return those arguments that should be tracked when we report a bug about
212*06c3fb27SDimitry Andric     /// argument constraint violation. By default it is the argument that is
213*06c3fb27SDimitry Andric     /// constrained, however, in some special cases we need to track other
214*06c3fb27SDimitry Andric     /// arguments as well. E.g. a buffer size might be encoded in another
215*06c3fb27SDimitry Andric     /// argument.
216*06c3fb27SDimitry Andric     /// The "return value" argument number can not occur as returned value.
217*06c3fb27SDimitry Andric     virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
218*06c3fb27SDimitry Andric 
219*06c3fb27SDimitry Andric     /// Get a constraint that represents exactly the opposite of the current.
2205ffd83dbSDimitry Andric     virtual ValueConstraintPtr negate() const {
2215ffd83dbSDimitry Andric       llvm_unreachable("Not implemented");
2225ffd83dbSDimitry Andric     };
2235ffd83dbSDimitry Andric 
224*06c3fb27SDimitry Andric     /// Check whether the constraint is malformed or not. It is malformed if the
225*06c3fb27SDimitry Andric     /// specified argument has a mismatch with the given FunctionDecl (e.g. the
226*06c3fb27SDimitry Andric     /// arg number is out-of-range of the function's argument list).
227*06c3fb27SDimitry Andric     /// This condition can indicate if a probably wrong or unexpected function
228*06c3fb27SDimitry Andric     /// was found where the constraint is to be applied.
2295ffd83dbSDimitry Andric     bool checkValidity(const FunctionDecl *FD) const {
2305ffd83dbSDimitry Andric       const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
2315ffd83dbSDimitry Andric       assert(ValidArg && "Arg out of range!");
2325ffd83dbSDimitry Andric       if (!ValidArg)
2335ffd83dbSDimitry Andric         return false;
2345ffd83dbSDimitry Andric       // Subclasses may further refine the validation.
2355ffd83dbSDimitry Andric       return checkSpecificValidity(FD);
2365ffd83dbSDimitry Andric     }
237*06c3fb27SDimitry Andric 
238*06c3fb27SDimitry Andric     /// Return the argument number (may be placeholder for "return value").
2395ffd83dbSDimitry Andric     ArgNo getArgNo() const { return ArgN; }
2405ffd83dbSDimitry Andric 
2415ffd83dbSDimitry Andric   protected:
242*06c3fb27SDimitry Andric     /// Argument to which to apply the constraint. It can be a real argument of
243*06c3fb27SDimitry Andric     /// the function to check, or a special value to indicate the return value
244*06c3fb27SDimitry Andric     /// of the function.
245*06c3fb27SDimitry Andric     /// Every constraint is assigned to one main argument, even if other
246*06c3fb27SDimitry Andric     /// arguments are involved.
247*06c3fb27SDimitry Andric     ArgNo ArgN;
2485ffd83dbSDimitry Andric 
249*06c3fb27SDimitry Andric     /// Do constraint-specific validation check.
2505ffd83dbSDimitry Andric     virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
2515ffd83dbSDimitry Andric       return true;
2525ffd83dbSDimitry Andric     }
2535ffd83dbSDimitry Andric   };
2545ffd83dbSDimitry Andric 
255*06c3fb27SDimitry Andric   /// Check if a single argument falls into a specific "range".
256*06c3fb27SDimitry Andric   /// A range is formed as a set of intervals.
257*06c3fb27SDimitry Andric   /// E.g. \code {['A', 'Z'], ['a', 'z'], ['_', '_']} \endcode
258*06c3fb27SDimitry Andric   /// The intervals are closed intervals that contain one or more values.
259*06c3fb27SDimitry Andric   ///
260*06c3fb27SDimitry Andric   /// The default constructed RangeConstraint has an empty range, applying
261*06c3fb27SDimitry Andric   /// such constraint does not involve any assumptions, thus the State remains
262*06c3fb27SDimitry Andric   /// unchanged. This is meaningful, if the range is dependent on a looked up
263*06c3fb27SDimitry Andric   /// type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
264*06c3fb27SDimitry Andric   /// is default initialized to be empty.
2655ffd83dbSDimitry Andric   class RangeConstraint : public ValueConstraint {
266*06c3fb27SDimitry Andric     /// The constraint can be specified by allowing or disallowing the range.
267*06c3fb27SDimitry Andric     /// WithinRange indicates allowing the range, OutOfRange indicates
268*06c3fb27SDimitry Andric     /// disallowing it (allowing the complementary range).
269e8d8bef9SDimitry Andric     RangeKind Kind;
270*06c3fb27SDimitry Andric 
271*06c3fb27SDimitry Andric     /// A set of intervals.
272e8d8bef9SDimitry Andric     IntRangeVector Ranges;
2730b57cec5SDimitry Andric 
274*06c3fb27SDimitry Andric     /// A textual description of this constraint for the specific case where the
275*06c3fb27SDimitry Andric     /// constraint is used. If empty a generated description will be used that
276*06c3fb27SDimitry Andric     /// is built from the range of the constraint.
277*06c3fb27SDimitry Andric     StringRef Description;
2780b57cec5SDimitry Andric 
279*06c3fb27SDimitry Andric   public:
280*06c3fb27SDimitry Andric     RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges,
281*06c3fb27SDimitry Andric                     StringRef Desc = "")
282*06c3fb27SDimitry Andric         : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges), Description(Desc) {
283*06c3fb27SDimitry Andric     }
284fe6060f1SDimitry Andric 
285e8d8bef9SDimitry Andric     const IntRangeVector &getRanges() const { return Ranges; }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
2885ffd83dbSDimitry Andric                           const Summary &Summary,
289*06c3fb27SDimitry Andric                           CheckerContext &C) const override;
290*06c3fb27SDimitry Andric 
291*06c3fb27SDimitry Andric     void describe(DescriptionKind DK, const CallEvent &Call,
292*06c3fb27SDimitry Andric                   ProgramStateRef State, const Summary &Summary,
293*06c3fb27SDimitry Andric                   llvm::raw_ostream &Out) const override;
294*06c3fb27SDimitry Andric 
295*06c3fb27SDimitry Andric     bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
296*06c3fb27SDimitry Andric                                const Summary &Summary,
297*06c3fb27SDimitry Andric                                llvm::raw_ostream &Out) const override;
2985ffd83dbSDimitry Andric 
2995ffd83dbSDimitry Andric     ValueConstraintPtr negate() const override {
3005ffd83dbSDimitry Andric       RangeConstraint Tmp(*this);
301*06c3fb27SDimitry Andric       Tmp.Kind = negateKind(Kind);
3025ffd83dbSDimitry Andric       return std::make_shared<RangeConstraint>(Tmp);
3035ffd83dbSDimitry Andric     }
3045ffd83dbSDimitry Andric 
305*06c3fb27SDimitry Andric   protected:
3065ffd83dbSDimitry Andric     bool checkSpecificValidity(const FunctionDecl *FD) const override {
3075ffd83dbSDimitry Andric       const bool ValidArg =
3085ffd83dbSDimitry Andric           getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
3095ffd83dbSDimitry Andric       assert(ValidArg &&
3105ffd83dbSDimitry Andric              "This constraint should be applied on an integral type");
3115ffd83dbSDimitry Andric       return ValidArg;
3120b57cec5SDimitry Andric     }
313*06c3fb27SDimitry Andric 
314*06c3fb27SDimitry Andric   private:
315*06c3fb27SDimitry Andric     /// A callback function that is used when iterating over the range
316*06c3fb27SDimitry Andric     /// intervals. It gets the begin and end (inclusive) of one interval.
317*06c3fb27SDimitry Andric     /// This is used to make any kind of task possible that needs an iteration
318*06c3fb27SDimitry Andric     /// over the intervals.
319*06c3fb27SDimitry Andric     using RangeApplyFunction =
320*06c3fb27SDimitry Andric         std::function<bool(const llvm::APSInt &Min, const llvm::APSInt &Max)>;
321*06c3fb27SDimitry Andric 
322*06c3fb27SDimitry Andric     /// Call a function on the intervals of the range.
323*06c3fb27SDimitry Andric     /// The function is called with all intervals in the range.
324*06c3fb27SDimitry Andric     void applyOnWithinRange(BasicValueFactory &BVF, QualType ArgT,
325*06c3fb27SDimitry Andric                             const RangeApplyFunction &F) const;
326*06c3fb27SDimitry Andric     /// Call a function on all intervals in the complementary range.
327*06c3fb27SDimitry Andric     /// The function is called with all intervals that fall out of the range.
328*06c3fb27SDimitry Andric     /// E.g. consider an interval list [A, B] and [C, D]
329*06c3fb27SDimitry Andric     /// \code
330*06c3fb27SDimitry Andric     /// -------+--------+------------------+------------+----------->
331*06c3fb27SDimitry Andric     ///        A        B                  C            D
332*06c3fb27SDimitry Andric     /// \endcode
333*06c3fb27SDimitry Andric     /// We get the ranges [-inf, A - 1], [D + 1, +inf], [B + 1, C - 1].
334*06c3fb27SDimitry Andric     /// The \p ArgT is used to determine the min and max of the type that is
335*06c3fb27SDimitry Andric     /// used as "-inf" and "+inf".
336*06c3fb27SDimitry Andric     void applyOnOutOfRange(BasicValueFactory &BVF, QualType ArgT,
337*06c3fb27SDimitry Andric                            const RangeApplyFunction &F) const;
338*06c3fb27SDimitry Andric     /// Call a function on the intervals of the range or the complementary
339*06c3fb27SDimitry Andric     /// range.
340*06c3fb27SDimitry Andric     void applyOnRange(RangeKind Kind, BasicValueFactory &BVF, QualType ArgT,
341*06c3fb27SDimitry Andric                       const RangeApplyFunction &F) const {
342*06c3fb27SDimitry Andric       switch (Kind) {
343*06c3fb27SDimitry Andric       case OutOfRange:
344*06c3fb27SDimitry Andric         applyOnOutOfRange(BVF, ArgT, F);
345*06c3fb27SDimitry Andric         break;
346*06c3fb27SDimitry Andric       case WithinRange:
347*06c3fb27SDimitry Andric         applyOnWithinRange(BVF, ArgT, F);
348*06c3fb27SDimitry Andric         break;
349*06c3fb27SDimitry Andric       };
350*06c3fb27SDimitry Andric     }
3510b57cec5SDimitry Andric   };
3520b57cec5SDimitry Andric 
353*06c3fb27SDimitry Andric   /// Check relation of an argument to another.
3545ffd83dbSDimitry Andric   class ComparisonConstraint : public ValueConstraint {
3555ffd83dbSDimitry Andric     BinaryOperator::Opcode Opcode;
3565ffd83dbSDimitry Andric     ArgNo OtherArgN;
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric   public:
3595ffd83dbSDimitry Andric     ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
3605ffd83dbSDimitry Andric                          ArgNo OtherArgN)
3615ffd83dbSDimitry Andric         : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
3625ffd83dbSDimitry Andric     ArgNo getOtherArgNo() const { return OtherArgN; }
3635ffd83dbSDimitry Andric     BinaryOperator::Opcode getOpcode() const { return Opcode; }
3645ffd83dbSDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
3655ffd83dbSDimitry Andric                           const Summary &Summary,
3665ffd83dbSDimitry Andric                           CheckerContext &C) const override;
3675ffd83dbSDimitry Andric   };
3685ffd83dbSDimitry Andric 
369*06c3fb27SDimitry Andric   /// Check null or non-null-ness of an argument that is of pointer type.
3705ffd83dbSDimitry Andric   class NotNullConstraint : public ValueConstraint {
3715ffd83dbSDimitry Andric     using ValueConstraint::ValueConstraint;
3725ffd83dbSDimitry Andric     // This variable has a role when we negate the constraint.
3735ffd83dbSDimitry Andric     bool CannotBeNull = true;
3745ffd83dbSDimitry Andric 
3755ffd83dbSDimitry Andric   public:
376bdd1243dSDimitry Andric     NotNullConstraint(ArgNo ArgN, bool CannotBeNull = true)
377bdd1243dSDimitry Andric         : ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}
378*06c3fb27SDimitry Andric 
3795ffd83dbSDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
3805ffd83dbSDimitry Andric                           const Summary &Summary,
381*06c3fb27SDimitry Andric                           CheckerContext &C) const override;
3825ffd83dbSDimitry Andric 
383*06c3fb27SDimitry Andric     void describe(DescriptionKind DK, const CallEvent &Call,
384*06c3fb27SDimitry Andric                   ProgramStateRef State, const Summary &Summary,
385*06c3fb27SDimitry Andric                   llvm::raw_ostream &Out) const override;
3865ffd83dbSDimitry Andric 
387*06c3fb27SDimitry Andric     bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
388*06c3fb27SDimitry Andric                                const Summary &Summary,
389*06c3fb27SDimitry Andric                                llvm::raw_ostream &Out) const override;
3905ffd83dbSDimitry Andric 
3915ffd83dbSDimitry Andric     ValueConstraintPtr negate() const override {
3925ffd83dbSDimitry Andric       NotNullConstraint Tmp(*this);
3935ffd83dbSDimitry Andric       Tmp.CannotBeNull = !this->CannotBeNull;
3945ffd83dbSDimitry Andric       return std::make_shared<NotNullConstraint>(Tmp);
3955ffd83dbSDimitry Andric     }
3965ffd83dbSDimitry Andric 
397*06c3fb27SDimitry Andric   protected:
398*06c3fb27SDimitry Andric     bool checkSpecificValidity(const FunctionDecl *FD) const override {
399*06c3fb27SDimitry Andric       const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
400*06c3fb27SDimitry Andric       assert(ValidArg &&
401*06c3fb27SDimitry Andric              "This constraint should be applied only on a pointer type");
402*06c3fb27SDimitry Andric       return ValidArg;
403*06c3fb27SDimitry Andric     }
404*06c3fb27SDimitry Andric   };
405*06c3fb27SDimitry Andric 
406*06c3fb27SDimitry Andric   /// Check null or non-null-ness of an argument that is of pointer type.
407*06c3fb27SDimitry Andric   /// The argument is meant to be a buffer that has a size constraint, and it
408*06c3fb27SDimitry Andric   /// is allowed to have a NULL value if the size is 0. The size can depend on
409*06c3fb27SDimitry Andric   /// 1 or 2 additional arguments, if one of these is 0 the buffer is allowed to
410*06c3fb27SDimitry Andric   /// be NULL. This is useful for functions like `fread` which have this special
411*06c3fb27SDimitry Andric   /// property.
412*06c3fb27SDimitry Andric   class NotNullBufferConstraint : public ValueConstraint {
413*06c3fb27SDimitry Andric     using ValueConstraint::ValueConstraint;
414*06c3fb27SDimitry Andric     ArgNo SizeArg1N;
415*06c3fb27SDimitry Andric     std::optional<ArgNo> SizeArg2N;
416*06c3fb27SDimitry Andric     // This variable has a role when we negate the constraint.
417*06c3fb27SDimitry Andric     bool CannotBeNull = true;
418*06c3fb27SDimitry Andric 
419*06c3fb27SDimitry Andric   public:
420*06c3fb27SDimitry Andric     NotNullBufferConstraint(ArgNo ArgN, ArgNo SizeArg1N,
421*06c3fb27SDimitry Andric                             std::optional<ArgNo> SizeArg2N,
422*06c3fb27SDimitry Andric                             bool CannotBeNull = true)
423*06c3fb27SDimitry Andric         : ValueConstraint(ArgN), SizeArg1N(SizeArg1N), SizeArg2N(SizeArg2N),
424*06c3fb27SDimitry Andric           CannotBeNull(CannotBeNull) {}
425*06c3fb27SDimitry Andric 
426*06c3fb27SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
427*06c3fb27SDimitry Andric                           const Summary &Summary,
428*06c3fb27SDimitry Andric                           CheckerContext &C) const override;
429*06c3fb27SDimitry Andric 
430*06c3fb27SDimitry Andric     void describe(DescriptionKind DK, const CallEvent &Call,
431*06c3fb27SDimitry Andric                   ProgramStateRef State, const Summary &Summary,
432*06c3fb27SDimitry Andric                   llvm::raw_ostream &Out) const override;
433*06c3fb27SDimitry Andric 
434*06c3fb27SDimitry Andric     bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
435*06c3fb27SDimitry Andric                                const Summary &Summary,
436*06c3fb27SDimitry Andric                                llvm::raw_ostream &Out) const override;
437*06c3fb27SDimitry Andric 
438*06c3fb27SDimitry Andric     ValueConstraintPtr negate() const override {
439*06c3fb27SDimitry Andric       NotNullBufferConstraint Tmp(*this);
440*06c3fb27SDimitry Andric       Tmp.CannotBeNull = !this->CannotBeNull;
441*06c3fb27SDimitry Andric       return std::make_shared<NotNullBufferConstraint>(Tmp);
442*06c3fb27SDimitry Andric     }
443*06c3fb27SDimitry Andric 
444*06c3fb27SDimitry Andric   protected:
4455ffd83dbSDimitry Andric     bool checkSpecificValidity(const FunctionDecl *FD) const override {
4465ffd83dbSDimitry Andric       const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
4475ffd83dbSDimitry Andric       assert(ValidArg &&
4485ffd83dbSDimitry Andric              "This constraint should be applied only on a pointer type");
4495ffd83dbSDimitry Andric       return ValidArg;
4505ffd83dbSDimitry Andric     }
4515ffd83dbSDimitry Andric   };
4525ffd83dbSDimitry Andric 
453e8d8bef9SDimitry Andric   // Represents a buffer argument with an additional size constraint. The
454e8d8bef9SDimitry Andric   // constraint may be a concrete value, or a symbolic value in an argument.
455e8d8bef9SDimitry Andric   // Example 1. Concrete value as the minimum buffer size.
456e8d8bef9SDimitry Andric   //   char *asctime_r(const struct tm *restrict tm, char *restrict buf);
457e8d8bef9SDimitry Andric   //   // `buf` size must be at least 26 bytes according the POSIX standard.
458e8d8bef9SDimitry Andric   // Example 2. Argument as a buffer size.
4595ffd83dbSDimitry Andric   //   ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
460e8d8bef9SDimitry Andric   // Example 3. The size is computed as a multiplication of other args.
4615ffd83dbSDimitry Andric   //   size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
4625ffd83dbSDimitry Andric   //   // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
4635ffd83dbSDimitry Andric   class BufferSizeConstraint : public ValueConstraint {
464e8d8bef9SDimitry Andric     // The concrete value which is the minimum size for the buffer.
465bdd1243dSDimitry Andric     std::optional<llvm::APSInt> ConcreteSize;
4665ffd83dbSDimitry Andric     // The argument which holds the size of the buffer.
467bdd1243dSDimitry Andric     std::optional<ArgNo> SizeArgN;
4685ffd83dbSDimitry Andric     // The argument which is a multiplier to size. This is set in case of
4695ffd83dbSDimitry Andric     // `fread` like functions where the size is computed as a multiplication of
4705ffd83dbSDimitry Andric     // two arguments.
471bdd1243dSDimitry Andric     std::optional<ArgNo> SizeMultiplierArgN;
4725ffd83dbSDimitry Andric     // The operator we use in apply. This is negated in negate().
4735ffd83dbSDimitry Andric     BinaryOperator::Opcode Op = BO_LE;
4745ffd83dbSDimitry Andric 
4755ffd83dbSDimitry Andric   public:
476e8d8bef9SDimitry Andric     BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
477e8d8bef9SDimitry Andric         : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
4785ffd83dbSDimitry Andric     BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
4795ffd83dbSDimitry Andric         : ValueConstraint(Buffer), SizeArgN(BufSize) {}
4805ffd83dbSDimitry Andric     BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
4815ffd83dbSDimitry Andric         : ValueConstraint(Buffer), SizeArgN(BufSize),
4825ffd83dbSDimitry Andric           SizeMultiplierArgN(BufSizeMultiplier) {}
4835ffd83dbSDimitry Andric 
484*06c3fb27SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
485*06c3fb27SDimitry Andric                           const Summary &Summary,
486*06c3fb27SDimitry Andric                           CheckerContext &C) const override;
487*06c3fb27SDimitry Andric 
488*06c3fb27SDimitry Andric     void describe(DescriptionKind DK, const CallEvent &Call,
489*06c3fb27SDimitry Andric                   ProgramStateRef State, const Summary &Summary,
490*06c3fb27SDimitry Andric                   llvm::raw_ostream &Out) const override;
491*06c3fb27SDimitry Andric 
492*06c3fb27SDimitry Andric     bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
493*06c3fb27SDimitry Andric                                const Summary &Summary,
494*06c3fb27SDimitry Andric                                llvm::raw_ostream &Out) const override;
495*06c3fb27SDimitry Andric 
496fe6060f1SDimitry Andric     std::vector<ArgNo> getArgsToTrack() const override {
497fe6060f1SDimitry Andric       std::vector<ArgNo> Result{ArgN};
498fe6060f1SDimitry Andric       if (SizeArgN)
499fe6060f1SDimitry Andric         Result.push_back(*SizeArgN);
500fe6060f1SDimitry Andric       if (SizeMultiplierArgN)
501fe6060f1SDimitry Andric         Result.push_back(*SizeMultiplierArgN);
502fe6060f1SDimitry Andric       return Result;
503fe6060f1SDimitry Andric     }
504fe6060f1SDimitry Andric 
5055ffd83dbSDimitry Andric     ValueConstraintPtr negate() const override {
5065ffd83dbSDimitry Andric       BufferSizeConstraint Tmp(*this);
5075ffd83dbSDimitry Andric       Tmp.Op = BinaryOperator::negateComparisonOp(Op);
5085ffd83dbSDimitry Andric       return std::make_shared<BufferSizeConstraint>(Tmp);
5095ffd83dbSDimitry Andric     }
510e8d8bef9SDimitry Andric 
511*06c3fb27SDimitry Andric   protected:
512e8d8bef9SDimitry Andric     bool checkSpecificValidity(const FunctionDecl *FD) const override {
513e8d8bef9SDimitry Andric       const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
514e8d8bef9SDimitry Andric       assert(ValidArg &&
515e8d8bef9SDimitry Andric              "This constraint should be applied only on a pointer type");
516e8d8bef9SDimitry Andric       return ValidArg;
517e8d8bef9SDimitry Andric     }
5185ffd83dbSDimitry Andric   };
5195ffd83dbSDimitry Andric 
5205ffd83dbSDimitry Andric   /// The complete list of constraints that defines a single branch.
52181ad6265SDimitry Andric   using ConstraintSet = std::vector<ValueConstraintPtr>;
52281ad6265SDimitry Andric 
52381ad6265SDimitry Andric   /// Define how a function affects the system variable 'errno'.
524bdd1243dSDimitry Andric   /// This works together with the \c ErrnoModeling and \c ErrnoChecker classes.
525bdd1243dSDimitry Andric   /// Currently 3 use cases exist: success, failure, irrelevant.
526bdd1243dSDimitry Andric   /// In the future the failure case can be customized to set \c errno to a
527bdd1243dSDimitry Andric   /// more specific constraint (for example > 0), or new case can be added
528bdd1243dSDimitry Andric   /// for functions which require check of \c errno in both success and failure
529bdd1243dSDimitry Andric   /// case.
53081ad6265SDimitry Andric   class ErrnoConstraintBase {
53181ad6265SDimitry Andric   public:
53281ad6265SDimitry Andric     /// Apply specific state changes related to the errno variable.
53381ad6265SDimitry Andric     virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
53481ad6265SDimitry Andric                                   const Summary &Summary,
53581ad6265SDimitry Andric                                   CheckerContext &C) const = 0;
536bdd1243dSDimitry Andric     /// Get a NoteTag about the changes made to 'errno' and the possible bug.
537bdd1243dSDimitry Andric     /// It may return \c nullptr (if no bug report from \c ErrnoChecker is
538bdd1243dSDimitry Andric     /// expected).
539bdd1243dSDimitry Andric     virtual const NoteTag *describe(CheckerContext &C,
540bdd1243dSDimitry Andric                                     StringRef FunctionName) const {
541bdd1243dSDimitry Andric       return nullptr;
542bdd1243dSDimitry Andric     }
54381ad6265SDimitry Andric 
54481ad6265SDimitry Andric     virtual ~ErrnoConstraintBase() {}
54581ad6265SDimitry Andric 
54681ad6265SDimitry Andric   protected:
547bdd1243dSDimitry Andric     ErrnoConstraintBase() = default;
54881ad6265SDimitry Andric 
54981ad6265SDimitry Andric     /// This is used for conjure symbol for errno to differentiate from the
55081ad6265SDimitry Andric     /// original call expression (same expression is used for the errno symbol).
55181ad6265SDimitry Andric     static int Tag;
55281ad6265SDimitry Andric   };
55381ad6265SDimitry Andric 
554bdd1243dSDimitry Andric   /// Reset errno constraints to irrelevant.
555bdd1243dSDimitry Andric   /// This is applicable to functions that may change 'errno' and are not
556bdd1243dSDimitry Andric   /// modeled elsewhere.
557bdd1243dSDimitry Andric   class ResetErrnoConstraint : public ErrnoConstraintBase {
55881ad6265SDimitry Andric   public:
559bdd1243dSDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
560bdd1243dSDimitry Andric                           const Summary &Summary,
561bdd1243dSDimitry Andric                           CheckerContext &C) const override {
562bdd1243dSDimitry Andric       return errno_modeling::setErrnoState(State, errno_modeling::Irrelevant);
56381ad6265SDimitry Andric     }
564bdd1243dSDimitry Andric   };
56581ad6265SDimitry Andric 
566bdd1243dSDimitry Andric   /// Do not change errno constraints.
567bdd1243dSDimitry Andric   /// This is applicable to functions that are modeled in another checker
568bdd1243dSDimitry Andric   /// and the already set errno constraints should not be changed in the
569bdd1243dSDimitry Andric   /// post-call event.
570bdd1243dSDimitry Andric   class NoErrnoConstraint : public ErrnoConstraintBase {
571bdd1243dSDimitry Andric   public:
572bdd1243dSDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
573bdd1243dSDimitry Andric                           const Summary &Summary,
574bdd1243dSDimitry Andric                           CheckerContext &C) const override {
575bdd1243dSDimitry Andric       return State;
576bdd1243dSDimitry Andric     }
577bdd1243dSDimitry Andric   };
578bdd1243dSDimitry Andric 
579bdd1243dSDimitry Andric   /// Set errno constraint at failure cases of standard functions.
580bdd1243dSDimitry Andric   /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
581bdd1243dSDimitry Andric   /// by the program. \c ErrnoChecker does not emit a bug report after such a
582bdd1243dSDimitry Andric   /// function call.
583bdd1243dSDimitry Andric   class FailureErrnoConstraint : public ErrnoConstraintBase {
584bdd1243dSDimitry Andric   public:
58581ad6265SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
58681ad6265SDimitry Andric                           const Summary &Summary,
58781ad6265SDimitry Andric                           CheckerContext &C) const override {
58881ad6265SDimitry Andric       SValBuilder &SVB = C.getSValBuilder();
58981ad6265SDimitry Andric       NonLoc ErrnoSVal =
59081ad6265SDimitry Andric           SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
59181ad6265SDimitry Andric                                C.getLocationContext(), C.getASTContext().IntTy,
59281ad6265SDimitry Andric                                C.blockCount())
59381ad6265SDimitry Andric               .castAs<NonLoc>();
594bdd1243dSDimitry Andric       return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
59581ad6265SDimitry Andric     }
59681ad6265SDimitry Andric   };
59781ad6265SDimitry Andric 
598bdd1243dSDimitry Andric   /// Set errno constraint at success cases of standard functions.
599bdd1243dSDimitry Andric   /// Success case: 'errno' is not allowed to be used.
600bdd1243dSDimitry Andric   /// \c ErrnoChecker can emit bug report after such a function call if errno
601bdd1243dSDimitry Andric   /// is used.
60281ad6265SDimitry Andric   class SuccessErrnoConstraint : public ErrnoConstraintBase {
60381ad6265SDimitry Andric   public:
60481ad6265SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
60581ad6265SDimitry Andric                           const Summary &Summary,
60681ad6265SDimitry Andric                           CheckerContext &C) const override {
607bdd1243dSDimitry Andric       return errno_modeling::setErrnoForStdSuccess(State, C);
60881ad6265SDimitry Andric     }
60981ad6265SDimitry Andric 
610bdd1243dSDimitry Andric     const NoteTag *describe(CheckerContext &C,
611bdd1243dSDimitry Andric                             StringRef FunctionName) const override {
612bdd1243dSDimitry Andric       return errno_modeling::getNoteTagForStdSuccess(C, FunctionName);
61381ad6265SDimitry Andric     }
61481ad6265SDimitry Andric   };
61581ad6265SDimitry Andric 
616bdd1243dSDimitry Andric   class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
61781ad6265SDimitry Andric   public:
61881ad6265SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
61981ad6265SDimitry Andric                           const Summary &Summary,
62081ad6265SDimitry Andric                           CheckerContext &C) const override {
621bdd1243dSDimitry Andric       return errno_modeling::setErrnoStdMustBeChecked(State, C,
622bdd1243dSDimitry Andric                                                       Call.getOriginExpr());
623bdd1243dSDimitry Andric     }
624bdd1243dSDimitry Andric 
625bdd1243dSDimitry Andric     const NoteTag *describe(CheckerContext &C,
626bdd1243dSDimitry Andric                             StringRef FunctionName) const override {
627bdd1243dSDimitry Andric       return errno_modeling::getNoteTagForStdMustBeChecked(C, FunctionName);
62881ad6265SDimitry Andric     }
62981ad6265SDimitry Andric   };
63081ad6265SDimitry Andric 
63181ad6265SDimitry Andric   /// A single branch of a function summary.
63281ad6265SDimitry Andric   ///
63381ad6265SDimitry Andric   /// A branch is defined by a series of constraints - "assumptions" -
63481ad6265SDimitry Andric   /// that together form a single possible outcome of invoking the function.
63581ad6265SDimitry Andric   /// When static analyzer considers a branch, it tries to introduce
63681ad6265SDimitry Andric   /// a child node in the Exploded Graph. The child node has to include
63781ad6265SDimitry Andric   /// constraints that define the branch. If the constraints contradict
63881ad6265SDimitry Andric   /// existing constraints in the state, the node is not created and the branch
63981ad6265SDimitry Andric   /// is dropped; otherwise it's queued for future exploration.
64081ad6265SDimitry Andric   /// The branch is accompanied by a note text that may be displayed
64181ad6265SDimitry Andric   /// to the user when a bug is found on a path that takes this branch.
64281ad6265SDimitry Andric   ///
64381ad6265SDimitry Andric   /// For example, consider the branches in `isalpha(x)`:
64481ad6265SDimitry Andric   ///   Branch 1)
64581ad6265SDimitry Andric   ///     x is in range ['A', 'Z'] or in ['a', 'z']
64681ad6265SDimitry Andric   ///     then the return value is not 0. (I.e. out-of-range [0, 0])
64781ad6265SDimitry Andric   ///     and the note may say "Assuming the character is alphabetical"
64881ad6265SDimitry Andric   ///   Branch 2)
64981ad6265SDimitry Andric   ///     x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
65081ad6265SDimitry Andric   ///     then the return value is 0
65181ad6265SDimitry Andric   ///     and the note may say "Assuming the character is non-alphabetical".
65281ad6265SDimitry Andric   class SummaryCase {
65381ad6265SDimitry Andric     ConstraintSet Constraints;
65481ad6265SDimitry Andric     const ErrnoConstraintBase &ErrnoConstraint;
65581ad6265SDimitry Andric     StringRef Note;
65681ad6265SDimitry Andric 
65781ad6265SDimitry Andric   public:
65881ad6265SDimitry Andric     SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,
65981ad6265SDimitry Andric                 StringRef Note)
66081ad6265SDimitry Andric         : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),
66181ad6265SDimitry Andric           Note(Note) {}
66281ad6265SDimitry Andric 
66381ad6265SDimitry Andric     SummaryCase(const ConstraintSet &Constraints,
66481ad6265SDimitry Andric                 const ErrnoConstraintBase &ErrnoC, StringRef Note)
66581ad6265SDimitry Andric         : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}
66681ad6265SDimitry Andric 
66781ad6265SDimitry Andric     const ConstraintSet &getConstraints() const { return Constraints; }
66881ad6265SDimitry Andric     const ErrnoConstraintBase &getErrnoConstraint() const {
66981ad6265SDimitry Andric       return ErrnoConstraint;
67081ad6265SDimitry Andric     }
67181ad6265SDimitry Andric     StringRef getNote() const { return Note; }
67281ad6265SDimitry Andric   };
6735ffd83dbSDimitry Andric 
674bdd1243dSDimitry Andric   using ArgTypes = std::vector<std::optional<QualType>>;
675bdd1243dSDimitry Andric   using RetType = std::optional<QualType>;
6765ffd83dbSDimitry Andric 
6775ffd83dbSDimitry Andric   // A placeholder type, we use it whenever we do not care about the concrete
6785ffd83dbSDimitry Andric   // type in a Signature.
6795ffd83dbSDimitry Andric   const QualType Irrelevant{};
6805ffd83dbSDimitry Andric   bool static isIrrelevant(QualType T) { return T.isNull(); }
6815ffd83dbSDimitry Andric 
6825ffd83dbSDimitry Andric   // The signature of a function we want to describe with a summary. This is a
6835ffd83dbSDimitry Andric   // concessive signature, meaning there may be irrelevant types in the
6845ffd83dbSDimitry Andric   // signature which we do not check against a function with concrete types.
685e8d8bef9SDimitry Andric   // All types in the spec need to be canonical.
686e8d8bef9SDimitry Andric   class Signature {
687e8d8bef9SDimitry Andric     using ArgQualTypes = std::vector<QualType>;
688e8d8bef9SDimitry Andric     ArgQualTypes ArgTys;
689e8d8bef9SDimitry Andric     QualType RetTy;
690e8d8bef9SDimitry Andric     // True if any component type is not found by lookup.
691e8d8bef9SDimitry Andric     bool Invalid = false;
692e8d8bef9SDimitry Andric 
693e8d8bef9SDimitry Andric   public:
694e8d8bef9SDimitry Andric     // Construct a signature from optional types. If any of the optional types
695e8d8bef9SDimitry Andric     // are not set then the signature will be invalid.
696e8d8bef9SDimitry Andric     Signature(ArgTypes ArgTys, RetType RetTy) {
697bdd1243dSDimitry Andric       for (std::optional<QualType> Arg : ArgTys) {
698e8d8bef9SDimitry Andric         if (!Arg) {
699e8d8bef9SDimitry Andric           Invalid = true;
700e8d8bef9SDimitry Andric           return;
701e8d8bef9SDimitry Andric         } else {
702e8d8bef9SDimitry Andric           assertArgTypeSuitableForSignature(*Arg);
703e8d8bef9SDimitry Andric           this->ArgTys.push_back(*Arg);
7045ffd83dbSDimitry Andric         }
7055ffd83dbSDimitry Andric       }
706e8d8bef9SDimitry Andric       if (!RetTy) {
707e8d8bef9SDimitry Andric         Invalid = true;
708e8d8bef9SDimitry Andric         return;
709e8d8bef9SDimitry Andric       } else {
710e8d8bef9SDimitry Andric         assertRetTypeSuitableForSignature(*RetTy);
711e8d8bef9SDimitry Andric         this->RetTy = *RetTy;
712e8d8bef9SDimitry Andric       }
713e8d8bef9SDimitry Andric     }
714e8d8bef9SDimitry Andric 
715e8d8bef9SDimitry Andric     bool isInvalid() const { return Invalid; }
7165ffd83dbSDimitry Andric     bool matches(const FunctionDecl *FD) const;
7175ffd83dbSDimitry Andric 
7185ffd83dbSDimitry Andric   private:
7195ffd83dbSDimitry Andric     static void assertArgTypeSuitableForSignature(QualType T) {
7205ffd83dbSDimitry Andric       assert((T.isNull() || !T->isVoidType()) &&
7215ffd83dbSDimitry Andric              "We should have no void types in the spec");
7225ffd83dbSDimitry Andric       assert((T.isNull() || T.isCanonical()) &&
7235ffd83dbSDimitry Andric              "We should only have canonical types in the spec");
7245ffd83dbSDimitry Andric     }
7255ffd83dbSDimitry Andric     static void assertRetTypeSuitableForSignature(QualType T) {
7265ffd83dbSDimitry Andric       assert((T.isNull() || T.isCanonical()) &&
7275ffd83dbSDimitry Andric              "We should only have canonical types in the spec");
7285ffd83dbSDimitry Andric     }
7295ffd83dbSDimitry Andric   };
7305ffd83dbSDimitry Andric 
7315ffd83dbSDimitry Andric   static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
7325ffd83dbSDimitry Andric     assert(FD && "Function must be set");
7335ffd83dbSDimitry Andric     QualType T = (ArgN == Ret)
7345ffd83dbSDimitry Andric                      ? FD->getReturnType().getCanonicalType()
7355ffd83dbSDimitry Andric                      : FD->getParamDecl(ArgN)->getType().getCanonicalType();
7360b57cec5SDimitry Andric     return T;
7370b57cec5SDimitry Andric   }
7380b57cec5SDimitry Andric 
73981ad6265SDimitry Andric   using SummaryCases = std::vector<SummaryCase>;
7400b57cec5SDimitry Andric 
7415ffd83dbSDimitry Andric   /// A summary includes information about
7425ffd83dbSDimitry Andric   ///   * function prototype (signature)
7435ffd83dbSDimitry Andric   ///   * approach to invalidation,
74481ad6265SDimitry Andric   ///   * a list of branches - so, a list of list of ranges,
7455ffd83dbSDimitry Andric   ///   * a list of argument constraints, that must be true on every branch.
7465ffd83dbSDimitry Andric   ///     If these constraints are not satisfied that means a fatal error
7475ffd83dbSDimitry Andric   ///     usually resulting in undefined behaviour.
7485ffd83dbSDimitry Andric   ///
7495ffd83dbSDimitry Andric   /// Application of a summary:
7505ffd83dbSDimitry Andric   ///   The signature and argument constraints together contain information
7515ffd83dbSDimitry Andric   ///   about which functions are handled by the summary. The signature can use
7525ffd83dbSDimitry Andric   ///   "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
7535ffd83dbSDimitry Andric   ///   a signature means that type is not compared to the type of the parameter
7545ffd83dbSDimitry Andric   ///   in the found FunctionDecl. Argument constraints may specify additional
7555ffd83dbSDimitry Andric   ///   rules for the given parameter's type, those rules are checked once the
7565ffd83dbSDimitry Andric   ///   signature is matched.
7575ffd83dbSDimitry Andric   class Summary {
7585ffd83dbSDimitry Andric     const InvalidationKind InvalidationKd;
75981ad6265SDimitry Andric     SummaryCases Cases;
7605ffd83dbSDimitry Andric     ConstraintSet ArgConstraints;
7615ffd83dbSDimitry Andric 
7625ffd83dbSDimitry Andric     // The function to which the summary applies. This is set after lookup and
7635ffd83dbSDimitry Andric     // match to the signature.
7645ffd83dbSDimitry Andric     const FunctionDecl *FD = nullptr;
7655ffd83dbSDimitry Andric 
7665ffd83dbSDimitry Andric   public:
767e8d8bef9SDimitry Andric     Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
7685ffd83dbSDimitry Andric 
76981ad6265SDimitry Andric     Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,
77081ad6265SDimitry Andric                   StringRef Note = "") {
77181ad6265SDimitry Andric       Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));
7725ffd83dbSDimitry Andric       return *this;
7735ffd83dbSDimitry Andric     }
77481ad6265SDimitry Andric     Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,
77581ad6265SDimitry Andric                   StringRef Note = "") {
77681ad6265SDimitry Andric       Cases.push_back(SummaryCase(CS, ErrnoC, Note));
777e8d8bef9SDimitry Andric       return *this;
778e8d8bef9SDimitry Andric     }
7795ffd83dbSDimitry Andric     Summary &ArgConstraint(ValueConstraintPtr VC) {
780e8d8bef9SDimitry Andric       assert(VC->getArgNo() != Ret &&
781e8d8bef9SDimitry Andric              "Arg constraint should not refer to the return value");
7825ffd83dbSDimitry Andric       ArgConstraints.push_back(VC);
7835ffd83dbSDimitry Andric       return *this;
7845ffd83dbSDimitry Andric     }
7855ffd83dbSDimitry Andric 
7865ffd83dbSDimitry Andric     InvalidationKind getInvalidationKd() const { return InvalidationKd; }
78781ad6265SDimitry Andric     const SummaryCases &getCases() const { return Cases; }
7885ffd83dbSDimitry Andric     const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
7895ffd83dbSDimitry Andric 
7905ffd83dbSDimitry Andric     QualType getArgType(ArgNo ArgN) const {
7915ffd83dbSDimitry Andric       return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
7925ffd83dbSDimitry Andric     }
7935ffd83dbSDimitry Andric 
7945ffd83dbSDimitry Andric     // Returns true if the summary should be applied to the given function.
7955ffd83dbSDimitry Andric     // And if yes then store the function declaration.
796e8d8bef9SDimitry Andric     bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
7975ffd83dbSDimitry Andric       bool Result = Sign.matches(FD) && validateByConstraints(FD);
7985ffd83dbSDimitry Andric       if (Result) {
7995ffd83dbSDimitry Andric         assert(!this->FD && "FD must not be set more than once");
8005ffd83dbSDimitry Andric         this->FD = FD;
8015ffd83dbSDimitry Andric       }
8025ffd83dbSDimitry Andric       return Result;
8035ffd83dbSDimitry Andric     }
8045ffd83dbSDimitry Andric 
8055ffd83dbSDimitry Andric   private:
8065e801ac6SDimitry Andric     // Once we know the exact type of the function then do validation check on
8075e801ac6SDimitry Andric     // all the given constraints.
8085ffd83dbSDimitry Andric     bool validateByConstraints(const FunctionDecl *FD) const {
80981ad6265SDimitry Andric       for (const SummaryCase &Case : Cases)
81081ad6265SDimitry Andric         for (const ValueConstraintPtr &Constraint : Case.getConstraints())
8115ffd83dbSDimitry Andric           if (!Constraint->checkValidity(FD))
8125ffd83dbSDimitry Andric             return false;
8135ffd83dbSDimitry Andric       for (const ValueConstraintPtr &Constraint : ArgConstraints)
8145ffd83dbSDimitry Andric         if (!Constraint->checkValidity(FD))
8155ffd83dbSDimitry Andric           return false;
8165ffd83dbSDimitry Andric       return true;
8175ffd83dbSDimitry Andric     }
8185ffd83dbSDimitry Andric   };
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric   // The map of all functions supported by the checker. It is initialized
8210b57cec5SDimitry Andric   // lazily, and it doesn't change after initialization.
8225ffd83dbSDimitry Andric   using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
8235ffd83dbSDimitry Andric   mutable FunctionSummaryMapType FunctionSummaryMap;
8240b57cec5SDimitry Andric 
8255ffd83dbSDimitry Andric   mutable std::unique_ptr<BugType> BT_InvalidArg;
826fe6060f1SDimitry Andric   mutable bool SummariesInitialized = false;
8275ffd83dbSDimitry Andric 
8285ffd83dbSDimitry Andric   static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
8295ffd83dbSDimitry Andric     return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
8300b57cec5SDimitry Andric   }
831*06c3fb27SDimitry Andric   static std::string getFunctionName(const CallEvent &Call) {
832*06c3fb27SDimitry Andric     assert(Call.getDecl() &&
833*06c3fb27SDimitry Andric            "Call was found by a summary, should have declaration");
834*06c3fb27SDimitry Andric     return cast<NamedDecl>(Call.getDecl())->getNameAsString();
835*06c3fb27SDimitry Andric   }
8360b57cec5SDimitry Andric 
8370b57cec5SDimitry Andric public:
8385ffd83dbSDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
8390b57cec5SDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
8400b57cec5SDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
8410b57cec5SDimitry Andric 
842*06c3fb27SDimitry Andric   CheckerNameRef CheckName;
843*06c3fb27SDimitry Andric   bool AddTestFunctions = false;
8445ffd83dbSDimitry Andric 
8455ffd83dbSDimitry Andric   bool DisplayLoadedSummaries = false;
8465ffd83dbSDimitry Andric   bool ModelPOSIX = false;
847349cc55cSDimitry Andric   bool ShouldAssumeControlledEnvironment = false;
8485ffd83dbSDimitry Andric 
8490b57cec5SDimitry Andric private:
850bdd1243dSDimitry Andric   std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,
8515ffd83dbSDimitry Andric                                              CheckerContext &C) const;
852bdd1243dSDimitry Andric   std::optional<Summary> findFunctionSummary(const CallEvent &Call,
8530b57cec5SDimitry Andric                                              CheckerContext &C) const;
8540b57cec5SDimitry Andric 
8555ffd83dbSDimitry Andric   void initFunctionSummaries(CheckerContext &C) const;
8565ffd83dbSDimitry Andric 
8575ffd83dbSDimitry Andric   void reportBug(const CallEvent &Call, ExplodedNode *N,
858*06c3fb27SDimitry Andric                  const ValueConstraint *VC, const ValueConstraint *NegatedVC,
859*06c3fb27SDimitry Andric                  const Summary &Summary, CheckerContext &C) const {
860*06c3fb27SDimitry Andric     assert(Call.getDecl() &&
861*06c3fb27SDimitry Andric            "Function found in summary must have a declaration available");
862*06c3fb27SDimitry Andric     SmallString<256> Msg;
863*06c3fb27SDimitry Andric     llvm::raw_svector_ostream MsgOs(Msg);
864*06c3fb27SDimitry Andric 
865*06c3fb27SDimitry Andric     MsgOs << "The ";
866*06c3fb27SDimitry Andric     printArgDesc(VC->getArgNo(), MsgOs);
867*06c3fb27SDimitry Andric     MsgOs << " to '" << getFunctionName(Call) << "' ";
868*06c3fb27SDimitry Andric     bool ValuesPrinted =
869*06c3fb27SDimitry Andric         NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);
870*06c3fb27SDimitry Andric     if (ValuesPrinted)
871*06c3fb27SDimitry Andric       MsgOs << " but ";
872*06c3fb27SDimitry Andric     else
873*06c3fb27SDimitry Andric       MsgOs << "is out of the accepted range; It ";
874*06c3fb27SDimitry Andric     VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,
875*06c3fb27SDimitry Andric                  MsgOs);
876*06c3fb27SDimitry Andric     Msg[0] = toupper(Msg[0]);
8775ffd83dbSDimitry Andric     if (!BT_InvalidArg)
8785ffd83dbSDimitry Andric       BT_InvalidArg = std::make_unique<BugType>(
879*06c3fb27SDimitry Andric           CheckName, "Function call with invalid argument",
880*06c3fb27SDimitry Andric           categories::LogicError);
8815ffd83dbSDimitry Andric     auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
882fe6060f1SDimitry Andric 
883*06c3fb27SDimitry Andric     for (ArgNo ArgN : VC->getArgsToTrack()) {
884fe6060f1SDimitry Andric       bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
885*06c3fb27SDimitry Andric       R->markInteresting(Call.getArgSVal(ArgN));
886*06c3fb27SDimitry Andric       // All tracked arguments are important, highlight them.
887*06c3fb27SDimitry Andric       R->addRange(Call.getArgSourceRange(ArgN));
888*06c3fb27SDimitry Andric     }
889fe6060f1SDimitry Andric 
8905ffd83dbSDimitry Andric     C.emitReport(std::move(R));
8915ffd83dbSDimitry Andric   }
89281ad6265SDimitry Andric 
89381ad6265SDimitry Andric   /// These are the errno constraints that can be passed to summary cases.
89481ad6265SDimitry Andric   /// One of these should fit for a single summary case.
89581ad6265SDimitry Andric   /// Usually if a failure return value exists for function, that function
89681ad6265SDimitry Andric   /// needs different cases for success and failure with different errno
89781ad6265SDimitry Andric   /// constraints (and different return value constraints).
898bdd1243dSDimitry Andric   const NoErrnoConstraint ErrnoUnchanged{};
899bdd1243dSDimitry Andric   const ResetErrnoConstraint ErrnoIrrelevant{};
900bdd1243dSDimitry Andric   const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
901bdd1243dSDimitry Andric   const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
902bdd1243dSDimitry Andric   const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
9030b57cec5SDimitry Andric };
9045ffd83dbSDimitry Andric 
90581ad6265SDimitry Andric int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
90681ad6265SDimitry Andric 
9075ffd83dbSDimitry Andric const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
9085ffd83dbSDimitry Andric     std::numeric_limits<ArgNo>::max();
9095ffd83dbSDimitry Andric 
910fe6060f1SDimitry Andric static BasicValueFactory &getBVF(ProgramStateRef State) {
911fe6060f1SDimitry Andric   ProgramStateManager &Mgr = State->getStateManager();
912fe6060f1SDimitry Andric   SValBuilder &SVB = Mgr.getSValBuilder();
913fe6060f1SDimitry Andric   return SVB.getBasicValueFactory();
914fe6060f1SDimitry Andric }
915fe6060f1SDimitry Andric 
916*06c3fb27SDimitry Andric } // end of anonymous namespace
917*06c3fb27SDimitry Andric 
918*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::printArgDesc(
919*06c3fb27SDimitry Andric     StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
920*06c3fb27SDimitry Andric   Out << std::to_string(ArgN + 1);
921*06c3fb27SDimitry Andric   Out << llvm::getOrdinalSuffix(ArgN + 1);
922*06c3fb27SDimitry Andric   Out << " argument";
923fe6060f1SDimitry Andric }
924fe6060f1SDimitry Andric 
925*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
926*06c3fb27SDimitry Andric                                                    ProgramStateRef State,
927*06c3fb27SDimitry Andric                                                    const CallEvent &Call,
928*06c3fb27SDimitry Andric                                                    llvm::raw_ostream &Out) {
929*06c3fb27SDimitry Andric   if (const llvm::APSInt *Val =
930*06c3fb27SDimitry Andric           State->getStateManager().getSValBuilder().getKnownValue(
931*06c3fb27SDimitry Andric               State, getArgSVal(Call, ArgN)))
932*06c3fb27SDimitry Andric     Out << " (which is " << *Val << ")";
933*06c3fb27SDimitry Andric }
934*06c3fb27SDimitry Andric 
935*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
936*06c3fb27SDimitry Andric                                                        llvm::APSInt RMax,
937*06c3fb27SDimitry Andric                                                        QualType ArgT,
938*06c3fb27SDimitry Andric                                                        BasicValueFactory &BVF,
939*06c3fb27SDimitry Andric                                                        llvm::raw_ostream &Out) {
940*06c3fb27SDimitry Andric   if (RMin.isZero() && RMax.isZero())
941*06c3fb27SDimitry Andric     Out << "zero";
942*06c3fb27SDimitry Andric   else if (RMin == RMax)
943*06c3fb27SDimitry Andric     Out << RMin;
944*06c3fb27SDimitry Andric   else if (RMin == BVF.getMinValue(ArgT)) {
945*06c3fb27SDimitry Andric     if (RMax == -1)
946*06c3fb27SDimitry Andric       Out << "< 0";
947*06c3fb27SDimitry Andric     else
948*06c3fb27SDimitry Andric       Out << "<= " << RMax;
949*06c3fb27SDimitry Andric   } else if (RMax == BVF.getMaxValue(ArgT)) {
950*06c3fb27SDimitry Andric     if (RMin.isOne())
951*06c3fb27SDimitry Andric       Out << "> 0";
952*06c3fb27SDimitry Andric     else
953*06c3fb27SDimitry Andric       Out << ">= " << RMin;
954*06c3fb27SDimitry Andric   } else if (RMin.isNegative() == RMax.isNegative() &&
955*06c3fb27SDimitry Andric              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
956*06c3fb27SDimitry Andric     Out << RMin << " or " << RMax;
957*06c3fb27SDimitry Andric   } else {
958*06c3fb27SDimitry Andric     Out << "between " << RMin << " and " << RMax;
959*06c3fb27SDimitry Andric   }
960*06c3fb27SDimitry Andric }
961*06c3fb27SDimitry Andric 
962*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
963*06c3fb27SDimitry Andric                                                       llvm::APSInt RMax,
964*06c3fb27SDimitry Andric                                                       QualType ArgT,
965*06c3fb27SDimitry Andric                                                       BasicValueFactory &BVF,
966*06c3fb27SDimitry Andric                                                       llvm::raw_ostream &Out) {
967*06c3fb27SDimitry Andric   if (RMin.isZero() && RMax.isZero())
968*06c3fb27SDimitry Andric     Out << "nonzero";
969*06c3fb27SDimitry Andric   else if (RMin == RMax) {
970*06c3fb27SDimitry Andric     Out << "not equal to " << RMin;
971*06c3fb27SDimitry Andric   } else if (RMin == BVF.getMinValue(ArgT)) {
972*06c3fb27SDimitry Andric     if (RMax == -1)
973*06c3fb27SDimitry Andric       Out << ">= 0";
974*06c3fb27SDimitry Andric     else
975*06c3fb27SDimitry Andric       Out << "> " << RMax;
976*06c3fb27SDimitry Andric   } else if (RMax == BVF.getMaxValue(ArgT)) {
977*06c3fb27SDimitry Andric     if (RMin.isOne())
978*06c3fb27SDimitry Andric       Out << "<= 0";
979*06c3fb27SDimitry Andric     else
980*06c3fb27SDimitry Andric       Out << "< " << RMin;
981*06c3fb27SDimitry Andric   } else if (RMin.isNegative() == RMax.isNegative() &&
982*06c3fb27SDimitry Andric              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
983*06c3fb27SDimitry Andric     Out << "not " << RMin << " and not " << RMax;
984*06c3fb27SDimitry Andric   } else {
985*06c3fb27SDimitry Andric     Out << "not between " << RMin << " and " << RMax;
986*06c3fb27SDimitry Andric   }
987*06c3fb27SDimitry Andric }
988*06c3fb27SDimitry Andric 
989*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
990*06c3fb27SDimitry Andric     BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
991*06c3fb27SDimitry Andric   if (Ranges.empty())
992*06c3fb27SDimitry Andric     return;
993*06c3fb27SDimitry Andric 
994*06c3fb27SDimitry Andric   for (auto [Start, End] : getRanges()) {
995*06c3fb27SDimitry Andric     const llvm::APSInt &Min = BVF.getValue(Start, ArgT);
996*06c3fb27SDimitry Andric     const llvm::APSInt &Max = BVF.getValue(End, ArgT);
997*06c3fb27SDimitry Andric     assert(Min <= Max);
998*06c3fb27SDimitry Andric     if (!F(Min, Max))
999*06c3fb27SDimitry Andric       return;
1000*06c3fb27SDimitry Andric   }
1001*06c3fb27SDimitry Andric }
1002*06c3fb27SDimitry Andric 
1003*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
1004*06c3fb27SDimitry Andric     BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
1005*06c3fb27SDimitry Andric   if (Ranges.empty())
1006*06c3fb27SDimitry Andric     return;
1007*06c3fb27SDimitry Andric 
1008*06c3fb27SDimitry Andric   const IntRangeVector &R = getRanges();
1009*06c3fb27SDimitry Andric   size_t E = R.size();
1010*06c3fb27SDimitry Andric 
1011*06c3fb27SDimitry Andric   const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);
1012*06c3fb27SDimitry Andric   const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);
1013*06c3fb27SDimitry Andric 
1014*06c3fb27SDimitry Andric   const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);
1015*06c3fb27SDimitry Andric   const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);
1016*06c3fb27SDimitry Andric 
1017*06c3fb27SDimitry Andric   // Iterate over the "holes" between intervals.
1018*06c3fb27SDimitry Andric   for (size_t I = 1; I != E; ++I) {
1019*06c3fb27SDimitry Andric     const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);
1020*06c3fb27SDimitry Andric     const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);
1021*06c3fb27SDimitry Andric     if (Min <= Max) {
1022*06c3fb27SDimitry Andric       if (!F(Min, Max))
1023*06c3fb27SDimitry Andric         return;
1024*06c3fb27SDimitry Andric     }
1025*06c3fb27SDimitry Andric   }
1026*06c3fb27SDimitry Andric   // Check the interval [T_MIN, min(R) - 1].
1027*06c3fb27SDimitry Andric   if (RangeLeft != PlusInf) {
1028*06c3fb27SDimitry Andric     assert(MinusInf <= RangeLeft);
1029*06c3fb27SDimitry Andric     if (!F(MinusInf, RangeLeft))
1030*06c3fb27SDimitry Andric       return;
1031*06c3fb27SDimitry Andric   }
1032*06c3fb27SDimitry Andric   // Check the interval [max(R) + 1, T_MAX],
1033*06c3fb27SDimitry Andric   if (RangeRight != MinusInf) {
1034*06c3fb27SDimitry Andric     assert(RangeRight <= PlusInf);
1035*06c3fb27SDimitry Andric     if (!F(RangeRight, PlusInf))
1036*06c3fb27SDimitry Andric       return;
1037*06c3fb27SDimitry Andric   }
1038*06c3fb27SDimitry Andric }
1039*06c3fb27SDimitry Andric 
1040*06c3fb27SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
1041*06c3fb27SDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1042*06c3fb27SDimitry Andric     CheckerContext &C) const {
1043*06c3fb27SDimitry Andric   ConstraintManager &CM = C.getConstraintManager();
1044*06c3fb27SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
1045*06c3fb27SDimitry Andric   QualType T = Summary.getArgType(getArgNo());
1046*06c3fb27SDimitry Andric 
1047*06c3fb27SDimitry Andric   if (auto N = V.getAs<NonLoc>()) {
1048*06c3fb27SDimitry Andric     auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,
1049*06c3fb27SDimitry Andric                                    const llvm::APSInt &Max) {
1050*06c3fb27SDimitry Andric       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
1051*06c3fb27SDimitry Andric       return static_cast<bool>(State);
1052*06c3fb27SDimitry Andric     };
1053*06c3fb27SDimitry Andric     // "OutOfRange R" is handled by excluding all ranges in R.
1054*06c3fb27SDimitry Andric     // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
1055*06c3fb27SDimitry Andric     applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,
1056*06c3fb27SDimitry Andric                  ExcludeRangeFromArg);
1057*06c3fb27SDimitry Andric   }
1058*06c3fb27SDimitry Andric 
1059*06c3fb27SDimitry Andric   return State;
1060*06c3fb27SDimitry Andric }
1061*06c3fb27SDimitry Andric 
1062*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::describe(
1063*06c3fb27SDimitry Andric     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1064*06c3fb27SDimitry Andric     const Summary &Summary, llvm::raw_ostream &Out) const {
1065fe6060f1SDimitry Andric 
1066fe6060f1SDimitry Andric   BasicValueFactory &BVF = getBVF(State);
1067fe6060f1SDimitry Andric   QualType T = Summary.getArgType(getArgNo());
1068fe6060f1SDimitry Andric 
1069*06c3fb27SDimitry Andric   Out << ((DK == Violation) ? "should be " : "is ");
1070*06c3fb27SDimitry Andric   if (!Description.empty()) {
1071*06c3fb27SDimitry Andric     Out << Description;
1072*06c3fb27SDimitry Andric   } else {
1073fe6060f1SDimitry Andric     unsigned I = Ranges.size();
1074*06c3fb27SDimitry Andric     if (Kind == WithinRange) {
1075fe6060f1SDimitry Andric       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1076*06c3fb27SDimitry Andric         appendInsideRangeDesc(BVF.getValue(R.first, T),
1077*06c3fb27SDimitry Andric                               BVF.getValue(R.second, T), T, BVF, Out);
1078fe6060f1SDimitry Andric         if (--I > 0)
1079*06c3fb27SDimitry Andric           Out << " or ";
1080fe6060f1SDimitry Andric       }
1081*06c3fb27SDimitry Andric     } else {
1082*06c3fb27SDimitry Andric       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1083*06c3fb27SDimitry Andric         appendOutOfRangeDesc(BVF.getValue(R.first, T),
1084*06c3fb27SDimitry Andric                              BVF.getValue(R.second, T), T, BVF, Out);
1085*06c3fb27SDimitry Andric         if (--I > 0)
1086*06c3fb27SDimitry Andric           Out << " and ";
1087*06c3fb27SDimitry Andric       }
1088*06c3fb27SDimitry Andric     }
1089*06c3fb27SDimitry Andric   }
1090fe6060f1SDimitry Andric }
1091fe6060f1SDimitry Andric 
1092*06c3fb27SDimitry Andric bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
1093*06c3fb27SDimitry Andric     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1094*06c3fb27SDimitry Andric     llvm::raw_ostream &Out) const {
1095*06c3fb27SDimitry Andric   unsigned int NRanges = 0;
1096*06c3fb27SDimitry Andric   bool HaveAllRanges = true;
10970b57cec5SDimitry Andric 
10980b57cec5SDimitry Andric   ProgramStateManager &Mgr = State->getStateManager();
1099*06c3fb27SDimitry Andric   BasicValueFactory &BVF = Mgr.getSValBuilder().getBasicValueFactory();
11000b57cec5SDimitry Andric   ConstraintManager &CM = Mgr.getConstraintManager();
11010b57cec5SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
11020b57cec5SDimitry Andric 
11030b57cec5SDimitry Andric   if (auto N = V.getAs<NonLoc>()) {
1104*06c3fb27SDimitry Andric     if (const llvm::APSInt *Int = N->getAsInteger()) {
1105*06c3fb27SDimitry Andric       Out << "is ";
1106*06c3fb27SDimitry Andric       Out << *Int;
1107*06c3fb27SDimitry Andric       return true;
11080b57cec5SDimitry Andric     }
11095ffd83dbSDimitry Andric     QualType T = Summary.getArgType(getArgNo());
1110*06c3fb27SDimitry Andric     SmallString<128> MoreInfo;
1111*06c3fb27SDimitry Andric     llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
1112*06c3fb27SDimitry Andric     auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
1113*06c3fb27SDimitry Andric       if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
1114*06c3fb27SDimitry Andric         if (NRanges > 0)
1115*06c3fb27SDimitry Andric           MoreInfoOs << " or ";
1116*06c3fb27SDimitry Andric         appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
1117*06c3fb27SDimitry Andric         ++NRanges;
1118*06c3fb27SDimitry Andric       } else {
1119*06c3fb27SDimitry Andric         HaveAllRanges = false;
11200b57cec5SDimitry Andric       }
1121*06c3fb27SDimitry Andric       return true;
1122*06c3fb27SDimitry Andric     };
11230b57cec5SDimitry Andric 
1124*06c3fb27SDimitry Andric     applyOnRange(Kind, BVF, T, ApplyF);
1125*06c3fb27SDimitry Andric     assert(NRanges > 0);
1126*06c3fb27SDimitry Andric     if (!HaveAllRanges || NRanges == 1) {
1127*06c3fb27SDimitry Andric       Out << "is ";
1128*06c3fb27SDimitry Andric       Out << MoreInfo;
1129*06c3fb27SDimitry Andric       return true;
11300b57cec5SDimitry Andric     }
11310b57cec5SDimitry Andric   }
1132*06c3fb27SDimitry Andric   return false;
11330b57cec5SDimitry Andric }
11340b57cec5SDimitry Andric 
11355ffd83dbSDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
11365ffd83dbSDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
11375ffd83dbSDimitry Andric     CheckerContext &C) const {
11380b57cec5SDimitry Andric 
11390b57cec5SDimitry Andric   ProgramStateManager &Mgr = State->getStateManager();
11400b57cec5SDimitry Andric   SValBuilder &SVB = Mgr.getSValBuilder();
11410b57cec5SDimitry Andric   QualType CondT = SVB.getConditionType();
11425ffd83dbSDimitry Andric   QualType T = Summary.getArgType(getArgNo());
11430b57cec5SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric   BinaryOperator::Opcode Op = getOpcode();
11465ffd83dbSDimitry Andric   ArgNo OtherArg = getOtherArgNo();
11470b57cec5SDimitry Andric   SVal OtherV = getArgSVal(Call, OtherArg);
11485ffd83dbSDimitry Andric   QualType OtherT = Summary.getArgType(OtherArg);
11490b57cec5SDimitry Andric   // Note: we avoid integral promotion for comparison.
11500b57cec5SDimitry Andric   OtherV = SVB.evalCast(OtherV, T, OtherT);
11510b57cec5SDimitry Andric   if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
11520b57cec5SDimitry Andric                        .getAs<DefinedOrUnknownSVal>())
11530b57cec5SDimitry Andric     State = State->assume(*CompV, true);
11540b57cec5SDimitry Andric   return State;
11550b57cec5SDimitry Andric }
11560b57cec5SDimitry Andric 
1157*06c3fb27SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::NotNullConstraint::apply(
1158*06c3fb27SDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1159*06c3fb27SDimitry Andric     CheckerContext &C) const {
1160*06c3fb27SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
1161*06c3fb27SDimitry Andric   if (V.isUndef())
1162*06c3fb27SDimitry Andric     return State;
1163*06c3fb27SDimitry Andric 
1164*06c3fb27SDimitry Andric   DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1165*06c3fb27SDimitry Andric   if (!isa<Loc>(L))
1166*06c3fb27SDimitry Andric     return State;
1167*06c3fb27SDimitry Andric 
1168*06c3fb27SDimitry Andric   return State->assume(L, CannotBeNull);
1169*06c3fb27SDimitry Andric }
1170*06c3fb27SDimitry Andric 
1171*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::NotNullConstraint::describe(
1172*06c3fb27SDimitry Andric     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1173*06c3fb27SDimitry Andric     const Summary &Summary, llvm::raw_ostream &Out) const {
1174*06c3fb27SDimitry Andric   assert(CannotBeNull &&
1175*06c3fb27SDimitry Andric          "Describe should not be used when the value must be NULL");
1176*06c3fb27SDimitry Andric   if (DK == Violation)
1177*06c3fb27SDimitry Andric     Out << "should not be NULL";
1178*06c3fb27SDimitry Andric   else
1179*06c3fb27SDimitry Andric     Out << "is not NULL";
1180*06c3fb27SDimitry Andric }
1181*06c3fb27SDimitry Andric 
1182*06c3fb27SDimitry Andric bool StdLibraryFunctionsChecker::NotNullConstraint::describeArgumentValue(
1183*06c3fb27SDimitry Andric     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1184*06c3fb27SDimitry Andric     llvm::raw_ostream &Out) const {
1185*06c3fb27SDimitry Andric   assert(!CannotBeNull && "This function is used when the value is NULL");
1186*06c3fb27SDimitry Andric   Out << "is NULL";
1187*06c3fb27SDimitry Andric   return true;
1188*06c3fb27SDimitry Andric }
1189*06c3fb27SDimitry Andric 
1190*06c3fb27SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::NotNullBufferConstraint::apply(
1191*06c3fb27SDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1192*06c3fb27SDimitry Andric     CheckerContext &C) const {
1193*06c3fb27SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
1194*06c3fb27SDimitry Andric   if (V.isUndef())
1195*06c3fb27SDimitry Andric     return State;
1196*06c3fb27SDimitry Andric   DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1197*06c3fb27SDimitry Andric   if (!isa<Loc>(L))
1198*06c3fb27SDimitry Andric     return State;
1199*06c3fb27SDimitry Andric 
1200*06c3fb27SDimitry Andric   std::optional<DefinedOrUnknownSVal> SizeArg1 =
1201*06c3fb27SDimitry Andric       getArgSVal(Call, SizeArg1N).getAs<DefinedOrUnknownSVal>();
1202*06c3fb27SDimitry Andric   std::optional<DefinedOrUnknownSVal> SizeArg2;
1203*06c3fb27SDimitry Andric   if (SizeArg2N)
1204*06c3fb27SDimitry Andric     SizeArg2 = getArgSVal(Call, *SizeArg2N).getAs<DefinedOrUnknownSVal>();
1205*06c3fb27SDimitry Andric 
1206*06c3fb27SDimitry Andric   auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {
1207*06c3fb27SDimitry Andric     if (!Val)
1208*06c3fb27SDimitry Andric       return false;
1209*06c3fb27SDimitry Andric     auto [IsNonNull, IsNull] = State->assume(*Val);
1210*06c3fb27SDimitry Andric     return IsNull && !IsNonNull;
1211*06c3fb27SDimitry Andric   };
1212*06c3fb27SDimitry Andric 
1213*06c3fb27SDimitry Andric   if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))
1214*06c3fb27SDimitry Andric     return State;
1215*06c3fb27SDimitry Andric 
1216*06c3fb27SDimitry Andric   return State->assume(L, CannotBeNull);
1217*06c3fb27SDimitry Andric }
1218*06c3fb27SDimitry Andric 
1219*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::NotNullBufferConstraint::describe(
1220*06c3fb27SDimitry Andric     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1221*06c3fb27SDimitry Andric     const Summary &Summary, llvm::raw_ostream &Out) const {
1222*06c3fb27SDimitry Andric   assert(CannotBeNull &&
1223*06c3fb27SDimitry Andric          "Describe should not be used when the value must be NULL");
1224*06c3fb27SDimitry Andric   if (DK == Violation)
1225*06c3fb27SDimitry Andric     Out << "should not be NULL";
1226*06c3fb27SDimitry Andric   else
1227*06c3fb27SDimitry Andric     Out << "is not NULL";
1228*06c3fb27SDimitry Andric }
1229*06c3fb27SDimitry Andric 
1230*06c3fb27SDimitry Andric bool StdLibraryFunctionsChecker::NotNullBufferConstraint::describeArgumentValue(
1231*06c3fb27SDimitry Andric     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1232*06c3fb27SDimitry Andric     llvm::raw_ostream &Out) const {
1233*06c3fb27SDimitry Andric   assert(!CannotBeNull && "This function is used when the value is NULL");
1234*06c3fb27SDimitry Andric   Out << "is NULL";
1235*06c3fb27SDimitry Andric   return true;
1236*06c3fb27SDimitry Andric }
1237*06c3fb27SDimitry Andric 
1238*06c3fb27SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
1239*06c3fb27SDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1240*06c3fb27SDimitry Andric     CheckerContext &C) const {
1241*06c3fb27SDimitry Andric   SValBuilder &SvalBuilder = C.getSValBuilder();
1242*06c3fb27SDimitry Andric   // The buffer argument.
1243*06c3fb27SDimitry Andric   SVal BufV = getArgSVal(Call, getArgNo());
1244*06c3fb27SDimitry Andric 
1245*06c3fb27SDimitry Andric   // Get the size constraint.
1246*06c3fb27SDimitry Andric   const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
1247*06c3fb27SDimitry Andric     if (ConcreteSize) {
1248*06c3fb27SDimitry Andric       return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
1249*06c3fb27SDimitry Andric     }
1250*06c3fb27SDimitry Andric     assert(SizeArgN && "The constraint must be either a concrete value or "
1251*06c3fb27SDimitry Andric                        "encoded in an argument.");
1252*06c3fb27SDimitry Andric     // The size argument.
1253*06c3fb27SDimitry Andric     SVal SizeV = getArgSVal(Call, *SizeArgN);
1254*06c3fb27SDimitry Andric     // Multiply with another argument if given.
1255*06c3fb27SDimitry Andric     if (SizeMultiplierArgN) {
1256*06c3fb27SDimitry Andric       SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
1257*06c3fb27SDimitry Andric       SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
1258*06c3fb27SDimitry Andric                                     Summary.getArgType(*SizeArgN));
1259*06c3fb27SDimitry Andric     }
1260*06c3fb27SDimitry Andric     return SizeV;
1261*06c3fb27SDimitry Andric   }();
1262*06c3fb27SDimitry Andric 
1263*06c3fb27SDimitry Andric   // The dynamic size of the buffer argument, got from the analyzer engine.
1264*06c3fb27SDimitry Andric   SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1265*06c3fb27SDimitry Andric 
1266*06c3fb27SDimitry Andric   SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
1267*06c3fb27SDimitry Andric                                         SvalBuilder.getContext().BoolTy);
1268*06c3fb27SDimitry Andric   if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
1269*06c3fb27SDimitry Andric     return State->assume(*F, true);
1270*06c3fb27SDimitry Andric 
1271*06c3fb27SDimitry Andric   // We can get here only if the size argument or the dynamic size is
1272*06c3fb27SDimitry Andric   // undefined. But the dynamic size should never be undefined, only
1273*06c3fb27SDimitry Andric   // unknown. So, here, the size of the argument is undefined, i.e. we
1274*06c3fb27SDimitry Andric   // cannot apply the constraint. Actually, other checkers like
1275*06c3fb27SDimitry Andric   // CallAndMessage should catch this situation earlier, because we call a
1276*06c3fb27SDimitry Andric   // function with an uninitialized argument.
1277*06c3fb27SDimitry Andric   llvm_unreachable("Size argument or the dynamic size is Undefined");
1278*06c3fb27SDimitry Andric }
1279*06c3fb27SDimitry Andric 
1280*06c3fb27SDimitry Andric void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
1281*06c3fb27SDimitry Andric     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1282*06c3fb27SDimitry Andric     const Summary &Summary, llvm::raw_ostream &Out) const {
1283*06c3fb27SDimitry Andric   Out << ((DK == Violation) ? "should be " : "is ");
1284*06c3fb27SDimitry Andric   Out << "a buffer with size equal to or greater than ";
1285*06c3fb27SDimitry Andric   if (ConcreteSize) {
1286*06c3fb27SDimitry Andric     Out << *ConcreteSize;
1287*06c3fb27SDimitry Andric   } else if (SizeArgN) {
1288*06c3fb27SDimitry Andric     Out << "the value of the ";
1289*06c3fb27SDimitry Andric     printArgDesc(*SizeArgN, Out);
1290*06c3fb27SDimitry Andric     printArgValueInfo(*SizeArgN, State, Call, Out);
1291*06c3fb27SDimitry Andric     if (SizeMultiplierArgN) {
1292*06c3fb27SDimitry Andric       Out << " times the ";
1293*06c3fb27SDimitry Andric       printArgDesc(*SizeMultiplierArgN, Out);
1294*06c3fb27SDimitry Andric       printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
1295*06c3fb27SDimitry Andric     }
1296*06c3fb27SDimitry Andric   }
1297*06c3fb27SDimitry Andric }
1298*06c3fb27SDimitry Andric 
1299*06c3fb27SDimitry Andric bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
1300*06c3fb27SDimitry Andric     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1301*06c3fb27SDimitry Andric     llvm::raw_ostream &Out) const {
1302*06c3fb27SDimitry Andric   SVal BufV = getArgSVal(Call, getArgNo());
1303*06c3fb27SDimitry Andric   SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1304*06c3fb27SDimitry Andric   if (const llvm::APSInt *Val =
1305*06c3fb27SDimitry Andric           State->getStateManager().getSValBuilder().getKnownValue(State,
1306*06c3fb27SDimitry Andric                                                                   BufDynSize)) {
1307*06c3fb27SDimitry Andric     Out << "is a buffer with size " << *Val;
1308*06c3fb27SDimitry Andric     return true;
1309*06c3fb27SDimitry Andric   }
1310*06c3fb27SDimitry Andric   return false;
1311*06c3fb27SDimitry Andric }
1312*06c3fb27SDimitry Andric 
13135ffd83dbSDimitry Andric void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
13140b57cec5SDimitry Andric                                               CheckerContext &C) const {
1315bdd1243dSDimitry Andric   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
13160b57cec5SDimitry Andric   if (!FoundSummary)
13170b57cec5SDimitry Andric     return;
13180b57cec5SDimitry Andric 
13195ffd83dbSDimitry Andric   const Summary &Summary = *FoundSummary;
13200b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
13210b57cec5SDimitry Andric 
13220b57cec5SDimitry Andric   ProgramStateRef NewState = State;
1323bdd1243dSDimitry Andric   ExplodedNode *NewNode = C.getPredecessor();
13245ffd83dbSDimitry Andric   for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
1325*06c3fb27SDimitry Andric     ValueConstraintPtr NegatedConstraint = Constraint->negate();
13265ffd83dbSDimitry Andric     ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
13275ffd83dbSDimitry Andric     ProgramStateRef FailureSt =
1328*06c3fb27SDimitry Andric         NegatedConstraint->apply(NewState, Call, Summary, C);
13295ffd83dbSDimitry Andric     // The argument constraint is not satisfied.
13305ffd83dbSDimitry Andric     if (FailureSt && !SuccessSt) {
1331*06c3fb27SDimitry Andric       if (ExplodedNode *N = C.generateErrorNode(State, NewNode))
1332*06c3fb27SDimitry Andric         reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,
1333*06c3fb27SDimitry Andric                   C);
13345ffd83dbSDimitry Andric       break;
1335bdd1243dSDimitry Andric     }
13365ffd83dbSDimitry Andric     // We will apply the constraint even if we cannot reason about the
13375ffd83dbSDimitry Andric     // argument. This means both SuccessSt and FailureSt can be true. If we
13385ffd83dbSDimitry Andric     // weren't applying the constraint that would mean that symbolic
13395ffd83dbSDimitry Andric     // execution continues on a code whose behaviour is undefined.
13405ffd83dbSDimitry Andric     assert(SuccessSt);
13415ffd83dbSDimitry Andric     NewState = SuccessSt;
1342bdd1243dSDimitry Andric     if (NewState != State) {
1343*06c3fb27SDimitry Andric       SmallString<128> Msg;
1344*06c3fb27SDimitry Andric       llvm::raw_svector_ostream Os(Msg);
1345*06c3fb27SDimitry Andric       Os << "Assuming that the ";
1346*06c3fb27SDimitry Andric       printArgDesc(Constraint->getArgNo(), Os);
1347*06c3fb27SDimitry Andric       Os << " to '";
1348*06c3fb27SDimitry Andric       Os << getFunctionName(Call);
1349*06c3fb27SDimitry Andric       Os << "' ";
1350*06c3fb27SDimitry Andric       Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
1351*06c3fb27SDimitry Andric                            Os);
1352bdd1243dSDimitry Andric       const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
1353bdd1243dSDimitry Andric       NewNode = C.addTransition(
1354bdd1243dSDimitry Andric           NewState, NewNode,
1355bdd1243dSDimitry Andric           C.getNoteTag([Msg = std::move(Msg), ArgSVal](
1356bdd1243dSDimitry Andric                            PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1357bdd1243dSDimitry Andric             if (BR.isInteresting(ArgSVal))
1358bdd1243dSDimitry Andric               OS << Msg;
1359bdd1243dSDimitry Andric           }));
13605ffd83dbSDimitry Andric     }
13615ffd83dbSDimitry Andric   }
13625ffd83dbSDimitry Andric }
13635ffd83dbSDimitry Andric 
13645ffd83dbSDimitry Andric void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
13655ffd83dbSDimitry Andric                                                CheckerContext &C) const {
1366bdd1243dSDimitry Andric   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
13675ffd83dbSDimitry Andric   if (!FoundSummary)
13685ffd83dbSDimitry Andric     return;
13695ffd83dbSDimitry Andric 
13705ffd83dbSDimitry Andric   // Now apply the constraints.
13715ffd83dbSDimitry Andric   const Summary &Summary = *FoundSummary;
13725ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1373*06c3fb27SDimitry Andric   ExplodedNode *Node = C.getPredecessor();
13745ffd83dbSDimitry Andric 
13755ffd83dbSDimitry Andric   // Apply case/branch specifications.
137681ad6265SDimitry Andric   for (const SummaryCase &Case : Summary.getCases()) {
13775ffd83dbSDimitry Andric     ProgramStateRef NewState = State;
137881ad6265SDimitry Andric     for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
13795ffd83dbSDimitry Andric       NewState = Constraint->apply(NewState, Call, Summary, C);
13800b57cec5SDimitry Andric       if (!NewState)
13810b57cec5SDimitry Andric         break;
13820b57cec5SDimitry Andric     }
13830b57cec5SDimitry Andric 
138481ad6265SDimitry Andric     if (NewState)
138581ad6265SDimitry Andric       NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
138681ad6265SDimitry Andric 
1387*06c3fb27SDimitry Andric     if (!NewState)
1388*06c3fb27SDimitry Andric       continue;
1389*06c3fb27SDimitry Andric 
1390*06c3fb27SDimitry Andric     // It is possible that NewState == State is true.
1391*06c3fb27SDimitry Andric     // It can occur if another checker has applied the state before us.
1392*06c3fb27SDimitry Andric     // Still add these note tags, the other checker should add only its
1393*06c3fb27SDimitry Andric     // specialized note tags. These general note tags are handled always by
1394*06c3fb27SDimitry Andric     // StdLibraryFunctionsChecker.
1395*06c3fb27SDimitry Andric     ExplodedNode *Pred = Node;
1396*06c3fb27SDimitry Andric     if (!Case.getNote().empty()) {
1397*06c3fb27SDimitry Andric       const SVal RV = Call.getReturnValue();
1398*06c3fb27SDimitry Andric       // If there is a description for this execution branch (summary case),
1399*06c3fb27SDimitry Andric       // use it as a note tag.
1400*06c3fb27SDimitry Andric       std::string Note =
1401*06c3fb27SDimitry Andric           llvm::formatv(Case.getNote().str().c_str(),
1402*06c3fb27SDimitry Andric                         cast<NamedDecl>(Call.getDecl())->getDeclName());
1403*06c3fb27SDimitry Andric       if (Summary.getInvalidationKd() == EvalCallAsPure) {
140481ad6265SDimitry Andric         const NoteTag *Tag = C.getNoteTag(
1405*06c3fb27SDimitry Andric             [Node, Note, RV](PathSensitiveBugReport &BR) -> std::string {
1406*06c3fb27SDimitry Andric               // Try to omit the note if we know in advance which branch is
1407*06c3fb27SDimitry Andric               // taken (this means, only one branch exists).
1408*06c3fb27SDimitry Andric               // This check is performed inside the lambda, after other
1409*06c3fb27SDimitry Andric               // (or this) checkers had a chance to add other successors.
1410*06c3fb27SDimitry Andric               // Dereferencing the saved node object is valid because it's part
1411*06c3fb27SDimitry Andric               // of a bug report call sequence.
1412*06c3fb27SDimitry Andric               // FIXME: This check is not exact. We may be here after a state
1413*06c3fb27SDimitry Andric               // split that was performed by another checker (and can not find
1414*06c3fb27SDimitry Andric               // the successors). This is why this check is only used in the
1415*06c3fb27SDimitry Andric               // EvalCallAsPure case.
1416*06c3fb27SDimitry Andric               if (BR.isInteresting(RV) && Node->succ_size() > 1)
1417*06c3fb27SDimitry Andric                 return Note;
1418*06c3fb27SDimitry Andric               return "";
1419*06c3fb27SDimitry Andric             });
1420*06c3fb27SDimitry Andric         Pred = C.addTransition(NewState, Pred, Tag);
1421*06c3fb27SDimitry Andric       } else {
1422*06c3fb27SDimitry Andric         const NoteTag *Tag =
1423*06c3fb27SDimitry Andric             C.getNoteTag([Note, RV](PathSensitiveBugReport &BR) -> std::string {
1424*06c3fb27SDimitry Andric               if (BR.isInteresting(RV))
1425*06c3fb27SDimitry Andric                 return Note;
1426*06c3fb27SDimitry Andric               return "";
1427*06c3fb27SDimitry Andric             });
1428*06c3fb27SDimitry Andric         Pred = C.addTransition(NewState, Pred, Tag);
142981ad6265SDimitry Andric       }
1430*06c3fb27SDimitry Andric       if (!Pred)
1431*06c3fb27SDimitry Andric         continue;
1432*06c3fb27SDimitry Andric     }
1433*06c3fb27SDimitry Andric 
1434*06c3fb27SDimitry Andric     // If we can get a note tag for the errno change, add this additionally to
1435*06c3fb27SDimitry Andric     // the previous. This note is only about value of 'errno' and is displayed
1436*06c3fb27SDimitry Andric     // if 'errno' is interesting.
1437*06c3fb27SDimitry Andric     if (const auto *D = dyn_cast<FunctionDecl>(Call.getDecl()))
1438bdd1243dSDimitry Andric       if (const NoteTag *NT =
1439bdd1243dSDimitry Andric               Case.getErrnoConstraint().describe(C, D->getNameAsString()))
1440*06c3fb27SDimitry Andric         Pred = C.addTransition(NewState, Pred, NT);
1441*06c3fb27SDimitry Andric 
1442*06c3fb27SDimitry Andric     // Add the transition if no note tag could be added.
1443*06c3fb27SDimitry Andric     if (Pred == Node && NewState != State)
1444*06c3fb27SDimitry Andric       C.addTransition(NewState);
14450b57cec5SDimitry Andric   }
14460b57cec5SDimitry Andric }
14470b57cec5SDimitry Andric 
14480b57cec5SDimitry Andric bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
14490b57cec5SDimitry Andric                                           CheckerContext &C) const {
1450bdd1243dSDimitry Andric   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
14510b57cec5SDimitry Andric   if (!FoundSummary)
14520b57cec5SDimitry Andric     return false;
14530b57cec5SDimitry Andric 
14545ffd83dbSDimitry Andric   const Summary &Summary = *FoundSummary;
14555ffd83dbSDimitry Andric   switch (Summary.getInvalidationKd()) {
14560b57cec5SDimitry Andric   case EvalCallAsPure: {
14570b57cec5SDimitry Andric     ProgramStateRef State = C.getState();
14580b57cec5SDimitry Andric     const LocationContext *LC = C.getLocationContext();
1459e8d8bef9SDimitry Andric     const auto *CE = cast<CallExpr>(Call.getOriginExpr());
14600b57cec5SDimitry Andric     SVal V = C.getSValBuilder().conjureSymbolVal(
14610b57cec5SDimitry Andric         CE, LC, CE->getType().getCanonicalType(), C.blockCount());
14620b57cec5SDimitry Andric     State = State->BindExpr(CE, LC, V);
146381ad6265SDimitry Andric 
14640b57cec5SDimitry Andric     C.addTransition(State);
146581ad6265SDimitry Andric 
14660b57cec5SDimitry Andric     return true;
14670b57cec5SDimitry Andric   }
14680b57cec5SDimitry Andric   case NoEvalCall:
14690b57cec5SDimitry Andric     // Summary tells us to avoid performing eval::Call. The function is possibly
14700b57cec5SDimitry Andric     // evaluated by another checker, or evaluated conservatively.
14710b57cec5SDimitry Andric     return false;
14720b57cec5SDimitry Andric   }
14730b57cec5SDimitry Andric   llvm_unreachable("Unknown invalidation kind!");
14740b57cec5SDimitry Andric }
14750b57cec5SDimitry Andric 
14765ffd83dbSDimitry Andric bool StdLibraryFunctionsChecker::Signature::matches(
14775ffd83dbSDimitry Andric     const FunctionDecl *FD) const {
1478e8d8bef9SDimitry Andric   assert(!isInvalid());
1479e8d8bef9SDimitry Andric   // Check the number of arguments.
14805ffd83dbSDimitry Andric   if (FD->param_size() != ArgTys.size())
14810b57cec5SDimitry Andric     return false;
14820b57cec5SDimitry Andric 
1483e8d8bef9SDimitry Andric   // The "restrict" keyword is illegal in C++, however, many libc
1484e8d8bef9SDimitry Andric   // implementations use the "__restrict" compiler intrinsic in functions
1485e8d8bef9SDimitry Andric   // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1486e8d8bef9SDimitry Andric   // even in C++.
1487e8d8bef9SDimitry Andric   // In case of any non-C99 languages, we don't want to match based on the
1488e8d8bef9SDimitry Andric   // restrict qualifier because we cannot know if the given libc implementation
1489e8d8bef9SDimitry Andric   // qualifies the paramter type or not.
1490e8d8bef9SDimitry Andric   auto RemoveRestrict = [&FD](QualType T) {
1491e8d8bef9SDimitry Andric     if (!FD->getASTContext().getLangOpts().C99)
1492e8d8bef9SDimitry Andric       T.removeLocalRestrict();
1493e8d8bef9SDimitry Andric     return T;
1494e8d8bef9SDimitry Andric   };
14950b57cec5SDimitry Andric 
1496e8d8bef9SDimitry Andric   // Check the return type.
1497e8d8bef9SDimitry Andric   if (!isIrrelevant(RetTy)) {
1498e8d8bef9SDimitry Andric     QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1499e8d8bef9SDimitry Andric     if (RetTy != FDRetTy)
1500e8d8bef9SDimitry Andric       return false;
1501e8d8bef9SDimitry Andric   }
1502e8d8bef9SDimitry Andric 
1503e8d8bef9SDimitry Andric   // Check the argument types.
1504*06c3fb27SDimitry Andric   for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {
15055ffd83dbSDimitry Andric     if (isIrrelevant(ArgTy))
15060b57cec5SDimitry Andric       continue;
1507e8d8bef9SDimitry Andric     QualType FDArgTy =
1508*06c3fb27SDimitry Andric         RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());
1509e8d8bef9SDimitry Andric     if (ArgTy != FDArgTy)
15100b57cec5SDimitry Andric       return false;
15110b57cec5SDimitry Andric   }
15120b57cec5SDimitry Andric 
15130b57cec5SDimitry Andric   return true;
15140b57cec5SDimitry Andric }
15150b57cec5SDimitry Andric 
1516bdd1243dSDimitry Andric std::optional<StdLibraryFunctionsChecker::Summary>
15170b57cec5SDimitry Andric StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
15180b57cec5SDimitry Andric                                                 CheckerContext &C) const {
15190b57cec5SDimitry Andric   if (!FD)
1520bdd1243dSDimitry Andric     return std::nullopt;
15210b57cec5SDimitry Andric 
15225ffd83dbSDimitry Andric   initFunctionSummaries(C);
15230b57cec5SDimitry Andric 
15245ffd83dbSDimitry Andric   auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
15250b57cec5SDimitry Andric   if (FSMI == FunctionSummaryMap.end())
1526bdd1243dSDimitry Andric     return std::nullopt;
15275ffd83dbSDimitry Andric   return FSMI->second;
15285ffd83dbSDimitry Andric }
15290b57cec5SDimitry Andric 
1530bdd1243dSDimitry Andric std::optional<StdLibraryFunctionsChecker::Summary>
15315ffd83dbSDimitry Andric StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
15325ffd83dbSDimitry Andric                                                 CheckerContext &C) const {
15335ffd83dbSDimitry Andric   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
15345ffd83dbSDimitry Andric   if (!FD)
1535bdd1243dSDimitry Andric     return std::nullopt;
15365ffd83dbSDimitry Andric   return findFunctionSummary(FD, C);
15375ffd83dbSDimitry Andric }
15380b57cec5SDimitry Andric 
1539e8d8bef9SDimitry Andric void StdLibraryFunctionsChecker::initFunctionSummaries(
1540e8d8bef9SDimitry Andric     CheckerContext &C) const {
1541fe6060f1SDimitry Andric   if (SummariesInitialized)
1542e8d8bef9SDimitry Andric     return;
1543*06c3fb27SDimitry Andric   SummariesInitialized = true;
1544e8d8bef9SDimitry Andric 
1545e8d8bef9SDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
1546e8d8bef9SDimitry Andric   BasicValueFactory &BVF = SVB.getBasicValueFactory();
1547e8d8bef9SDimitry Andric   const ASTContext &ACtx = BVF.getContext();
1548*06c3fb27SDimitry Andric   Preprocessor &PP = C.getPreprocessor();
1549e8d8bef9SDimitry Andric 
1550e8d8bef9SDimitry Andric   // Helper class to lookup a type by its name.
1551e8d8bef9SDimitry Andric   class LookupType {
1552e8d8bef9SDimitry Andric     const ASTContext &ACtx;
1553e8d8bef9SDimitry Andric 
1554e8d8bef9SDimitry Andric   public:
1555e8d8bef9SDimitry Andric     LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1556e8d8bef9SDimitry Andric 
1557e8d8bef9SDimitry Andric     // Find the type. If not found then the optional is not set.
1558bdd1243dSDimitry Andric     std::optional<QualType> operator()(StringRef Name) {
15595ffd83dbSDimitry Andric       IdentifierInfo &II = ACtx.Idents.get(Name);
15605ffd83dbSDimitry Andric       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1561fe6060f1SDimitry Andric       if (LookupRes.empty())
1562bdd1243dSDimitry Andric         return std::nullopt;
15635ffd83dbSDimitry Andric 
15645ffd83dbSDimitry Andric       // Prioritze typedef declarations.
15655ffd83dbSDimitry Andric       // This is needed in case of C struct typedefs. E.g.:
15665ffd83dbSDimitry Andric       //   typedef struct FILE FILE;
1567e8d8bef9SDimitry Andric       // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1568e8d8bef9SDimitry Andric       // and we have a TypedefDecl with the name 'FILE'.
15695ffd83dbSDimitry Andric       for (Decl *D : LookupRes)
15705ffd83dbSDimitry Andric         if (auto *TD = dyn_cast<TypedefNameDecl>(D))
15715ffd83dbSDimitry Andric           return ACtx.getTypeDeclType(TD).getCanonicalType();
15725ffd83dbSDimitry Andric 
15735ffd83dbSDimitry Andric       // Find the first TypeDecl.
15745ffd83dbSDimitry Andric       // There maybe cases when a function has the same name as a struct.
15755ffd83dbSDimitry Andric       // E.g. in POSIX: `struct stat` and the function `stat()`:
15765ffd83dbSDimitry Andric       //   int stat(const char *restrict path, struct stat *restrict buf);
15775ffd83dbSDimitry Andric       for (Decl *D : LookupRes)
15785ffd83dbSDimitry Andric         if (auto *TD = dyn_cast<TypeDecl>(D))
15795ffd83dbSDimitry Andric           return ACtx.getTypeDeclType(TD).getCanonicalType();
1580bdd1243dSDimitry Andric       return std::nullopt;
15810b57cec5SDimitry Andric     }
1582e8d8bef9SDimitry Andric   } lookupTy(ACtx);
15830b57cec5SDimitry Andric 
1584e8d8bef9SDimitry Andric   // Below are auxiliary classes to handle optional types that we get as a
1585e8d8bef9SDimitry Andric   // result of the lookup.
1586e8d8bef9SDimitry Andric   class GetRestrictTy {
1587e8d8bef9SDimitry Andric     const ASTContext &ACtx;
15880b57cec5SDimitry Andric 
1589e8d8bef9SDimitry Andric   public:
1590e8d8bef9SDimitry Andric     GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1591e8d8bef9SDimitry Andric     QualType operator()(QualType Ty) {
1592e8d8bef9SDimitry Andric       return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1593e8d8bef9SDimitry Andric     }
1594bdd1243dSDimitry Andric     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1595e8d8bef9SDimitry Andric       if (Ty)
1596e8d8bef9SDimitry Andric         return operator()(*Ty);
1597bdd1243dSDimitry Andric       return std::nullopt;
1598e8d8bef9SDimitry Andric     }
1599e8d8bef9SDimitry Andric   } getRestrictTy(ACtx);
1600e8d8bef9SDimitry Andric   class GetPointerTy {
1601e8d8bef9SDimitry Andric     const ASTContext &ACtx;
1602e8d8bef9SDimitry Andric 
1603e8d8bef9SDimitry Andric   public:
1604e8d8bef9SDimitry Andric     GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1605e8d8bef9SDimitry Andric     QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1606bdd1243dSDimitry Andric     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1607e8d8bef9SDimitry Andric       if (Ty)
1608e8d8bef9SDimitry Andric         return operator()(*Ty);
1609bdd1243dSDimitry Andric       return std::nullopt;
1610e8d8bef9SDimitry Andric     }
1611e8d8bef9SDimitry Andric   } getPointerTy(ACtx);
1612e8d8bef9SDimitry Andric   class {
1613e8d8bef9SDimitry Andric   public:
1614bdd1243dSDimitry Andric     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1615bdd1243dSDimitry Andric       return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1616e8d8bef9SDimitry Andric     }
1617e8d8bef9SDimitry Andric     QualType operator()(QualType Ty) { return Ty.withConst(); }
1618e8d8bef9SDimitry Andric   } getConstTy;
1619e8d8bef9SDimitry Andric   class GetMaxValue {
1620e8d8bef9SDimitry Andric     BasicValueFactory &BVF;
1621e8d8bef9SDimitry Andric 
1622e8d8bef9SDimitry Andric   public:
1623e8d8bef9SDimitry Andric     GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1624bdd1243dSDimitry Andric     std::optional<RangeInt> operator()(QualType Ty) {
1625e8d8bef9SDimitry Andric       return BVF.getMaxValue(Ty).getLimitedValue();
1626e8d8bef9SDimitry Andric     }
1627bdd1243dSDimitry Andric     std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1628e8d8bef9SDimitry Andric       if (Ty) {
1629e8d8bef9SDimitry Andric         return operator()(*Ty);
1630e8d8bef9SDimitry Andric       }
1631bdd1243dSDimitry Andric       return std::nullopt;
1632e8d8bef9SDimitry Andric     }
1633e8d8bef9SDimitry Andric   } getMaxValue(BVF);
16340b57cec5SDimitry Andric 
16350b57cec5SDimitry Andric   // These types are useful for writing specifications quickly,
16360b57cec5SDimitry Andric   // New specifications should probably introduce more types.
16370b57cec5SDimitry Andric   // Some types are hard to obtain from the AST, eg. "ssize_t".
16380b57cec5SDimitry Andric   // In such cases it should be possible to provide multiple variants
16390b57cec5SDimitry Andric   // of function summary for common cases (eg. ssize_t could be int or long
16400b57cec5SDimitry Andric   // or long long, so three summary variants would be enough).
16410b57cec5SDimitry Andric   // Of course, function variants are also useful for C++ overloads.
16425ffd83dbSDimitry Andric   const QualType VoidTy = ACtx.VoidTy;
1643e8d8bef9SDimitry Andric   const QualType CharTy = ACtx.CharTy;
1644e8d8bef9SDimitry Andric   const QualType WCharTy = ACtx.WCharTy;
16455ffd83dbSDimitry Andric   const QualType IntTy = ACtx.IntTy;
16465ffd83dbSDimitry Andric   const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
16475ffd83dbSDimitry Andric   const QualType LongTy = ACtx.LongTy;
16485ffd83dbSDimitry Andric   const QualType SizeTy = ACtx.getSizeType();
16490b57cec5SDimitry Andric 
1650e8d8bef9SDimitry Andric   const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1651e8d8bef9SDimitry Andric   const QualType IntPtrTy = getPointerTy(IntTy);   // int *
16525ffd83dbSDimitry Andric   const QualType UnsignedIntPtrTy =
1653e8d8bef9SDimitry Andric       getPointerTy(UnsignedIntTy); // unsigned int *
1654e8d8bef9SDimitry Andric   const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
16555ffd83dbSDimitry Andric   const QualType ConstVoidPtrTy =
1656e8d8bef9SDimitry Andric       getPointerTy(getConstTy(VoidTy));            // const void *
1657e8d8bef9SDimitry Andric   const QualType CharPtrTy = getPointerTy(CharTy); // char *
1658e8d8bef9SDimitry Andric   const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
16595ffd83dbSDimitry Andric   const QualType ConstCharPtrTy =
1660e8d8bef9SDimitry Andric       getPointerTy(getConstTy(CharTy)); // const char *
1661e8d8bef9SDimitry Andric   const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1662e8d8bef9SDimitry Andric   const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
16635ffd83dbSDimitry Andric   const QualType ConstWchar_tPtrTy =
1664e8d8bef9SDimitry Andric       getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1665e8d8bef9SDimitry Andric   const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1666e8d8bef9SDimitry Andric   const QualType SizePtrTy = getPointerTy(SizeTy);
1667e8d8bef9SDimitry Andric   const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
16685ffd83dbSDimitry Andric 
16695ffd83dbSDimitry Andric   const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
16705ffd83dbSDimitry Andric   const RangeInt UnsignedIntMax =
16715ffd83dbSDimitry Andric       BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
16725ffd83dbSDimitry Andric   const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
16735ffd83dbSDimitry Andric   const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
16745ffd83dbSDimitry Andric 
16755ffd83dbSDimitry Andric   // Set UCharRangeMax to min of int or uchar maximum value.
16765ffd83dbSDimitry Andric   // The C standard states that the arguments of functions like isalpha must
16775ffd83dbSDimitry Andric   // be representable as an unsigned char. Their type is 'int', so the max
16785ffd83dbSDimitry Andric   // value of the argument should be min(UCharMax, IntMax). This just happen
16795ffd83dbSDimitry Andric   // to be true for commonly used and well tested instruction set
16805ffd83dbSDimitry Andric   // architectures, but not for others.
16815ffd83dbSDimitry Andric   const RangeInt UCharRangeMax =
16825ffd83dbSDimitry Andric       std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
16835ffd83dbSDimitry Andric 
1684*06c3fb27SDimitry Andric   // Get platform dependent values of some macros.
1685*06c3fb27SDimitry Andric   // Try our best to parse this from the Preprocessor, otherwise fallback to a
1686*06c3fb27SDimitry Andric   // default value (what is found in a library header).
1687*06c3fb27SDimitry Andric   const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
1688*06c3fb27SDimitry Andric   const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
16895ffd83dbSDimitry Andric 
16905ffd83dbSDimitry Andric   // Auxiliary class to aid adding summaries to the summary map.
16915ffd83dbSDimitry Andric   struct AddToFunctionSummaryMap {
16925ffd83dbSDimitry Andric     const ASTContext &ACtx;
16935ffd83dbSDimitry Andric     FunctionSummaryMapType &Map;
16945ffd83dbSDimitry Andric     bool DisplayLoadedSummaries;
16955ffd83dbSDimitry Andric     AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
16965ffd83dbSDimitry Andric                             bool DisplayLoadedSummaries)
16975ffd83dbSDimitry Andric         : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
16985ffd83dbSDimitry Andric     }
16995ffd83dbSDimitry Andric 
17005ffd83dbSDimitry Andric     // Add a summary to a FunctionDecl found by lookup. The lookup is performed
17015ffd83dbSDimitry Andric     // by the given Name, and in the global scope. The summary will be attached
17025ffd83dbSDimitry Andric     // to the found FunctionDecl only if the signatures match.
1703e8d8bef9SDimitry Andric     //
1704e8d8bef9SDimitry Andric     // Returns true if the summary has been added, false otherwise.
1705e8d8bef9SDimitry Andric     bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1706e8d8bef9SDimitry Andric       if (Sign.isInvalid())
1707e8d8bef9SDimitry Andric         return false;
17085ffd83dbSDimitry Andric       IdentifierInfo &II = ACtx.Idents.get(Name);
17095ffd83dbSDimitry Andric       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1710fe6060f1SDimitry Andric       if (LookupRes.empty())
1711e8d8bef9SDimitry Andric         return false;
17125ffd83dbSDimitry Andric       for (Decl *D : LookupRes) {
17135ffd83dbSDimitry Andric         if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1714e8d8bef9SDimitry Andric           if (Sum.matchesAndSet(Sign, FD)) {
1715e8d8bef9SDimitry Andric             auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
17165ffd83dbSDimitry Andric             assert(Res.second && "Function already has a summary set!");
17175ffd83dbSDimitry Andric             (void)Res;
17185ffd83dbSDimitry Andric             if (DisplayLoadedSummaries) {
17195ffd83dbSDimitry Andric               llvm::errs() << "Loaded summary for: ";
17205ffd83dbSDimitry Andric               FD->print(llvm::errs());
17215ffd83dbSDimitry Andric               llvm::errs() << "\n";
17225ffd83dbSDimitry Andric             }
1723e8d8bef9SDimitry Andric             return true;
17245ffd83dbSDimitry Andric           }
17255ffd83dbSDimitry Andric         }
17265ffd83dbSDimitry Andric       }
1727e8d8bef9SDimitry Andric       return false;
17285ffd83dbSDimitry Andric     }
1729e8d8bef9SDimitry Andric     // Add the same summary for different names with the Signature explicitly
1730e8d8bef9SDimitry Andric     // given.
1731e8d8bef9SDimitry Andric     void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1732e8d8bef9SDimitry Andric       for (StringRef Name : Names)
1733e8d8bef9SDimitry Andric         operator()(Name, Sign, Sum);
17345ffd83dbSDimitry Andric     }
17355ffd83dbSDimitry Andric   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
17360b57cec5SDimitry Andric 
17375ffd83dbSDimitry Andric   // Below are helpers functions to create the summaries.
1738*06c3fb27SDimitry Andric   auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
1739*06c3fb27SDimitry Andric                               StringRef Desc = "") {
1740*06c3fb27SDimitry Andric     return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
17415ffd83dbSDimitry Andric   };
17425ffd83dbSDimitry Andric   auto BufferSize = [](auto... Args) {
17435ffd83dbSDimitry Andric     return std::make_shared<BufferSizeConstraint>(Args...);
17445ffd83dbSDimitry Andric   };
17455ffd83dbSDimitry Andric   struct {
17465ffd83dbSDimitry Andric     auto operator()(RangeKind Kind, IntRangeVector Ranges) {
17475ffd83dbSDimitry Andric       return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
17485ffd83dbSDimitry Andric     }
17495ffd83dbSDimitry Andric     auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
17505ffd83dbSDimitry Andric       return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
17515ffd83dbSDimitry Andric     }
17525ffd83dbSDimitry Andric   } ReturnValueCondition;
1753e8d8bef9SDimitry Andric   struct {
1754e8d8bef9SDimitry Andric     auto operator()(RangeInt b, RangeInt e) {
17555ffd83dbSDimitry Andric       return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1756e8d8bef9SDimitry Andric     }
1757bdd1243dSDimitry Andric     auto operator()(RangeInt b, std::optional<RangeInt> e) {
1758e8d8bef9SDimitry Andric       if (e)
1759e8d8bef9SDimitry Andric         return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1760e8d8bef9SDimitry Andric       return IntRangeVector{};
1761e8d8bef9SDimitry Andric     }
1762e8d8bef9SDimitry Andric     auto operator()(std::pair<RangeInt, RangeInt> i0,
1763bdd1243dSDimitry Andric                     std::pair<RangeInt, std::optional<RangeInt>> i1) {
1764e8d8bef9SDimitry Andric       if (i1.second)
1765e8d8bef9SDimitry Andric         return IntRangeVector{i0, {i1.first, *(i1.second)}};
1766e8d8bef9SDimitry Andric       return IntRangeVector{i0};
1767e8d8bef9SDimitry Andric     }
1768e8d8bef9SDimitry Andric   } Range;
17695ffd83dbSDimitry Andric   auto SingleValue = [](RangeInt v) {
17705ffd83dbSDimitry Andric     return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
17715ffd83dbSDimitry Andric   };
17725ffd83dbSDimitry Andric   auto LessThanOrEq = BO_LE;
17735ffd83dbSDimitry Andric   auto NotNull = [&](ArgNo ArgN) {
17745ffd83dbSDimitry Andric     return std::make_shared<NotNullConstraint>(ArgN);
17755ffd83dbSDimitry Andric   };
1776bdd1243dSDimitry Andric   auto IsNull = [&](ArgNo ArgN) {
1777bdd1243dSDimitry Andric     return std::make_shared<NotNullConstraint>(ArgN, false);
1778bdd1243dSDimitry Andric   };
1779*06c3fb27SDimitry Andric   auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N, ArgNo SizeArg2N) {
1780*06c3fb27SDimitry Andric     return std::make_shared<NotNullBufferConstraint>(ArgN, SizeArg1N,
1781*06c3fb27SDimitry Andric                                                      SizeArg2N);
1782*06c3fb27SDimitry Andric   };
17830b57cec5SDimitry Andric 
1784bdd1243dSDimitry Andric   std::optional<QualType> FileTy = lookupTy("FILE");
1785bdd1243dSDimitry Andric   std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
1786bdd1243dSDimitry Andric   std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1787bdd1243dSDimitry Andric 
1788bdd1243dSDimitry Andric   std::optional<QualType> FPosTTy = lookupTy("fpos_t");
1789bdd1243dSDimitry Andric   std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
1790bdd1243dSDimitry Andric   std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
1791bdd1243dSDimitry Andric   std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
17925ffd83dbSDimitry Andric 
1793*06c3fb27SDimitry Andric   constexpr llvm::StringLiteral GenericSuccessMsg(
1794*06c3fb27SDimitry Andric       "Assuming that '{0}' is successful");
1795*06c3fb27SDimitry Andric   constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");
1796*06c3fb27SDimitry Andric 
1797e8d8bef9SDimitry Andric   // We are finally ready to define specifications for all supported functions.
1798e8d8bef9SDimitry Andric   //
1799e8d8bef9SDimitry Andric   // Argument ranges should always cover all variants. If return value
1800e8d8bef9SDimitry Andric   // is completely unknown, omit it from the respective range set.
1801e8d8bef9SDimitry Andric   //
1802e8d8bef9SDimitry Andric   // Every item in the list of range sets represents a particular
1803e8d8bef9SDimitry Andric   // execution path the analyzer would need to explore once
1804e8d8bef9SDimitry Andric   // the call is modeled - a new program state is constructed
1805e8d8bef9SDimitry Andric   // for every range set, and each range line in the range set
1806e8d8bef9SDimitry Andric   // corresponds to a specific constraint within this state.
18075ffd83dbSDimitry Andric 
18080b57cec5SDimitry Andric   // The isascii() family of functions.
18095ffd83dbSDimitry Andric   // The behavior is undefined if the value of the argument is not
18105ffd83dbSDimitry Andric   // representable as unsigned char or is not equal to EOF. See e.g. C99
18115ffd83dbSDimitry Andric   // 7.4.1.2 The isalpha function (p: 181-182).
18125ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1813e8d8bef9SDimitry Andric       "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1814e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18155ffd83dbSDimitry Andric           // Boils down to isupper() or islower() or isdigit().
18165ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange,
18175ffd83dbSDimitry Andric                                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
181881ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
181981ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is alphanumeric")
18205ffd83dbSDimitry Andric           // The locale-specific range.
18210b57cec5SDimitry Andric           // No post-condition. We are completely unaware of
18220b57cec5SDimitry Andric           // locale-specific return values.
182381ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
182481ad6265SDimitry Andric                 ErrnoIrrelevant)
18255ffd83dbSDimitry Andric           .Case(
18265ffd83dbSDimitry Andric               {ArgumentCondition(
18275ffd83dbSDimitry Andric                    0U, OutOfRange,
18285ffd83dbSDimitry Andric                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
182981ad6265SDimitry Andric                ReturnValueCondition(WithinRange, SingleValue(0))},
183081ad6265SDimitry Andric               ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
1831*06c3fb27SDimitry Andric           .ArgConstraint(ArgumentCondition(0U, WithinRange,
1832*06c3fb27SDimitry Andric                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
1833*06c3fb27SDimitry Andric                                            "an unsigned char value or EOF")));
18345ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1835e8d8bef9SDimitry Andric       "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1836e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18375ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
183881ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
183981ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is alphabetical")
18405ffd83dbSDimitry Andric           // The locale-specific range.
184181ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
184281ad6265SDimitry Andric                 ErrnoIrrelevant)
18435ffd83dbSDimitry Andric           .Case({ArgumentCondition(
18445ffd83dbSDimitry Andric                      0U, OutOfRange,
18455ffd83dbSDimitry Andric                      {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
184681ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
184781ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
18485ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1849e8d8bef9SDimitry Andric       "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1850e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18515ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
185281ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
185381ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is an ASCII character")
18545ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
185581ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
185681ad6265SDimitry Andric                 ErrnoIrrelevant,
185781ad6265SDimitry Andric                 "Assuming the character is not an ASCII character"));
18585ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1859e8d8bef9SDimitry Andric       "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1860e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18615ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
186281ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
186381ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is a blank character")
18645ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
186581ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
186681ad6265SDimitry Andric                 ErrnoIrrelevant,
186781ad6265SDimitry Andric                 "Assuming the character is not a blank character"));
18685ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1869e8d8bef9SDimitry Andric       "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1870e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18715ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
187281ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
187381ad6265SDimitry Andric                 ErrnoIrrelevant,
187481ad6265SDimitry Andric                 "Assuming the character is a control character")
18755ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
187681ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
187781ad6265SDimitry Andric                 ErrnoIrrelevant,
187881ad6265SDimitry Andric                 "Assuming the character is not a control character"));
18795ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1880e8d8bef9SDimitry Andric       "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1881e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18825ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
188381ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
188481ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is a digit")
18855ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
188681ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
188781ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is not a digit"));
18885ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1889e8d8bef9SDimitry Andric       "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1890e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18915ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
189281ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
189381ad6265SDimitry Andric                 ErrnoIrrelevant,
189481ad6265SDimitry Andric                 "Assuming the character has graphical representation")
189581ad6265SDimitry Andric           .Case(
189681ad6265SDimitry Andric               {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
189781ad6265SDimitry Andric                ReturnValueCondition(WithinRange, SingleValue(0))},
189881ad6265SDimitry Andric               ErrnoIrrelevant,
189981ad6265SDimitry Andric               "Assuming the character does not have graphical representation"));
19005ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1901e8d8bef9SDimitry Andric       "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1902e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19035ffd83dbSDimitry Andric           // Is certainly lowercase.
19045ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
190581ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
190681ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is a lowercase letter")
19075ffd83dbSDimitry Andric           // Is ascii but not lowercase.
19085ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
19095ffd83dbSDimitry Andric                  ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
191081ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
191181ad6265SDimitry Andric                 ErrnoIrrelevant,
191281ad6265SDimitry Andric                 "Assuming the character is not a lowercase letter")
19135ffd83dbSDimitry Andric           // The locale-specific range.
191481ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
191581ad6265SDimitry Andric                 ErrnoIrrelevant)
19165ffd83dbSDimitry Andric           // Is not an unsigned char.
19175ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
191881ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
191981ad6265SDimitry Andric                 ErrnoIrrelevant));
19205ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1921e8d8bef9SDimitry Andric       "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1922e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19235ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
192481ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
192581ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is printable")
19265ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
192781ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
192881ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is non-printable"));
19295ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1930e8d8bef9SDimitry Andric       "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1931e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19325ffd83dbSDimitry Andric           .Case({ArgumentCondition(
19335ffd83dbSDimitry Andric                      0U, WithinRange,
19345ffd83dbSDimitry Andric                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
193581ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
193681ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is a punctuation mark")
19375ffd83dbSDimitry Andric           .Case({ArgumentCondition(
19385ffd83dbSDimitry Andric                      0U, OutOfRange,
19395ffd83dbSDimitry Andric                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
194081ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
194181ad6265SDimitry Andric                 ErrnoIrrelevant,
194281ad6265SDimitry Andric                 "Assuming the character is not a punctuation mark"));
19435ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1944e8d8bef9SDimitry Andric       "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1945e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19465ffd83dbSDimitry Andric           // Space, '\f', '\n', '\r', '\t', '\v'.
19475ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
194881ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
194981ad6265SDimitry Andric                 ErrnoIrrelevant,
195081ad6265SDimitry Andric                 "Assuming the character is a whitespace character")
19515ffd83dbSDimitry Andric           // The locale-specific range.
195281ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
195381ad6265SDimitry Andric                 ErrnoIrrelevant)
19545ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange,
19555ffd83dbSDimitry Andric                                    {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
195681ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
195781ad6265SDimitry Andric                 ErrnoIrrelevant,
195881ad6265SDimitry Andric                 "Assuming the character is not a whitespace character"));
19595ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1960e8d8bef9SDimitry Andric       "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1961e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19625ffd83dbSDimitry Andric           // Is certainly uppercase.
19635ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
196481ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
196581ad6265SDimitry Andric                 ErrnoIrrelevant,
196681ad6265SDimitry Andric                 "Assuming the character is an uppercase letter")
19675ffd83dbSDimitry Andric           // The locale-specific range.
196881ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
196981ad6265SDimitry Andric                 ErrnoIrrelevant)
19705ffd83dbSDimitry Andric           // Other.
19715ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange,
19725ffd83dbSDimitry Andric                                    {{'A', 'Z'}, {128, UCharRangeMax}}),
197381ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
197481ad6265SDimitry Andric                 ErrnoIrrelevant,
197581ad6265SDimitry Andric                 "Assuming the character is not an uppercase letter"));
19765ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1977e8d8bef9SDimitry Andric       "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1978e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19795ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange,
19805ffd83dbSDimitry Andric                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
198181ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
198281ad6265SDimitry Andric                 ErrnoIrrelevant,
198381ad6265SDimitry Andric                 "Assuming the character is a hexadecimal digit")
19845ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange,
19855ffd83dbSDimitry Andric                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
198681ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
198781ad6265SDimitry Andric                 ErrnoIrrelevant,
198881ad6265SDimitry Andric                 "Assuming the character is not a hexadecimal digit"));
1989e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
1990e8d8bef9SDimitry Andric       "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1991e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
1992*06c3fb27SDimitry Andric           .ArgConstraint(ArgumentCondition(0U, WithinRange,
1993*06c3fb27SDimitry Andric                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
1994*06c3fb27SDimitry Andric                                            "an unsigned char value or EOF")));
1995e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
1996e8d8bef9SDimitry Andric       "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1997e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
1998*06c3fb27SDimitry Andric           .ArgConstraint(ArgumentCondition(0U, WithinRange,
1999*06c3fb27SDimitry Andric                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
2000*06c3fb27SDimitry Andric                                            "an unsigned char value or EOF")));
2001e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2002e8d8bef9SDimitry Andric       "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2003e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
2004*06c3fb27SDimitry Andric           .ArgConstraint(ArgumentCondition(0U, WithinRange,
2005*06c3fb27SDimitry Andric                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
2006*06c3fb27SDimitry Andric                                            "an unsigned char value or EOF")));
20070b57cec5SDimitry Andric 
20080b57cec5SDimitry Andric   // The getc() family of functions that returns either a char or an EOF.
20095ffd83dbSDimitry Andric   addToFunctionSummaryMap(
2010e8d8bef9SDimitry Andric       {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2011e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2012e8d8bef9SDimitry Andric           .Case({ReturnValueCondition(WithinRange,
201381ad6265SDimitry Andric                                       {{EOFv, EOFv}, {0, UCharRangeMax}})},
201481ad6265SDimitry Andric                 ErrnoIrrelevant));
2015e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2016e8d8bef9SDimitry Andric       "getchar", Signature(ArgTypes{}, RetType{IntTy}),
2017e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2018e8d8bef9SDimitry Andric           .Case({ReturnValueCondition(WithinRange,
201981ad6265SDimitry Andric                                       {{EOFv, EOFv}, {0, UCharRangeMax}})},
202081ad6265SDimitry Andric                 ErrnoIrrelevant));
20210b57cec5SDimitry Andric 
20220b57cec5SDimitry Andric   // read()-like functions that never return more than buffer size.
2023e8d8bef9SDimitry Andric   auto FreadSummary =
2024e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2025bdd1243dSDimitry Andric           .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2026bdd1243dSDimitry Andric                  ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
2027bdd1243dSDimitry Andric                  ReturnValueCondition(BO_LT, ArgNo(2)),
202881ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2029*06c3fb27SDimitry Andric                 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2030bdd1243dSDimitry Andric           .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2031bdd1243dSDimitry Andric                  ReturnValueCondition(BO_EQ, ArgNo(2)),
2032bdd1243dSDimitry Andric                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2033*06c3fb27SDimitry Andric                 ErrnoMustNotBeChecked, GenericSuccessMsg)
2034bdd1243dSDimitry Andric           .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
2035bdd1243dSDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
2036*06c3fb27SDimitry Andric                 ErrnoMustNotBeChecked, GenericSuccessMsg)
2037*06c3fb27SDimitry Andric           .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2038e8d8bef9SDimitry Andric           .ArgConstraint(NotNull(ArgNo(3)))
2039e8d8bef9SDimitry Andric           .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2040e8d8bef9SDimitry Andric                                     /*BufSizeMultiplier=*/ArgNo(2)));
20415ffd83dbSDimitry Andric 
2042e8d8bef9SDimitry Andric   // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2043e8d8bef9SDimitry Andric   //              FILE *restrict stream);
2044e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2045e8d8bef9SDimitry Andric       "fread",
2046e8d8bef9SDimitry Andric       Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
2047e8d8bef9SDimitry Andric                 RetType{SizeTy}),
2048e8d8bef9SDimitry Andric       FreadSummary);
2049e8d8bef9SDimitry Andric   // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2050e8d8bef9SDimitry Andric   //               FILE *restrict stream);
2051e8d8bef9SDimitry Andric   addToFunctionSummaryMap("fwrite",
2052e8d8bef9SDimitry Andric                           Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
2053e8d8bef9SDimitry Andric                                              SizeTy, FilePtrRestrictTy},
2054e8d8bef9SDimitry Andric                                     RetType{SizeTy}),
2055e8d8bef9SDimitry Andric                           FreadSummary);
2056e8d8bef9SDimitry Andric 
2057bdd1243dSDimitry Andric   std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
2058bdd1243dSDimitry Andric   std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
2059e8d8bef9SDimitry Andric 
2060e8d8bef9SDimitry Andric   auto ReadSummary =
2061e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2062e8d8bef9SDimitry Andric           .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
206381ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
206481ad6265SDimitry Andric                 ErrnoIrrelevant);
2065e8d8bef9SDimitry Andric 
20665ffd83dbSDimitry Andric   // FIXME these are actually defined by POSIX and not by the C standard, we
20675ffd83dbSDimitry Andric   // should handle them together with the rest of the POSIX functions.
2068e8d8bef9SDimitry Andric   // ssize_t read(int fildes, void *buf, size_t nbyte);
2069e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2070e8d8bef9SDimitry Andric       "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2071e8d8bef9SDimitry Andric       ReadSummary);
2072e8d8bef9SDimitry Andric   // ssize_t write(int fildes, const void *buf, size_t nbyte);
2073e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2074e8d8bef9SDimitry Andric       "write",
2075e8d8bef9SDimitry Andric       Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2076e8d8bef9SDimitry Andric       ReadSummary);
2077e8d8bef9SDimitry Andric 
2078e8d8bef9SDimitry Andric   auto GetLineSummary =
2079e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2080e8d8bef9SDimitry Andric           .Case({ReturnValueCondition(WithinRange,
208181ad6265SDimitry Andric                                       Range({-1, -1}, {1, Ssize_tMax}))},
208281ad6265SDimitry Andric                 ErrnoIrrelevant);
2083e8d8bef9SDimitry Andric 
2084e8d8bef9SDimitry Andric   QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
20850b57cec5SDimitry Andric 
20860b57cec5SDimitry Andric   // getline()-like functions either fail or read at least the delimiter.
20875ffd83dbSDimitry Andric   // FIXME these are actually defined by POSIX and not by the C standard, we
20885ffd83dbSDimitry Andric   // should handle them together with the rest of the POSIX functions.
2089e8d8bef9SDimitry Andric   // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2090e8d8bef9SDimitry Andric   //                 FILE *restrict stream);
2091e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2092e8d8bef9SDimitry Andric       "getline",
2093e8d8bef9SDimitry Andric       Signature(
2094e8d8bef9SDimitry Andric           ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
2095e8d8bef9SDimitry Andric           RetType{Ssize_tTy}),
2096e8d8bef9SDimitry Andric       GetLineSummary);
2097e8d8bef9SDimitry Andric   // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2098e8d8bef9SDimitry Andric   //                  int delimiter, FILE *restrict stream);
2099e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2100e8d8bef9SDimitry Andric       "getdelim",
2101e8d8bef9SDimitry Andric       Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2102e8d8bef9SDimitry Andric                          FilePtrRestrictTy},
2103e8d8bef9SDimitry Andric                 RetType{Ssize_tTy}),
2104e8d8bef9SDimitry Andric       GetLineSummary);
21055ffd83dbSDimitry Andric 
2106349cc55cSDimitry Andric   {
210781ad6265SDimitry Andric     Summary GetenvSummary =
210881ad6265SDimitry Andric         Summary(NoEvalCall)
2109349cc55cSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
211081ad6265SDimitry Andric             .Case({NotNull(Ret)}, ErrnoIrrelevant,
211181ad6265SDimitry Andric                   "Assuming the environment variable exists");
2112349cc55cSDimitry Andric     // In untrusted environments the envvar might not exist.
2113349cc55cSDimitry Andric     if (!ShouldAssumeControlledEnvironment)
211481ad6265SDimitry Andric       GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
211581ad6265SDimitry Andric                          "Assuming the environment variable does not exist");
2116349cc55cSDimitry Andric 
2117349cc55cSDimitry Andric     // char *getenv(const char *name);
2118349cc55cSDimitry Andric     addToFunctionSummaryMap(
2119349cc55cSDimitry Andric         "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2120349cc55cSDimitry Andric         std::move(GetenvSummary));
2121349cc55cSDimitry Andric   }
2122349cc55cSDimitry Andric 
21235ffd83dbSDimitry Andric   if (ModelPOSIX) {
2124bdd1243dSDimitry Andric     const auto ReturnsZeroOrMinusOne =
2125bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
2126bdd1243dSDimitry Andric     const auto ReturnsZero =
2127bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2128bdd1243dSDimitry Andric     const auto ReturnsMinusOne =
2129bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
2130bdd1243dSDimitry Andric     const auto ReturnsNonnegative =
2131bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2132bdd1243dSDimitry Andric     const auto ReturnsNonZero =
2133bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2134bdd1243dSDimitry Andric     const auto ReturnsFileDescriptor =
2135bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
2136bdd1243dSDimitry Andric     const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2137bdd1243dSDimitry Andric 
2138*06c3fb27SDimitry Andric     auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
2139*06c3fb27SDimitry Andric       return std::make_shared<RangeConstraint>(
2140*06c3fb27SDimitry Andric           ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
2141*06c3fb27SDimitry Andric           "a valid file descriptor or AT_FDCWD");
2142*06c3fb27SDimitry Andric     };
2143*06c3fb27SDimitry Andric 
2144bdd1243dSDimitry Andric     // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2145bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2146bdd1243dSDimitry Andric         "fopen",
2147bdd1243dSDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2148bdd1243dSDimitry Andric                   RetType{FilePtrTy}),
2149bdd1243dSDimitry Andric         Summary(NoEvalCall)
2150*06c3fb27SDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2151*06c3fb27SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2152bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2153bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2154bdd1243dSDimitry Andric 
2155bdd1243dSDimitry Andric     // FILE *tmpfile(void);
2156*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2157*06c3fb27SDimitry Andric         "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2158bdd1243dSDimitry Andric         Summary(NoEvalCall)
2159*06c3fb27SDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2160*06c3fb27SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2161bdd1243dSDimitry Andric 
2162bdd1243dSDimitry Andric     // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2163bdd1243dSDimitry Andric     //               FILE *restrict stream);
2164bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2165bdd1243dSDimitry Andric         "freopen",
2166bdd1243dSDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2167bdd1243dSDimitry Andric                            FilePtrRestrictTy},
2168bdd1243dSDimitry Andric                   RetType{FilePtrTy}),
2169bdd1243dSDimitry Andric         Summary(NoEvalCall)
2170bdd1243dSDimitry Andric             .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
2171*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2172*06c3fb27SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2173bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
2174bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
2175bdd1243dSDimitry Andric 
2176bdd1243dSDimitry Andric     // int fclose(FILE *stream);
2177bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2178bdd1243dSDimitry Andric         "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2179bdd1243dSDimitry Andric         Summary(NoEvalCall)
2180*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2181bdd1243dSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2182*06c3fb27SDimitry Andric                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2183bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2184bdd1243dSDimitry Andric 
2185bdd1243dSDimitry Andric     // int fseek(FILE *stream, long offset, int whence);
2186bdd1243dSDimitry Andric     // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2187bdd1243dSDimitry Andric     // these for condition of arg 2.
2188bdd1243dSDimitry Andric     // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2189bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2190bdd1243dSDimitry Andric         "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2191bdd1243dSDimitry Andric         Summary(NoEvalCall)
2192*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2193*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2194bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2195bdd1243dSDimitry Andric             .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2196bdd1243dSDimitry Andric 
2197bdd1243dSDimitry Andric     // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2198bdd1243dSDimitry Andric     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2199bdd1243dSDimitry Andric     // "The fgetpos() function shall not change the setting of errno if
2200bdd1243dSDimitry Andric     // successful."
2201bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2202bdd1243dSDimitry Andric         "fgetpos",
2203bdd1243dSDimitry Andric         Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2204bdd1243dSDimitry Andric                   RetType{IntTy}),
2205bdd1243dSDimitry Andric         Summary(NoEvalCall)
2206*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2207*06c3fb27SDimitry Andric             .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2208bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2209bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2210bdd1243dSDimitry Andric 
2211bdd1243dSDimitry Andric     // int fsetpos(FILE *stream, const fpos_t *pos);
2212bdd1243dSDimitry Andric     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2213bdd1243dSDimitry Andric     // "The fsetpos() function shall not change the setting of errno if
2214bdd1243dSDimitry Andric     // successful."
2215bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2216bdd1243dSDimitry Andric         "fsetpos",
2217bdd1243dSDimitry Andric         Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2218bdd1243dSDimitry Andric         Summary(NoEvalCall)
2219*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2220*06c3fb27SDimitry Andric             .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2221bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2222bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2223bdd1243dSDimitry Andric 
2224bdd1243dSDimitry Andric     // long ftell(FILE *stream);
2225bdd1243dSDimitry Andric     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2226bdd1243dSDimitry Andric     // "The ftell() function shall not change the setting of errno if
2227bdd1243dSDimitry Andric     // successful."
2228bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2229bdd1243dSDimitry Andric         "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2230bdd1243dSDimitry Andric         Summary(NoEvalCall)
2231bdd1243dSDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(1, LongMax))},
2232*06c3fb27SDimitry Andric                   ErrnoUnchanged, GenericSuccessMsg)
2233*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2234bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2235bdd1243dSDimitry Andric 
2236bdd1243dSDimitry Andric     // int fileno(FILE *stream);
2237bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2238bdd1243dSDimitry Andric         "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2239bdd1243dSDimitry Andric         Summary(NoEvalCall)
2240*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2241*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2242*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2243bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2244bdd1243dSDimitry Andric 
2245bdd1243dSDimitry Andric     // void rewind(FILE *stream);
2246bdd1243dSDimitry Andric     // This function indicates error only by setting of 'errno'.
2247bdd1243dSDimitry Andric     addToFunctionSummaryMap("rewind",
2248bdd1243dSDimitry Andric                             Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2249bdd1243dSDimitry Andric                             Summary(NoEvalCall)
2250bdd1243dSDimitry Andric                                 .Case({}, ErrnoMustBeChecked)
2251bdd1243dSDimitry Andric                                 .ArgConstraint(NotNull(ArgNo(0))));
2252bdd1243dSDimitry Andric 
2253bdd1243dSDimitry Andric     // void clearerr(FILE *stream);
2254bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2255bdd1243dSDimitry Andric         "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2256bdd1243dSDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2257bdd1243dSDimitry Andric 
2258bdd1243dSDimitry Andric     // int feof(FILE *stream);
2259bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2260bdd1243dSDimitry Andric         "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2261bdd1243dSDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2262bdd1243dSDimitry Andric 
2263bdd1243dSDimitry Andric     // int ferror(FILE *stream);
2264bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2265bdd1243dSDimitry Andric         "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2266bdd1243dSDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
22675ffd83dbSDimitry Andric 
22685ffd83dbSDimitry Andric     // long a64l(const char *str64);
22695ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2270e8d8bef9SDimitry Andric         "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2271e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
22725ffd83dbSDimitry Andric 
22735ffd83dbSDimitry Andric     // char *l64a(long value);
2274e8d8bef9SDimitry Andric     addToFunctionSummaryMap("l64a",
2275e8d8bef9SDimitry Andric                             Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2276e8d8bef9SDimitry Andric                             Summary(NoEvalCall)
2277e8d8bef9SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
2278e8d8bef9SDimitry Andric                                     0, WithinRange, Range(0, LongMax))));
2279e8d8bef9SDimitry Andric 
2280*06c3fb27SDimitry Andric     // int open(const char *path, int oflag, ...);
2281*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2282*06c3fb27SDimitry Andric         "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2283*06c3fb27SDimitry Andric         Summary(NoEvalCall)
2284*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2285*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2286*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2287*06c3fb27SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2288*06c3fb27SDimitry Andric 
2289*06c3fb27SDimitry Andric     // int openat(int fd, const char *path, int oflag, ...);
2290*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2291*06c3fb27SDimitry Andric         "openat",
2292*06c3fb27SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2293*06c3fb27SDimitry Andric         Summary(NoEvalCall)
2294*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2295*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2296*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2297*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2298*06c3fb27SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2299*06c3fb27SDimitry Andric 
23005ffd83dbSDimitry Andric     // int access(const char *pathname, int amode);
2301e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2302e8d8bef9SDimitry Andric         "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2303e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2304*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2305*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23065ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
23075ffd83dbSDimitry Andric 
23085ffd83dbSDimitry Andric     // int faccessat(int dirfd, const char *pathname, int mode, int flags);
23095ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2310e8d8bef9SDimitry Andric         "faccessat",
2311e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2312e8d8bef9SDimitry Andric                   RetType{IntTy}),
2313e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2314*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2315*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2316*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
23175ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
23185ffd83dbSDimitry Andric 
23195ffd83dbSDimitry Andric     // int dup(int fildes);
232081ad6265SDimitry Andric     addToFunctionSummaryMap(
232181ad6265SDimitry Andric         "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2322e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2323*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2324*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2325*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
232681ad6265SDimitry Andric             .ArgConstraint(
232781ad6265SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
23285ffd83dbSDimitry Andric 
23295ffd83dbSDimitry Andric     // int dup2(int fildes1, int filedes2);
23305ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2331e8d8bef9SDimitry Andric         "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2332e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2333*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2334*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2335*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23365ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
23375ffd83dbSDimitry Andric             .ArgConstraint(
23385ffd83dbSDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
23395ffd83dbSDimitry Andric 
23405ffd83dbSDimitry Andric     // int fdatasync(int fildes);
2341*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2342*06c3fb27SDimitry Andric         "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2343e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2344*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2345*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2346*06c3fb27SDimitry Andric             .ArgConstraint(
2347*06c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
23485ffd83dbSDimitry Andric 
23495ffd83dbSDimitry Andric     // int fnmatch(const char *pattern, const char *string, int flags);
23505ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2351e8d8bef9SDimitry Andric         "fnmatch",
2352e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2353e8d8bef9SDimitry Andric                   RetType{IntTy}),
235481ad6265SDimitry Andric         Summary(NoEvalCall)
23555ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
23565ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
23575ffd83dbSDimitry Andric 
23585ffd83dbSDimitry Andric     // int fsync(int fildes);
2359*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2360*06c3fb27SDimitry Andric         "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2361e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2362*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2363*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2364*06c3fb27SDimitry Andric             .ArgConstraint(
2365*06c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
23665ffd83dbSDimitry Andric 
2367bdd1243dSDimitry Andric     std::optional<QualType> Off_tTy = lookupTy("off_t");
23685ffd83dbSDimitry Andric 
23695ffd83dbSDimitry Andric     // int truncate(const char *path, off_t length);
2370e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2371e8d8bef9SDimitry Andric         "truncate",
2372e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2373e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2374*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2375*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23765ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
23775ffd83dbSDimitry Andric 
23785ffd83dbSDimitry Andric     // int symlink(const char *oldpath, const char *newpath);
2379e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2380e8d8bef9SDimitry Andric         "symlink",
2381e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2382e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2383*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2384*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23855ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
23865ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
23875ffd83dbSDimitry Andric 
23885ffd83dbSDimitry Andric     // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
23895ffd83dbSDimitry Andric     addToFunctionSummaryMap(
23905ffd83dbSDimitry Andric         "symlinkat",
2391e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2392e8d8bef9SDimitry Andric                   RetType{IntTy}),
2393e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2394*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2395*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23965ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2397*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
23985ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
23995ffd83dbSDimitry Andric 
24005ffd83dbSDimitry Andric     // int lockf(int fd, int cmd, off_t len);
24015ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2402e8d8bef9SDimitry Andric         "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2403e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2404*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2405*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24065ffd83dbSDimitry Andric             .ArgConstraint(
24075ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
24085ffd83dbSDimitry Andric 
2409bdd1243dSDimitry Andric     std::optional<QualType> Mode_tTy = lookupTy("mode_t");
24105ffd83dbSDimitry Andric 
24115ffd83dbSDimitry Andric     // int creat(const char *pathname, mode_t mode);
2412e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2413e8d8bef9SDimitry Andric         "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2414e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2415*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2416*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2417*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24185ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
24195ffd83dbSDimitry Andric 
24205ffd83dbSDimitry Andric     // unsigned int sleep(unsigned int seconds);
24215ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2422e8d8bef9SDimitry Andric         "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2423e8d8bef9SDimitry Andric         Summary(NoEvalCall)
24245ffd83dbSDimitry Andric             .ArgConstraint(
24255ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
24265ffd83dbSDimitry Andric 
2427bdd1243dSDimitry Andric     std::optional<QualType> DirTy = lookupTy("DIR");
2428bdd1243dSDimitry Andric     std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
24295ffd83dbSDimitry Andric 
24305ffd83dbSDimitry Andric     // int dirfd(DIR *dirp);
243181ad6265SDimitry Andric     addToFunctionSummaryMap(
243281ad6265SDimitry Andric         "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2433e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2434*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2435*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2436*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24375ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
24385ffd83dbSDimitry Andric 
24395ffd83dbSDimitry Andric     // unsigned int alarm(unsigned int seconds);
24405ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2441e8d8bef9SDimitry Andric         "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2442e8d8bef9SDimitry Andric         Summary(NoEvalCall)
24435ffd83dbSDimitry Andric             .ArgConstraint(
24445ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
24455ffd83dbSDimitry Andric 
24465ffd83dbSDimitry Andric     // int closedir(DIR *dir);
2447*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2448*06c3fb27SDimitry Andric         "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2449e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2450*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2451*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24525ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
24535ffd83dbSDimitry Andric 
24545ffd83dbSDimitry Andric     // char *strdup(const char *s);
2455e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2456e8d8bef9SDimitry Andric         "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2457e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
24585ffd83dbSDimitry Andric 
24595ffd83dbSDimitry Andric     // char *strndup(const char *s, size_t n);
24605ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2461e8d8bef9SDimitry Andric         "strndup",
2462e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
2463e8d8bef9SDimitry Andric         Summary(NoEvalCall)
24645ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2465e8d8bef9SDimitry Andric             .ArgConstraint(
2466e8d8bef9SDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
24675ffd83dbSDimitry Andric 
24685ffd83dbSDimitry Andric     // wchar_t *wcsdup(const wchar_t *s);
2469e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2470e8d8bef9SDimitry Andric         "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2471e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
24725ffd83dbSDimitry Andric 
24735ffd83dbSDimitry Andric     // int mkstemp(char *template);
247481ad6265SDimitry Andric     addToFunctionSummaryMap(
247581ad6265SDimitry Andric         "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2476e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2477*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2478*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2479*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24805ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
24815ffd83dbSDimitry Andric 
24825ffd83dbSDimitry Andric     // char *mkdtemp(char *template);
248381ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
24845ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2485e8d8bef9SDimitry Andric         "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
2486e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
24875ffd83dbSDimitry Andric 
24885ffd83dbSDimitry Andric     // char *getcwd(char *buf, size_t size);
248981ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
24905ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2491e8d8bef9SDimitry Andric         "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
2492e8d8bef9SDimitry Andric         Summary(NoEvalCall)
24935ffd83dbSDimitry Andric             .ArgConstraint(
24945ffd83dbSDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
24955ffd83dbSDimitry Andric 
24965ffd83dbSDimitry Andric     // int mkdir(const char *pathname, mode_t mode);
2497e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2498e8d8bef9SDimitry Andric         "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2499e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2500*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2501*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25025ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
25035ffd83dbSDimitry Andric 
25045ffd83dbSDimitry Andric     // int mkdirat(int dirfd, const char *pathname, mode_t mode);
25055ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2506e8d8bef9SDimitry Andric         "mkdirat",
2507e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2508e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2509*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2510*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2511*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
25125ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
25135ffd83dbSDimitry Andric 
2514bdd1243dSDimitry Andric     std::optional<QualType> Dev_tTy = lookupTy("dev_t");
25155ffd83dbSDimitry Andric 
25165ffd83dbSDimitry Andric     // int mknod(const char *pathname, mode_t mode, dev_t dev);
25175ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2518e8d8bef9SDimitry Andric         "mknod",
2519e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2520e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2521*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2522*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25235ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
25245ffd83dbSDimitry Andric 
25255ffd83dbSDimitry Andric     // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2526e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2527e8d8bef9SDimitry Andric         "mknodat",
2528e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2529e8d8bef9SDimitry Andric                   RetType{IntTy}),
2530e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2531*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2532*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2533*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
25345ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
25355ffd83dbSDimitry Andric 
25365ffd83dbSDimitry Andric     // int chmod(const char *path, mode_t mode);
2537e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2538e8d8bef9SDimitry Andric         "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2539e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2540*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2541*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25425ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
25435ffd83dbSDimitry Andric 
25445ffd83dbSDimitry Andric     // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
25455ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2546e8d8bef9SDimitry Andric         "fchmodat",
2547e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2548e8d8bef9SDimitry Andric                   RetType{IntTy}),
2549e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2550*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2551*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2552*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
25535ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
25545ffd83dbSDimitry Andric 
25555ffd83dbSDimitry Andric     // int fchmod(int fildes, mode_t mode);
25565ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2557e8d8bef9SDimitry Andric         "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2558e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2559*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2560*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25615ffd83dbSDimitry Andric             .ArgConstraint(
25625ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
25635ffd83dbSDimitry Andric 
2564bdd1243dSDimitry Andric     std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2565bdd1243dSDimitry Andric     std::optional<QualType> Gid_tTy = lookupTy("gid_t");
25665ffd83dbSDimitry Andric 
25675ffd83dbSDimitry Andric     // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
25685ffd83dbSDimitry Andric     //              int flags);
25695ffd83dbSDimitry Andric     addToFunctionSummaryMap(
25705ffd83dbSDimitry Andric         "fchownat",
2571e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2572e8d8bef9SDimitry Andric                   RetType{IntTy}),
2573e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2574*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2575*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2576*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
25775ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
25785ffd83dbSDimitry Andric 
25795ffd83dbSDimitry Andric     // int chown(const char *path, uid_t owner, gid_t group);
25805ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2581e8d8bef9SDimitry Andric         "chown",
2582e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2583e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2584*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2585*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25865ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
25875ffd83dbSDimitry Andric 
25885ffd83dbSDimitry Andric     // int lchown(const char *path, uid_t owner, gid_t group);
25895ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2590e8d8bef9SDimitry Andric         "lchown",
2591e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2592e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2593*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2594*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25955ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
25965ffd83dbSDimitry Andric 
25975ffd83dbSDimitry Andric     // int fchown(int fildes, uid_t owner, gid_t group);
25985ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2599e8d8bef9SDimitry Andric         "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2600e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2601*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2602*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2603e8d8bef9SDimitry Andric             .ArgConstraint(
2604e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
26055ffd83dbSDimitry Andric 
26065ffd83dbSDimitry Andric     // int rmdir(const char *pathname);
2607*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2608*06c3fb27SDimitry Andric         "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2609e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2610*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2611*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26125ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
26135ffd83dbSDimitry Andric 
26145ffd83dbSDimitry Andric     // int chdir(const char *path);
2615*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2616*06c3fb27SDimitry Andric         "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2617e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2618*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2619*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26205ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
26215ffd83dbSDimitry Andric 
26225ffd83dbSDimitry Andric     // int link(const char *oldpath, const char *newpath);
2623e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2624e8d8bef9SDimitry Andric         "link",
2625e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2626e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2627*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2628*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26295ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
26305ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
26315ffd83dbSDimitry Andric 
26325ffd83dbSDimitry Andric     // int linkat(int fd1, const char *path1, int fd2, const char *path2,
26335ffd83dbSDimitry Andric     //            int flag);
26345ffd83dbSDimitry Andric     addToFunctionSummaryMap(
26355ffd83dbSDimitry Andric         "linkat",
2636e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2637e8d8bef9SDimitry Andric                   RetType{IntTy}),
2638e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2639*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2640*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2641*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
26425ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
2643*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
26445ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(3))));
26455ffd83dbSDimitry Andric 
26465ffd83dbSDimitry Andric     // int unlink(const char *pathname);
2647*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2648*06c3fb27SDimitry Andric         "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2649e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2650*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2651*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26525ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
26535ffd83dbSDimitry Andric 
26545ffd83dbSDimitry Andric     // int unlinkat(int fd, const char *path, int flag);
26555ffd83dbSDimitry Andric     addToFunctionSummaryMap(
26565ffd83dbSDimitry Andric         "unlinkat",
2657e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2658e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2659*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2660*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2661*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
26625ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
26635ffd83dbSDimitry Andric 
2664bdd1243dSDimitry Andric     std::optional<QualType> StructStatTy = lookupTy("stat");
2665bdd1243dSDimitry Andric     std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2666bdd1243dSDimitry Andric     std::optional<QualType> StructStatPtrRestrictTy =
2667bdd1243dSDimitry Andric         getRestrictTy(StructStatPtrTy);
26685ffd83dbSDimitry Andric 
26695ffd83dbSDimitry Andric     // int fstat(int fd, struct stat *statbuf);
26705ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2671e8d8bef9SDimitry Andric         "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2672e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2673*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2674*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2675e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
26765ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
26775ffd83dbSDimitry Andric 
26785ffd83dbSDimitry Andric     // int stat(const char *restrict path, struct stat *restrict buf);
26795ffd83dbSDimitry Andric     addToFunctionSummaryMap(
26805ffd83dbSDimitry Andric         "stat",
2681e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2682e8d8bef9SDimitry Andric                   RetType{IntTy}),
2683e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2684*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2685*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26865ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
26875ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
26885ffd83dbSDimitry Andric 
26895ffd83dbSDimitry Andric     // int lstat(const char *restrict path, struct stat *restrict buf);
26905ffd83dbSDimitry Andric     addToFunctionSummaryMap(
26915ffd83dbSDimitry Andric         "lstat",
2692e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2693e8d8bef9SDimitry Andric                   RetType{IntTy}),
2694e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2695*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2696*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26975ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
26985ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
26995ffd83dbSDimitry Andric 
27005ffd83dbSDimitry Andric     // int fstatat(int fd, const char *restrict path,
27015ffd83dbSDimitry Andric     //             struct stat *restrict buf, int flag);
27025ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2703e8d8bef9SDimitry Andric         "fstatat",
2704e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2705e8d8bef9SDimitry Andric                            StructStatPtrRestrictTy, IntTy},
2706e8d8bef9SDimitry Andric                   RetType{IntTy}),
2707e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2708*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2709*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2710*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
27115ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
27125ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
27135ffd83dbSDimitry Andric 
27145ffd83dbSDimitry Andric     // DIR *opendir(const char *name);
271581ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
2716e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2717e8d8bef9SDimitry Andric         "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
2718e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
27195ffd83dbSDimitry Andric 
27205ffd83dbSDimitry Andric     // DIR *fdopendir(int fd);
272181ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
2722e8d8bef9SDimitry Andric     addToFunctionSummaryMap("fdopendir",
2723e8d8bef9SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2724e8d8bef9SDimitry Andric                             Summary(NoEvalCall)
2725e8d8bef9SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
2726e8d8bef9SDimitry Andric                                     0, WithinRange, Range(0, IntMax))));
27275ffd83dbSDimitry Andric 
27285ffd83dbSDimitry Andric     // int isatty(int fildes);
27295ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2730e8d8bef9SDimitry Andric         "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2731e8d8bef9SDimitry Andric         Summary(NoEvalCall)
273281ad6265SDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
273381ad6265SDimitry Andric                   ErrnoIrrelevant)
27345ffd83dbSDimitry Andric             .ArgConstraint(
27355ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
27365ffd83dbSDimitry Andric 
27375ffd83dbSDimitry Andric     // FILE *popen(const char *command, const char *type);
273881ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
2739e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2740e8d8bef9SDimitry Andric         "popen",
2741e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2742e8d8bef9SDimitry Andric         Summary(NoEvalCall)
27435ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
27445ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
27455ffd83dbSDimitry Andric 
27465ffd83dbSDimitry Andric     // int pclose(FILE *stream);
274781ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
27485ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2749e8d8bef9SDimitry Andric         "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2750e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
27515ffd83dbSDimitry Andric 
27525ffd83dbSDimitry Andric     // int close(int fildes);
2753*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2754*06c3fb27SDimitry Andric         "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2755e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2756*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2757*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2758*06c3fb27SDimitry Andric             .ArgConstraint(
2759*06c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(-1, IntMax))));
27605ffd83dbSDimitry Andric 
27615ffd83dbSDimitry Andric     // long fpathconf(int fildes, int name);
2762e8d8bef9SDimitry Andric     addToFunctionSummaryMap("fpathconf",
2763e8d8bef9SDimitry Andric                             Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2764e8d8bef9SDimitry Andric                             Summary(NoEvalCall)
2765e8d8bef9SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
2766e8d8bef9SDimitry Andric                                     0, WithinRange, Range(0, IntMax))));
27675ffd83dbSDimitry Andric 
27685ffd83dbSDimitry Andric     // long pathconf(const char *path, int name);
2769e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2770e8d8bef9SDimitry Andric         "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2771e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
27725ffd83dbSDimitry Andric 
27735ffd83dbSDimitry Andric     // FILE *fdopen(int fd, const char *mode);
277481ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
27755ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2776e8d8bef9SDimitry Andric         "fdopen",
2777e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2778e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2779e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
27805ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
27815ffd83dbSDimitry Andric 
27825ffd83dbSDimitry Andric     // void rewinddir(DIR *dir);
27835ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2784e8d8bef9SDimitry Andric         "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2785e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
27865ffd83dbSDimitry Andric 
27875ffd83dbSDimitry Andric     // void seekdir(DIR *dirp, long loc);
2788e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2789e8d8bef9SDimitry Andric         "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2790e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
27915ffd83dbSDimitry Andric 
27925ffd83dbSDimitry Andric     // int rand_r(unsigned int *seedp);
27935ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2794e8d8bef9SDimitry Andric         "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2795e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
27965ffd83dbSDimitry Andric 
27975ffd83dbSDimitry Andric     // int fseeko(FILE *stream, off_t offset, int whence);
2798e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2799e8d8bef9SDimitry Andric         "fseeko",
2800e8d8bef9SDimitry Andric         Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2801e8d8bef9SDimitry Andric         Summary(NoEvalCall)
280281ad6265SDimitry Andric             .Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant)
28035ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
28045ffd83dbSDimitry Andric 
28055ffd83dbSDimitry Andric     // off_t ftello(FILE *stream);
28065ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2807e8d8bef9SDimitry Andric         "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2808e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
28095ffd83dbSDimitry Andric 
28105ffd83dbSDimitry Andric     // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
28115ffd83dbSDimitry Andric     // off_t offset);
281281ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
28135ffd83dbSDimitry Andric     addToFunctionSummaryMap(
28145ffd83dbSDimitry Andric         "mmap",
2815e8d8bef9SDimitry Andric         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
2816e8d8bef9SDimitry Andric                   RetType{VoidPtrTy}),
2817e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2818e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
28195ffd83dbSDimitry Andric             .ArgConstraint(
2820e8d8bef9SDimitry Andric                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
28215ffd83dbSDimitry Andric 
2822bdd1243dSDimitry Andric     std::optional<QualType> Off64_tTy = lookupTy("off64_t");
28235ffd83dbSDimitry Andric     // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
28245ffd83dbSDimitry Andric     // off64_t offset);
282581ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
28265ffd83dbSDimitry Andric     addToFunctionSummaryMap(
28275ffd83dbSDimitry Andric         "mmap64",
2828e8d8bef9SDimitry Andric         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
2829e8d8bef9SDimitry Andric                   RetType{VoidPtrTy}),
2830e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2831e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
28325ffd83dbSDimitry Andric             .ArgConstraint(
2833e8d8bef9SDimitry Andric                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
28345ffd83dbSDimitry Andric 
28355ffd83dbSDimitry Andric     // int pipe(int fildes[2]);
2836*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2837*06c3fb27SDimitry Andric         "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2838e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2839*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2840*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28415ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
28425ffd83dbSDimitry Andric 
28435ffd83dbSDimitry Andric     // off_t lseek(int fildes, off_t offset, int whence);
284481ad6265SDimitry Andric     // In the first case we can not tell for sure if it failed or not.
284581ad6265SDimitry Andric     // A return value different from of the expected offset (that is unknown
284681ad6265SDimitry Andric     // here) may indicate failure. For this reason we do not enforce the errno
284781ad6265SDimitry Andric     // check (can cause false positive).
28485ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2849e8d8bef9SDimitry Andric         "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2850e8d8bef9SDimitry Andric         Summary(NoEvalCall)
285181ad6265SDimitry Andric             .Case(ReturnsNonnegative, ErrnoIrrelevant)
2852*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2853e8d8bef9SDimitry Andric             .ArgConstraint(
2854e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
28555ffd83dbSDimitry Andric 
28565ffd83dbSDimitry Andric     // ssize_t readlink(const char *restrict path, char *restrict buf,
28575ffd83dbSDimitry Andric     //                  size_t bufsize);
28585ffd83dbSDimitry Andric     addToFunctionSummaryMap(
28595ffd83dbSDimitry Andric         "readlink",
2860e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2861e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
2862e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2863e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
286481ad6265SDimitry Andric                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2865*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2866*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28675ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
28685ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
28695ffd83dbSDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
28705ffd83dbSDimitry Andric                                       /*BufSize=*/ArgNo(2)))
28715ffd83dbSDimitry Andric             .ArgConstraint(
28725ffd83dbSDimitry Andric                 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
28735ffd83dbSDimitry Andric 
28745ffd83dbSDimitry Andric     // ssize_t readlinkat(int fd, const char *restrict path,
28755ffd83dbSDimitry Andric     //                    char *restrict buf, size_t bufsize);
28765ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2877e8d8bef9SDimitry Andric         "readlinkat",
2878e8d8bef9SDimitry Andric         Signature(
2879e8d8bef9SDimitry Andric             ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2880e8d8bef9SDimitry Andric             RetType{Ssize_tTy}),
2881e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2882e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)),
288381ad6265SDimitry Andric                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2884*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2885*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2886*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
28875ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
28885ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2)))
28895ffd83dbSDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
28905ffd83dbSDimitry Andric                                       /*BufSize=*/ArgNo(3)))
2891e8d8bef9SDimitry Andric             .ArgConstraint(
2892e8d8bef9SDimitry Andric                 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
28935ffd83dbSDimitry Andric 
28945ffd83dbSDimitry Andric     // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
28955ffd83dbSDimitry Andric     // *newpath);
2896e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2897e8d8bef9SDimitry Andric         "renameat",
2898e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
2899e8d8bef9SDimitry Andric                   RetType{IntTy}),
2900e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2901*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2902*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2903*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
29045ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
2905*06c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
29065ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(3))));
29075ffd83dbSDimitry Andric 
29085ffd83dbSDimitry Andric     // char *realpath(const char *restrict file_name,
29095ffd83dbSDimitry Andric     //                char *restrict resolved_name);
291081ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
29115ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2912e8d8bef9SDimitry Andric         "realpath",
2913e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
2914e8d8bef9SDimitry Andric                   RetType{CharPtrTy}),
2915e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
29165ffd83dbSDimitry Andric 
2917e8d8bef9SDimitry Andric     QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
29185ffd83dbSDimitry Andric 
29195ffd83dbSDimitry Andric     // int execv(const char *path, char *const argv[]);
2920e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2921e8d8bef9SDimitry Andric         "execv",
2922e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2923e8d8bef9SDimitry Andric         Summary(NoEvalCall)
292481ad6265SDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
292581ad6265SDimitry Andric                   ErrnoIrrelevant)
29265ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
29275ffd83dbSDimitry Andric 
29285ffd83dbSDimitry Andric     // int execvp(const char *file, char *const argv[]);
2929e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2930e8d8bef9SDimitry Andric         "execvp",
2931e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2932e8d8bef9SDimitry Andric         Summary(NoEvalCall)
293381ad6265SDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
293481ad6265SDimitry Andric                   ErrnoIrrelevant)
29355ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
29365ffd83dbSDimitry Andric 
29375ffd83dbSDimitry Andric     // int getopt(int argc, char * const argv[], const char *optstring);
29385ffd83dbSDimitry Andric     addToFunctionSummaryMap(
29395ffd83dbSDimitry Andric         "getopt",
2940e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
2941e8d8bef9SDimitry Andric                   RetType{IntTy}),
2942e8d8bef9SDimitry Andric         Summary(NoEvalCall)
294381ad6265SDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
294481ad6265SDimitry Andric                   ErrnoIrrelevant)
29455ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
29465ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
29475ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
2948e8d8bef9SDimitry Andric 
2949bdd1243dSDimitry Andric     std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
2950bdd1243dSDimitry Andric     std::optional<QualType> StructSockaddrPtrTy =
2951bdd1243dSDimitry Andric         getPointerTy(StructSockaddrTy);
2952bdd1243dSDimitry Andric     std::optional<QualType> ConstStructSockaddrPtrTy =
2953e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructSockaddrTy));
2954bdd1243dSDimitry Andric     std::optional<QualType> StructSockaddrPtrRestrictTy =
2955e8d8bef9SDimitry Andric         getRestrictTy(StructSockaddrPtrTy);
2956bdd1243dSDimitry Andric     std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
2957e8d8bef9SDimitry Andric         getRestrictTy(ConstStructSockaddrPtrTy);
2958bdd1243dSDimitry Andric     std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
2959bdd1243dSDimitry Andric     std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
2960bdd1243dSDimitry Andric     std::optional<QualType> Socklen_tPtrRestrictTy =
2961bdd1243dSDimitry Andric         getRestrictTy(Socklen_tPtrTy);
2962bdd1243dSDimitry Andric     std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
2963e8d8bef9SDimitry Andric 
2964e8d8bef9SDimitry Andric     // In 'socket.h' of some libc implementations with C99, sockaddr parameter
2965e8d8bef9SDimitry Andric     // is a transparent union of the underlying sockaddr_ family of pointers
2966e8d8bef9SDimitry Andric     // instead of being a pointer to struct sockaddr. In these cases, the
2967e8d8bef9SDimitry Andric     // standardized signature will not match, thus we try to match with another
2968e8d8bef9SDimitry Andric     // signature that has the joker Irrelevant type. We also remove those
2969e8d8bef9SDimitry Andric     // constraints which require pointer types for the sockaddr param.
2970*06c3fb27SDimitry Andric 
2971*06c3fb27SDimitry Andric     // int socket(int domain, int type, int protocol);
2972*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
2973*06c3fb27SDimitry Andric         "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),
2974*06c3fb27SDimitry Andric         Summary(NoEvalCall)
2975*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2976*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2977*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2978*06c3fb27SDimitry Andric 
2979e8d8bef9SDimitry Andric     auto Accept =
2980e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2981*06c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2982*06c3fb27SDimitry Andric                   GenericSuccessMsg)
2983*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2984e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
2985e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
2986e8d8bef9SDimitry Andric             "accept",
2987e8d8bef9SDimitry Andric             // int accept(int socket, struct sockaddr *restrict address,
2988e8d8bef9SDimitry Andric             //            socklen_t *restrict address_len);
2989e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2990e8d8bef9SDimitry Andric                                Socklen_tPtrRestrictTy},
2991e8d8bef9SDimitry Andric                       RetType{IntTy}),
2992e8d8bef9SDimitry Andric             Accept))
2993e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
2994e8d8bef9SDimitry Andric           "accept",
2995e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
2996e8d8bef9SDimitry Andric                     RetType{IntTy}),
2997e8d8bef9SDimitry Andric           Accept);
2998e8d8bef9SDimitry Andric 
2999e8d8bef9SDimitry Andric     // int bind(int socket, const struct sockaddr *address, socklen_t
3000e8d8bef9SDimitry Andric     //          address_len);
3001e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3002e8d8bef9SDimitry Andric             "bind",
3003e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3004e8d8bef9SDimitry Andric                       RetType{IntTy}),
3005e8d8bef9SDimitry Andric             Summary(NoEvalCall)
3006*06c3fb27SDimitry Andric                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3007*06c3fb27SDimitry Andric                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3008e8d8bef9SDimitry Andric                 .ArgConstraint(
3009e8d8bef9SDimitry Andric                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3010e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(1)))
3011e8d8bef9SDimitry Andric                 .ArgConstraint(
3012e8d8bef9SDimitry Andric                     BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3013e8d8bef9SDimitry Andric                 .ArgConstraint(
3014e8d8bef9SDimitry Andric                     ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
3015e8d8bef9SDimitry Andric       // Do not add constraints on sockaddr.
3016e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3017e8d8bef9SDimitry Andric           "bind",
3018e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3019e8d8bef9SDimitry Andric           Summary(NoEvalCall)
3020*06c3fb27SDimitry Andric               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3021*06c3fb27SDimitry Andric               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3022e8d8bef9SDimitry Andric               .ArgConstraint(
3023e8d8bef9SDimitry Andric                   ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3024e8d8bef9SDimitry Andric               .ArgConstraint(
3025e8d8bef9SDimitry Andric                   ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
3026e8d8bef9SDimitry Andric 
3027e8d8bef9SDimitry Andric     // int getpeername(int socket, struct sockaddr *restrict address,
3028e8d8bef9SDimitry Andric     //                 socklen_t *restrict address_len);
3029e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3030e8d8bef9SDimitry Andric             "getpeername",
3031e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3032e8d8bef9SDimitry Andric                                Socklen_tPtrRestrictTy},
3033e8d8bef9SDimitry Andric                       RetType{IntTy}),
3034e8d8bef9SDimitry Andric             Summary(NoEvalCall)
3035*06c3fb27SDimitry Andric                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3036*06c3fb27SDimitry Andric                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3037e8d8bef9SDimitry Andric                 .ArgConstraint(
3038e8d8bef9SDimitry Andric                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3039e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(1)))
3040e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(2)))))
3041e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3042e8d8bef9SDimitry Andric           "getpeername",
3043e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3044e8d8bef9SDimitry Andric                     RetType{IntTy}),
3045e8d8bef9SDimitry Andric           Summary(NoEvalCall)
3046*06c3fb27SDimitry Andric               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3047*06c3fb27SDimitry Andric               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3048e8d8bef9SDimitry Andric               .ArgConstraint(
3049e8d8bef9SDimitry Andric                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3050e8d8bef9SDimitry Andric 
3051e8d8bef9SDimitry Andric     // int getsockname(int socket, struct sockaddr *restrict address,
3052e8d8bef9SDimitry Andric     //                 socklen_t *restrict address_len);
3053e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3054e8d8bef9SDimitry Andric             "getsockname",
3055e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3056e8d8bef9SDimitry Andric                                Socklen_tPtrRestrictTy},
3057e8d8bef9SDimitry Andric                       RetType{IntTy}),
3058e8d8bef9SDimitry Andric             Summary(NoEvalCall)
3059*06c3fb27SDimitry Andric                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3060*06c3fb27SDimitry Andric                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3061e8d8bef9SDimitry Andric                 .ArgConstraint(
3062e8d8bef9SDimitry Andric                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3063e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(1)))
3064e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(2)))))
3065e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3066e8d8bef9SDimitry Andric           "getsockname",
3067e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3068e8d8bef9SDimitry Andric                     RetType{IntTy}),
3069e8d8bef9SDimitry Andric           Summary(NoEvalCall)
3070*06c3fb27SDimitry Andric               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3071*06c3fb27SDimitry Andric               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3072e8d8bef9SDimitry Andric               .ArgConstraint(
3073e8d8bef9SDimitry Andric                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3074e8d8bef9SDimitry Andric 
3075e8d8bef9SDimitry Andric     // int connect(int socket, const struct sockaddr *address, socklen_t
3076e8d8bef9SDimitry Andric     //             address_len);
3077e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3078e8d8bef9SDimitry Andric             "connect",
3079e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3080e8d8bef9SDimitry Andric                       RetType{IntTy}),
3081e8d8bef9SDimitry Andric             Summary(NoEvalCall)
3082*06c3fb27SDimitry Andric                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3083*06c3fb27SDimitry Andric                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3084e8d8bef9SDimitry Andric                 .ArgConstraint(
3085e8d8bef9SDimitry Andric                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3086e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(1)))))
3087e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3088e8d8bef9SDimitry Andric           "connect",
3089e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3090e8d8bef9SDimitry Andric           Summary(NoEvalCall)
3091*06c3fb27SDimitry Andric               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3092*06c3fb27SDimitry Andric               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3093e8d8bef9SDimitry Andric               .ArgConstraint(
3094e8d8bef9SDimitry Andric                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3095e8d8bef9SDimitry Andric 
3096e8d8bef9SDimitry Andric     auto Recvfrom =
3097e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3098e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
309981ad6265SDimitry Andric                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3100*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3101*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3102e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3103e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3104e8d8bef9SDimitry Andric                                       /*BufSize=*/ArgNo(2)));
3105e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3106e8d8bef9SDimitry Andric             "recvfrom",
3107e8d8bef9SDimitry Andric             // ssize_t recvfrom(int socket, void *restrict buffer,
3108e8d8bef9SDimitry Andric             //                  size_t length,
3109e8d8bef9SDimitry Andric             //                  int flags, struct sockaddr *restrict address,
3110e8d8bef9SDimitry Andric             //                  socklen_t *restrict address_len);
3111e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3112e8d8bef9SDimitry Andric                                StructSockaddrPtrRestrictTy,
3113e8d8bef9SDimitry Andric                                Socklen_tPtrRestrictTy},
3114e8d8bef9SDimitry Andric                       RetType{Ssize_tTy}),
3115e8d8bef9SDimitry Andric             Recvfrom))
3116e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3117e8d8bef9SDimitry Andric           "recvfrom",
3118e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3119e8d8bef9SDimitry Andric                              Irrelevant, Socklen_tPtrRestrictTy},
3120e8d8bef9SDimitry Andric                     RetType{Ssize_tTy}),
3121e8d8bef9SDimitry Andric           Recvfrom);
3122e8d8bef9SDimitry Andric 
3123e8d8bef9SDimitry Andric     auto Sendto =
3124e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3125e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
312681ad6265SDimitry Andric                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3127*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3128*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3129e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3130e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3131e8d8bef9SDimitry Andric                                       /*BufSize=*/ArgNo(2)));
3132e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3133e8d8bef9SDimitry Andric             "sendto",
3134e8d8bef9SDimitry Andric             // ssize_t sendto(int socket, const void *message, size_t length,
3135e8d8bef9SDimitry Andric             //                int flags, const struct sockaddr *dest_addr,
3136e8d8bef9SDimitry Andric             //                socklen_t dest_len);
3137e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
3138e8d8bef9SDimitry Andric                                ConstStructSockaddrPtrTy, Socklen_tTy},
3139e8d8bef9SDimitry Andric                       RetType{Ssize_tTy}),
3140e8d8bef9SDimitry Andric             Sendto))
3141e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3142e8d8bef9SDimitry Andric           "sendto",
3143e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
3144e8d8bef9SDimitry Andric                              Socklen_tTy},
3145e8d8bef9SDimitry Andric                     RetType{Ssize_tTy}),
3146e8d8bef9SDimitry Andric           Sendto);
3147e8d8bef9SDimitry Andric 
3148e8d8bef9SDimitry Andric     // int listen(int sockfd, int backlog);
3149*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3150*06c3fb27SDimitry Andric         "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3151e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3152*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3153*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3154*06c3fb27SDimitry Andric             .ArgConstraint(
3155*06c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3156e8d8bef9SDimitry Andric 
3157e8d8bef9SDimitry Andric     // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3158e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3159e8d8bef9SDimitry Andric         "recv",
3160e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
3161e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
3162e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3163e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
316481ad6265SDimitry Andric                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3165*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3166*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3167e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3168e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3169e8d8bef9SDimitry Andric                                       /*BufSize=*/ArgNo(2))));
3170e8d8bef9SDimitry Andric 
3171bdd1243dSDimitry Andric     std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3172bdd1243dSDimitry Andric     std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3173bdd1243dSDimitry Andric     std::optional<QualType> ConstStructMsghdrPtrTy =
3174e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructMsghdrTy));
3175e8d8bef9SDimitry Andric 
3176e8d8bef9SDimitry Andric     // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3177e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3178e8d8bef9SDimitry Andric         "recvmsg",
3179e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3180e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
3181e8d8bef9SDimitry Andric         Summary(NoEvalCall)
318281ad6265SDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3183*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3184*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3185e8d8bef9SDimitry Andric             .ArgConstraint(
3186e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3187e8d8bef9SDimitry Andric 
3188e8d8bef9SDimitry Andric     // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3189e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3190e8d8bef9SDimitry Andric         "sendmsg",
3191e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3192e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
3193e8d8bef9SDimitry Andric         Summary(NoEvalCall)
319481ad6265SDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3195*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3196*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3197e8d8bef9SDimitry Andric             .ArgConstraint(
3198e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3199e8d8bef9SDimitry Andric 
3200e8d8bef9SDimitry Andric     // int setsockopt(int socket, int level, int option_name,
3201e8d8bef9SDimitry Andric     //                const void *option_value, socklen_t option_len);
3202e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3203e8d8bef9SDimitry Andric         "setsockopt",
3204e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3205e8d8bef9SDimitry Andric                   RetType{IntTy}),
3206e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3207*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3208*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3209e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(3)))
3210e8d8bef9SDimitry Andric             .ArgConstraint(
3211e8d8bef9SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3212e8d8bef9SDimitry Andric             .ArgConstraint(
3213e8d8bef9SDimitry Andric                 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3214e8d8bef9SDimitry Andric 
3215e8d8bef9SDimitry Andric     // int getsockopt(int socket, int level, int option_name,
3216e8d8bef9SDimitry Andric     //                void *restrict option_value,
3217e8d8bef9SDimitry Andric     //                socklen_t *restrict option_len);
3218e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3219e8d8bef9SDimitry Andric         "getsockopt",
3220e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3221e8d8bef9SDimitry Andric                            Socklen_tPtrRestrictTy},
3222e8d8bef9SDimitry Andric                   RetType{IntTy}),
3223e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3224*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3225*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3226e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(3)))
3227e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(4))));
3228e8d8bef9SDimitry Andric 
3229e8d8bef9SDimitry Andric     // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3230e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3231e8d8bef9SDimitry Andric         "send",
3232e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
3233e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
3234e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3235e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
323681ad6265SDimitry Andric                    ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
3237*06c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
3238*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3239e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3240e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3241e8d8bef9SDimitry Andric                                       /*BufSize=*/ArgNo(2))));
3242e8d8bef9SDimitry Andric 
3243e8d8bef9SDimitry Andric     // int socketpair(int domain, int type, int protocol, int sv[2]);
3244e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3245e8d8bef9SDimitry Andric         "socketpair",
3246e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3247e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3248*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3249*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3250e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(3))));
3251e8d8bef9SDimitry Andric 
3252*06c3fb27SDimitry Andric     // int shutdown(int socket, int how);
3253*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3254*06c3fb27SDimitry Andric         "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3255*06c3fb27SDimitry Andric         Summary(NoEvalCall)
3256*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3257*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3258*06c3fb27SDimitry Andric             .ArgConstraint(
3259*06c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3260*06c3fb27SDimitry Andric 
3261e8d8bef9SDimitry Andric     // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3262e8d8bef9SDimitry Andric     //                 char *restrict node, socklen_t nodelen,
3263e8d8bef9SDimitry Andric     //                 char *restrict service,
3264e8d8bef9SDimitry Andric     //                 socklen_t servicelen, int flags);
3265e8d8bef9SDimitry Andric     //
3266e8d8bef9SDimitry Andric     // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3267e8d8bef9SDimitry Andric     // parameter is never handled as a transparent union in netdb.h
3268e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3269e8d8bef9SDimitry Andric         "getnameinfo",
3270e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3271e8d8bef9SDimitry Andric                            CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3272e8d8bef9SDimitry Andric                            Socklen_tTy, IntTy},
3273e8d8bef9SDimitry Andric                   RetType{IntTy}),
3274e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3275e8d8bef9SDimitry Andric             .ArgConstraint(
3276e8d8bef9SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3277e8d8bef9SDimitry Andric             .ArgConstraint(
3278e8d8bef9SDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3279e8d8bef9SDimitry Andric             .ArgConstraint(
3280e8d8bef9SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3281e8d8bef9SDimitry Andric             .ArgConstraint(
3282e8d8bef9SDimitry Andric                 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3283e8d8bef9SDimitry Andric             .ArgConstraint(
3284e8d8bef9SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3285e8d8bef9SDimitry Andric             .ArgConstraint(
3286e8d8bef9SDimitry Andric                 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3287e8d8bef9SDimitry Andric 
3288bdd1243dSDimitry Andric     std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3289bdd1243dSDimitry Andric     std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3290e8d8bef9SDimitry Andric 
3291e8d8bef9SDimitry Andric     // int utime(const char *filename, struct utimbuf *buf);
3292e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3293e8d8bef9SDimitry Andric         "utime",
3294e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3295e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3296*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3297*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3298e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
3299e8d8bef9SDimitry Andric 
3300bdd1243dSDimitry Andric     std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3301bdd1243dSDimitry Andric     std::optional<QualType> StructTimespecPtrTy =
3302bdd1243dSDimitry Andric         getPointerTy(StructTimespecTy);
3303bdd1243dSDimitry Andric     std::optional<QualType> ConstStructTimespecPtrTy =
3304e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructTimespecTy));
3305e8d8bef9SDimitry Andric 
3306e8d8bef9SDimitry Andric     // int futimens(int fd, const struct timespec times[2]);
3307e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3308e8d8bef9SDimitry Andric         "futimens",
3309e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3310e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3311*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3312*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3313e8d8bef9SDimitry Andric             .ArgConstraint(
3314e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3315e8d8bef9SDimitry Andric 
3316e8d8bef9SDimitry Andric     // int utimensat(int dirfd, const char *pathname,
3317e8d8bef9SDimitry Andric     //               const struct timespec times[2], int flags);
3318*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3319*06c3fb27SDimitry Andric         "utimensat",
3320*06c3fb27SDimitry Andric         Signature(
3321*06c3fb27SDimitry Andric             ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
3322e8d8bef9SDimitry Andric             RetType{IntTy}),
3323e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3324*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3325*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3326e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3327e8d8bef9SDimitry Andric 
3328bdd1243dSDimitry Andric     std::optional<QualType> StructTimevalTy = lookupTy("timeval");
3329bdd1243dSDimitry Andric     std::optional<QualType> ConstStructTimevalPtrTy =
3330e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructTimevalTy));
3331e8d8bef9SDimitry Andric 
3332e8d8bef9SDimitry Andric     // int utimes(const char *filename, const struct timeval times[2]);
3333e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3334e8d8bef9SDimitry Andric         "utimes",
3335e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3336e8d8bef9SDimitry Andric                   RetType{IntTy}),
3337e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3338*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3339*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3340e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
3341e8d8bef9SDimitry Andric 
3342e8d8bef9SDimitry Andric     // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3343e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3344e8d8bef9SDimitry Andric         "nanosleep",
3345e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3346e8d8bef9SDimitry Andric                   RetType{IntTy}),
3347e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3348*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3349*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3350e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
3351e8d8bef9SDimitry Andric 
3352bdd1243dSDimitry Andric     std::optional<QualType> Time_tTy = lookupTy("time_t");
3353bdd1243dSDimitry Andric     std::optional<QualType> ConstTime_tPtrTy =
3354bdd1243dSDimitry Andric         getPointerTy(getConstTy(Time_tTy));
3355bdd1243dSDimitry Andric     std::optional<QualType> ConstTime_tPtrRestrictTy =
3356e8d8bef9SDimitry Andric         getRestrictTy(ConstTime_tPtrTy);
3357e8d8bef9SDimitry Andric 
3358bdd1243dSDimitry Andric     std::optional<QualType> StructTmTy = lookupTy("tm");
3359bdd1243dSDimitry Andric     std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3360bdd1243dSDimitry Andric     std::optional<QualType> StructTmPtrRestrictTy =
3361bdd1243dSDimitry Andric         getRestrictTy(StructTmPtrTy);
3362bdd1243dSDimitry Andric     std::optional<QualType> ConstStructTmPtrTy =
3363e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructTmTy));
3364bdd1243dSDimitry Andric     std::optional<QualType> ConstStructTmPtrRestrictTy =
3365e8d8bef9SDimitry Andric         getRestrictTy(ConstStructTmPtrTy);
3366e8d8bef9SDimitry Andric 
3367e8d8bef9SDimitry Andric     // struct tm * localtime(const time_t *tp);
3368e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3369e8d8bef9SDimitry Andric         "localtime",
3370e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3371e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3372e8d8bef9SDimitry Andric 
3373e8d8bef9SDimitry Andric     // struct tm *localtime_r(const time_t *restrict timer,
3374e8d8bef9SDimitry Andric     //                        struct tm *restrict result);
3375e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3376e8d8bef9SDimitry Andric         "localtime_r",
3377e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3378e8d8bef9SDimitry Andric                   RetType{StructTmPtrTy}),
3379e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3380e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3381e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3382e8d8bef9SDimitry Andric 
3383e8d8bef9SDimitry Andric     // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3384e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3385e8d8bef9SDimitry Andric         "asctime_r",
3386e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3387e8d8bef9SDimitry Andric                   RetType{CharPtrTy}),
3388e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3389e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3390e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
3391e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3392e8d8bef9SDimitry Andric                                       /*MinBufSize=*/BVF.getValue(26, IntTy))));
3393e8d8bef9SDimitry Andric 
3394e8d8bef9SDimitry Andric     // char *ctime_r(const time_t *timep, char *buf);
3395e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3396e8d8bef9SDimitry Andric         "ctime_r",
3397e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3398e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3399e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3400e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
3401e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(
3402e8d8bef9SDimitry Andric                 /*Buffer=*/ArgNo(1),
3403e8d8bef9SDimitry Andric                 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3404e8d8bef9SDimitry Andric 
3405e8d8bef9SDimitry Andric     // struct tm *gmtime_r(const time_t *restrict timer,
3406e8d8bef9SDimitry Andric     //                     struct tm *restrict result);
3407e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3408e8d8bef9SDimitry Andric         "gmtime_r",
3409e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3410e8d8bef9SDimitry Andric                   RetType{StructTmPtrTy}),
3411e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3412e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3413e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3414e8d8bef9SDimitry Andric 
3415e8d8bef9SDimitry Andric     // struct tm * gmtime(const time_t *tp);
3416e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3417e8d8bef9SDimitry Andric         "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3418e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3419e8d8bef9SDimitry Andric 
3420bdd1243dSDimitry Andric     std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3421e8d8bef9SDimitry Andric 
3422e8d8bef9SDimitry Andric     // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3423e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3424e8d8bef9SDimitry Andric         "clock_gettime",
3425e8d8bef9SDimitry Andric         Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3426e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3427*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3428*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3429e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3430e8d8bef9SDimitry Andric 
3431bdd1243dSDimitry Andric     std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3432bdd1243dSDimitry Andric     std::optional<QualType> StructItimervalPtrTy =
3433bdd1243dSDimitry Andric         getPointerTy(StructItimervalTy);
3434e8d8bef9SDimitry Andric 
3435e8d8bef9SDimitry Andric     // int getitimer(int which, struct itimerval *curr_value);
3436e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3437e8d8bef9SDimitry Andric         "getitimer",
3438e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3439e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3440*06c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3441*06c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3442e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3443e8d8bef9SDimitry Andric 
3444bdd1243dSDimitry Andric     std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3445bdd1243dSDimitry Andric     std::optional<QualType> Pthread_cond_tPtrTy =
3446bdd1243dSDimitry Andric         getPointerTy(Pthread_cond_tTy);
3447bdd1243dSDimitry Andric     std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3448bdd1243dSDimitry Andric     std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3449bdd1243dSDimitry Andric     std::optional<QualType> Pthread_tPtrRestrictTy =
3450bdd1243dSDimitry Andric         getRestrictTy(Pthread_tPtrTy);
3451bdd1243dSDimitry Andric     std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3452bdd1243dSDimitry Andric     std::optional<QualType> Pthread_mutex_tPtrTy =
3453bdd1243dSDimitry Andric         getPointerTy(Pthread_mutex_tTy);
3454bdd1243dSDimitry Andric     std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3455e8d8bef9SDimitry Andric         getRestrictTy(Pthread_mutex_tPtrTy);
3456bdd1243dSDimitry Andric     std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3457bdd1243dSDimitry Andric     std::optional<QualType> Pthread_attr_tPtrTy =
3458bdd1243dSDimitry Andric         getPointerTy(Pthread_attr_tTy);
3459bdd1243dSDimitry Andric     std::optional<QualType> ConstPthread_attr_tPtrTy =
3460e8d8bef9SDimitry Andric         getPointerTy(getConstTy(Pthread_attr_tTy));
3461bdd1243dSDimitry Andric     std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3462e8d8bef9SDimitry Andric         getRestrictTy(ConstPthread_attr_tPtrTy);
3463bdd1243dSDimitry Andric     std::optional<QualType> Pthread_mutexattr_tTy =
3464bdd1243dSDimitry Andric         lookupTy("pthread_mutexattr_t");
3465bdd1243dSDimitry Andric     std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3466e8d8bef9SDimitry Andric         getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3467bdd1243dSDimitry Andric     std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3468e8d8bef9SDimitry Andric         getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3469e8d8bef9SDimitry Andric 
3470e8d8bef9SDimitry Andric     QualType PthreadStartRoutineTy = getPointerTy(
3471e8d8bef9SDimitry Andric         ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3472e8d8bef9SDimitry Andric                              FunctionProtoType::ExtProtoInfo()));
3473e8d8bef9SDimitry Andric 
3474e8d8bef9SDimitry Andric     // int pthread_cond_signal(pthread_cond_t *cond);
3475e8d8bef9SDimitry Andric     // int pthread_cond_broadcast(pthread_cond_t *cond);
3476e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3477e8d8bef9SDimitry Andric         {"pthread_cond_signal", "pthread_cond_broadcast"},
3478e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3479e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3480e8d8bef9SDimitry Andric 
3481e8d8bef9SDimitry Andric     // int pthread_create(pthread_t *restrict thread,
3482e8d8bef9SDimitry Andric     //                    const pthread_attr_t *restrict attr,
3483e8d8bef9SDimitry Andric     //                    void *(*start_routine)(void*), void *restrict arg);
3484e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3485e8d8bef9SDimitry Andric         "pthread_create",
3486e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_tPtrRestrictTy,
3487e8d8bef9SDimitry Andric                            ConstPthread_attr_tPtrRestrictTy,
3488e8d8bef9SDimitry Andric                            PthreadStartRoutineTy, VoidPtrRestrictTy},
3489e8d8bef9SDimitry Andric                   RetType{IntTy}),
3490e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3491e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3492e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
3493e8d8bef9SDimitry Andric 
3494e8d8bef9SDimitry Andric     // int pthread_attr_destroy(pthread_attr_t *attr);
3495e8d8bef9SDimitry Andric     // int pthread_attr_init(pthread_attr_t *attr);
3496e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3497e8d8bef9SDimitry Andric         {"pthread_attr_destroy", "pthread_attr_init"},
3498e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3499e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3500e8d8bef9SDimitry Andric 
3501e8d8bef9SDimitry Andric     // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3502e8d8bef9SDimitry Andric     //                               size_t *restrict stacksize);
3503e8d8bef9SDimitry Andric     // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3504e8d8bef9SDimitry Andric     //                               size_t *restrict guardsize);
3505e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3506e8d8bef9SDimitry Andric         {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3507e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3508e8d8bef9SDimitry Andric                   RetType{IntTy}),
3509e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3510e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3511e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3512e8d8bef9SDimitry Andric 
3513e8d8bef9SDimitry Andric     // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3514e8d8bef9SDimitry Andric     // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3515e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3516e8d8bef9SDimitry Andric         {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3517e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
3518e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3519e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3520e8d8bef9SDimitry Andric             .ArgConstraint(
3521e8d8bef9SDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3522e8d8bef9SDimitry Andric 
3523e8d8bef9SDimitry Andric     // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3524e8d8bef9SDimitry Andric     //                        pthread_mutexattr_t *restrict attr);
3525e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3526e8d8bef9SDimitry Andric         "pthread_mutex_init",
3527e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3528e8d8bef9SDimitry Andric                            ConstPthread_mutexattr_tPtrRestrictTy},
3529e8d8bef9SDimitry Andric                   RetType{IntTy}),
3530e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3531e8d8bef9SDimitry Andric 
3532e8d8bef9SDimitry Andric     // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3533e8d8bef9SDimitry Andric     // int pthread_mutex_lock(pthread_mutex_t *mutex);
3534e8d8bef9SDimitry Andric     // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3535e8d8bef9SDimitry Andric     // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3536e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3537e8d8bef9SDimitry Andric         {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3538e8d8bef9SDimitry Andric          "pthread_mutex_unlock"},
3539e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3540e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
35415ffd83dbSDimitry Andric   }
35425ffd83dbSDimitry Andric 
35435ffd83dbSDimitry Andric   // Functions for testing.
3544*06c3fb27SDimitry Andric   if (AddTestFunctions) {
3545*06c3fb27SDimitry Andric     const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue();
3546*06c3fb27SDimitry Andric 
35475ffd83dbSDimitry Andric     addToFunctionSummaryMap(
3548fe6060f1SDimitry Andric         "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3549fe6060f1SDimitry Andric         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3550fe6060f1SDimitry Andric 
3551*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3552*06c3fb27SDimitry Andric         "__not_null_buffer",
3553*06c3fb27SDimitry Andric         Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),
3554*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3555*06c3fb27SDimitry Andric             .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
3556*06c3fb27SDimitry Andric 
3557*06c3fb27SDimitry Andric     // Test inside range constraints.
3558fe6060f1SDimitry Andric     addToFunctionSummaryMap(
3559bdd1243dSDimitry Andric         "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3560bdd1243dSDimitry Andric         Summary(EvalCallAsPure)
3561bdd1243dSDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
3562bdd1243dSDimitry Andric     addToFunctionSummaryMap(
3563fe6060f1SDimitry Andric         "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3564fe6060f1SDimitry Andric         Summary(EvalCallAsPure)
3565fe6060f1SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3566fe6060f1SDimitry Andric     addToFunctionSummaryMap(
3567fe6060f1SDimitry Andric         "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3568fe6060f1SDimitry Andric         Summary(EvalCallAsPure)
3569fe6060f1SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
3570*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3571*06c3fb27SDimitry Andric         "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3572*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3573*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
3574*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3575*06c3fb27SDimitry Andric         "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3576*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3577*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
3578*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3579*06c3fb27SDimitry Andric         "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3580*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3581*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
3582*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_m1_inf",
3583fe6060f1SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3584fe6060f1SDimitry Andric                             Summary(EvalCallAsPure)
3585fe6060f1SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3586*06c3fb27SDimitry Andric                                     0U, WithinRange, Range(-1, IntMax))));
3587*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_0_inf",
3588*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3589*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3590*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3591*06c3fb27SDimitry Andric                                     0U, WithinRange, Range(0, IntMax))));
3592*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_1_inf",
3593*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3594*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3595*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3596*06c3fb27SDimitry Andric                                     0U, WithinRange, Range(1, IntMax))));
3597*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_minf_m1",
3598*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3599*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3600*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3601*06c3fb27SDimitry Andric                                     0U, WithinRange, Range(IntMin, -1))));
3602*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_minf_0",
3603*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3604*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3605*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3606*06c3fb27SDimitry Andric                                     0U, WithinRange, Range(IntMin, 0))));
3607*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_minf_1",
3608*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3609*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3610*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3611*06c3fb27SDimitry Andric                                     0U, WithinRange, Range(IntMin, 1))));
3612*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_1_2__4_6",
3613*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3614*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3615*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3616*06c3fb27SDimitry Andric                                     0U, WithinRange, Range({1, 2}, {4, 6}))));
3617*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3618*06c3fb27SDimitry Andric         "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3619*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3620*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange,
3621*06c3fb27SDimitry Andric                                              Range({1, 2}, {4, IntMax}))));
3622*06c3fb27SDimitry Andric 
3623*06c3fb27SDimitry Andric     // Test out of range constraints.
3624*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3625*06c3fb27SDimitry Andric         "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3626*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3627*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
3628*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3629*06c3fb27SDimitry Andric         "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3630*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3631*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3632*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3633*06c3fb27SDimitry Andric         "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3634*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3635*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
3636*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3637*06c3fb27SDimitry Andric         "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3638*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3639*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
3640*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3641*06c3fb27SDimitry Andric         "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3642*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3643*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
3644*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3645*06c3fb27SDimitry Andric         "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3646*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3647*06c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
3648*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_m1_inf",
3649*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3650*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3651*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3652*06c3fb27SDimitry Andric                                     0U, OutOfRange, Range(-1, IntMax))));
3653*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_0_inf",
3654*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3655*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3656*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3657*06c3fb27SDimitry Andric                                     0U, OutOfRange, Range(0, IntMax))));
3658*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_1_inf",
3659*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3660*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3661*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3662*06c3fb27SDimitry Andric                                     0U, OutOfRange, Range(1, IntMax))));
3663*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_minf_m1",
3664*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3665*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3666*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3667*06c3fb27SDimitry Andric                                     0U, OutOfRange, Range(IntMin, -1))));
3668*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_minf_0",
3669*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3670*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3671*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3672*06c3fb27SDimitry Andric                                     0U, OutOfRange, Range(IntMin, 0))));
3673*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_minf_1",
3674*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3675*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3676*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3677*06c3fb27SDimitry Andric                                     0U, OutOfRange, Range(IntMin, 1))));
3678*06c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_1_2__4_6",
3679*06c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3680*06c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
3681*06c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
3682*06c3fb27SDimitry Andric                                     0U, OutOfRange, Range({1, 2}, {4, 6}))));
3683*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3684*06c3fb27SDimitry Andric         "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3685*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3686*06c3fb27SDimitry Andric             .ArgConstraint(
3687*06c3fb27SDimitry Andric                 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3688fe6060f1SDimitry Andric 
3689fe6060f1SDimitry Andric     // Test range kind.
3690fe6060f1SDimitry Andric     addToFunctionSummaryMap(
3691fe6060f1SDimitry Andric         "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3692fe6060f1SDimitry Andric         Summary(EvalCallAsPure)
3693fe6060f1SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3694fe6060f1SDimitry Andric     addToFunctionSummaryMap(
3695fe6060f1SDimitry Andric         "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3696fe6060f1SDimitry Andric         Summary(EvalCallAsPure)
3697fe6060f1SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3698fe6060f1SDimitry Andric 
3699fe6060f1SDimitry Andric     addToFunctionSummaryMap(
37005ffd83dbSDimitry Andric         "__two_constrained_args",
3701e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3702e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
37035ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
37045ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
37055ffd83dbSDimitry Andric     addToFunctionSummaryMap(
3706e8d8bef9SDimitry Andric         "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3707e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
37085ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
37095ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
37105ffd83dbSDimitry Andric     addToFunctionSummaryMap(
37115ffd83dbSDimitry Andric         "__defaultparam",
3712e8d8bef9SDimitry Andric         Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3713e8d8bef9SDimitry Andric         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3714e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3715e8d8bef9SDimitry Andric         "__variadic",
3716e8d8bef9SDimitry Andric         Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3717e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
37185ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
37195ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
37205ffd83dbSDimitry Andric     addToFunctionSummaryMap(
37215ffd83dbSDimitry Andric         "__buf_size_arg_constraint",
3722e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
3723e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
37245ffd83dbSDimitry Andric             .ArgConstraint(
37255ffd83dbSDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
37265ffd83dbSDimitry Andric     addToFunctionSummaryMap(
37275ffd83dbSDimitry Andric         "__buf_size_arg_constraint_mul",
3728e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
3729e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
37305ffd83dbSDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
37315ffd83dbSDimitry Andric                                       /*BufSizeMultiplier=*/ArgNo(2))));
3732e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3733e8d8bef9SDimitry Andric         "__buf_size_arg_constraint_concrete",
3734e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3735e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
3736e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3737e8d8bef9SDimitry Andric                                       /*BufSize=*/BVF.getValue(10, IntTy))));
3738e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3739e8d8bef9SDimitry Andric         {"__test_restrict_param_0", "__test_restrict_param_1",
3740e8d8bef9SDimitry Andric          "__test_restrict_param_2"},
3741e8d8bef9SDimitry Andric         Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3742e8d8bef9SDimitry Andric         Summary(EvalCallAsPure));
3743bdd1243dSDimitry Andric 
3744bdd1243dSDimitry Andric     // Test the application of cases.
3745bdd1243dSDimitry Andric     addToFunctionSummaryMap(
3746bdd1243dSDimitry Andric         "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3747bdd1243dSDimitry Andric         Summary(EvalCallAsPure)
3748bdd1243dSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
3749bdd1243dSDimitry Andric                   ErrnoIrrelevant, "Function returns 0")
3750bdd1243dSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
3751bdd1243dSDimitry Andric                   ErrnoIrrelevant, "Function returns 1"));
3752*06c3fb27SDimitry Andric     addToFunctionSummaryMap(
3753*06c3fb27SDimitry Andric         "__test_case_range_1_2__4_6",
3754*06c3fb27SDimitry Andric         Signature(ArgTypes{IntTy}, RetType{IntTy}),
3755*06c3fb27SDimitry Andric         Summary(EvalCallAsPure)
3756*06c3fb27SDimitry Andric             .Case({ArgumentCondition(0U, WithinRange,
3757*06c3fb27SDimitry Andric                                      IntRangeVector{{IntMin, 0}, {3, 3}}),
3758*06c3fb27SDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(1))},
3759*06c3fb27SDimitry Andric                   ErrnoIrrelevant)
3760*06c3fb27SDimitry Andric             .Case({ArgumentCondition(0U, WithinRange,
3761*06c3fb27SDimitry Andric                                      IntRangeVector{{3, 3}, {7, IntMax}}),
3762*06c3fb27SDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(2))},
3763*06c3fb27SDimitry Andric                   ErrnoIrrelevant)
3764*06c3fb27SDimitry Andric             .Case({ArgumentCondition(0U, WithinRange,
3765*06c3fb27SDimitry Andric                                      IntRangeVector{{IntMin, 0}, {7, IntMax}}),
3766*06c3fb27SDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(3))},
3767*06c3fb27SDimitry Andric                   ErrnoIrrelevant)
3768*06c3fb27SDimitry Andric             .Case({ArgumentCondition(
3769*06c3fb27SDimitry Andric                        0U, WithinRange,
3770*06c3fb27SDimitry Andric                        IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
3771*06c3fb27SDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(4))},
3772*06c3fb27SDimitry Andric                   ErrnoIrrelevant));
37735ffd83dbSDimitry Andric   }
37740b57cec5SDimitry Andric }
37750b57cec5SDimitry Andric 
37760b57cec5SDimitry Andric void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
37775ffd83dbSDimitry Andric   auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
3778*06c3fb27SDimitry Andric   Checker->CheckName = mgr.getCurrentCheckerName();
3779349cc55cSDimitry Andric   const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
37805ffd83dbSDimitry Andric   Checker->DisplayLoadedSummaries =
3781349cc55cSDimitry Andric       Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3782349cc55cSDimitry Andric   Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3783349cc55cSDimitry Andric   Checker->ShouldAssumeControlledEnvironment =
3784349cc55cSDimitry Andric       Opts.ShouldAssumeControlledEnvironment;
37850b57cec5SDimitry Andric }
37860b57cec5SDimitry Andric 
3787e8d8bef9SDimitry Andric bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3788e8d8bef9SDimitry Andric     const CheckerManager &mgr) {
37890b57cec5SDimitry Andric   return true;
37900b57cec5SDimitry Andric }
37915ffd83dbSDimitry Andric 
3792*06c3fb27SDimitry Andric void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
3793*06c3fb27SDimitry Andric   auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
3794*06c3fb27SDimitry Andric   Checker->AddTestFunctions = true;
3795*06c3fb27SDimitry Andric }
37965ffd83dbSDimitry Andric 
3797*06c3fb27SDimitry Andric bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3798*06c3fb27SDimitry Andric     const CheckerManager &mgr) {
3799*06c3fb27SDimitry Andric   return true;
3800*06c3fb27SDimitry Andric }
3801