xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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
33*0fca6ea1SDimitry Andric // side effects), 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"
5206c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h"
53fe6060f1SDimitry Andric #include "llvm/ADT/SmallString.h"
54fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h"
5506c3fb27SDimitry 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
7006c3fb27SDimitry Andric   /// to us.
7106c3fb27SDimitry Andric   enum InvalidationKind {
7206c3fb27SDimitry Andric     /// No \c eval::Call for the function, it can be modeled elsewhere.
7306c3fb27SDimitry Andric     /// This checker checks only pre and post conditions.
7406c3fb27SDimitry Andric     NoEvalCall,
7506c3fb27SDimitry Andric     /// The function is modeled completely in this checker.
7606c3fb27SDimitry Andric     EvalCallAsPure
7706c3fb27SDimitry Andric   };
780b57cec5SDimitry Andric 
7906c3fb27SDimitry Andric   /// Given a range, should the argument stay inside or outside this range?
8006c3fb27SDimitry Andric   enum RangeKind { OutOfRange, WithinRange };
8106c3fb27SDimitry Andric 
8206c3fb27SDimitry Andric   static RangeKind negateKind(RangeKind K) {
8306c3fb27SDimitry Andric     switch (K) {
8406c3fb27SDimitry Andric     case OutOfRange:
8506c3fb27SDimitry Andric       return WithinRange;
8606c3fb27SDimitry Andric     case WithinRange:
8706c3fb27SDimitry Andric       return OutOfRange;
8806c3fb27SDimitry Andric     }
8906c3fb27SDimitry Andric     llvm_unreachable("Unknown range kind");
9006c3fb27SDimitry Andric   }
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric   /// The universal integral type to use in value range descriptions.
9306c3fb27SDimitry Andric   /// Unsigned to make sure overflows are well-defined.
945ffd83dbSDimitry Andric   typedef uint64_t RangeInt;
950b57cec5SDimitry Andric 
9606c3fb27SDimitry Andric   /// Describes a single range constraint. Eg. {{0, 1}, {3, 4}} is
9706c3fb27SDimitry 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;
10406c3fb27SDimitry Andric   /// Special argument number for specifying the return value.
1055ffd83dbSDimitry Andric   static const ArgNo Ret;
1060b57cec5SDimitry Andric 
10706c3fb27SDimitry Andric   /// Get a string representation of an argument index.
108fe6060f1SDimitry Andric   /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
10906c3fb27SDimitry Andric   static void printArgDesc(ArgNo, llvm::raw_ostream &Out);
11006c3fb27SDimitry Andric   /// Print value X of the argument in form " (which is X)",
11106c3fb27SDimitry Andric   /// if the value is a fixed known value, otherwise print nothing.
11206c3fb27SDimitry Andric   /// This is used as simple explanation of values if possible.
11306c3fb27SDimitry Andric   static void printArgValueInfo(ArgNo ArgN, ProgramStateRef State,
11406c3fb27SDimitry Andric                                 const CallEvent &Call, llvm::raw_ostream &Out);
11506c3fb27SDimitry Andric   /// Append textual description of a numeric range [RMin,RMax] to
11606c3fb27SDimitry Andric   /// \p Out.
11706c3fb27SDimitry Andric   static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
11806c3fb27SDimitry Andric                                     QualType ArgT, BasicValueFactory &BVF,
11906c3fb27SDimitry Andric                                     llvm::raw_ostream &Out);
12006c3fb27SDimitry Andric   /// Append textual description of a numeric range out of [RMin,RMax] to
12106c3fb27SDimitry Andric   /// \p Out.
12206c3fb27SDimitry Andric   static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
12306c3fb27SDimitry Andric                                    QualType ArgT, BasicValueFactory &BVF,
12406c3fb27SDimitry Andric                                    llvm::raw_ostream &Out);
125fe6060f1SDimitry Andric 
1265ffd83dbSDimitry Andric   class ValueConstraint;
1275ffd83dbSDimitry Andric 
12806c3fb27SDimitry Andric   /// Pointer to the ValueConstraint. We need a copyable, polymorphic and
12906c3fb27SDimitry Andric   /// default initializable type (vector needs that). A raw pointer was good,
13006c3fb27SDimitry Andric   /// however, we cannot default initialize that. unique_ptr makes the Summary
13106c3fb27SDimitry Andric   /// class non-copyable, therefore not an option. Releasing the copyability
13206c3fb27SDimitry Andric   /// requirement would render the initialization of the Summary map infeasible.
13306c3fb27SDimitry Andric   /// Mind that a pointer to a new value constraint is created when the negate
13406c3fb27SDimitry 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.
14106c3fb27SDimitry Andric   /// These are used as argument constraints (preconditions) of functions, in
14206c3fb27SDimitry Andric   /// which case a bug report may be emitted if the constraint is not satisfied.
14306c3fb27SDimitry Andric   /// Another use is as conditions for summary cases, to create different
14406c3fb27SDimitry Andric   /// classes of behavior for a function. In this case no description of the
14506c3fb27SDimitry Andric   /// constraint is needed because the summary cases have an own (not generated)
14606c3fb27SDimitry Andric   /// description string.
1475ffd83dbSDimitry Andric   class ValueConstraint {
1485ffd83dbSDimitry Andric   public:
1495ffd83dbSDimitry Andric     ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
1505ffd83dbSDimitry Andric     virtual ~ValueConstraint() {}
15106c3fb27SDimitry 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;
15706c3fb27SDimitry Andric 
15806c3fb27SDimitry Andric     /// Represents that in which context do we require a description of the
15906c3fb27SDimitry Andric     /// constraint.
16006c3fb27SDimitry Andric     enum DescriptionKind {
16106c3fb27SDimitry Andric       /// Describe a constraint that was violated.
16206c3fb27SDimitry Andric       /// Description should start with something like "should be".
16306c3fb27SDimitry Andric       Violation,
16406c3fb27SDimitry Andric       /// Describe a constraint that was assumed to be true.
16506c3fb27SDimitry Andric       /// This can be used when a precondition is satisfied, or when a summary
16606c3fb27SDimitry Andric       /// case is applied.
16706c3fb27SDimitry Andric       /// Description should start with something like "is".
16806c3fb27SDimitry Andric       Assumption
16906c3fb27SDimitry Andric     };
17006c3fb27SDimitry Andric 
17106c3fb27SDimitry Andric     /// Give a description that explains the constraint to the user. Used when
17206c3fb27SDimitry Andric     /// a bug is reported or when the constraint is applied and displayed as a
17306c3fb27SDimitry Andric     /// note. The description should not mention the argument (getArgNo).
17406c3fb27SDimitry Andric     /// See StdLibraryFunctionsChecker::reportBug about how this function is
17506c3fb27SDimitry Andric     /// used (this function is used not only there).
17606c3fb27SDimitry Andric     virtual void describe(DescriptionKind DK, const CallEvent &Call,
17706c3fb27SDimitry Andric                           ProgramStateRef State, const Summary &Summary,
17806c3fb27SDimitry Andric                           llvm::raw_ostream &Out) const {
17906c3fb27SDimitry Andric       // There are some descendant classes that are not used as argument
18006c3fb27SDimitry Andric       // constraints, e.g. ComparisonConstraint. In that case we can safely
18106c3fb27SDimitry Andric       // ignore the implementation of this function.
18206c3fb27SDimitry Andric       llvm_unreachable(
18306c3fb27SDimitry Andric           "Description not implemented for summary case constraints");
18406c3fb27SDimitry Andric     }
18506c3fb27SDimitry Andric 
18606c3fb27SDimitry Andric     /// Give a description that explains the actual argument value (where the
18706c3fb27SDimitry Andric     /// current ValueConstraint applies to) to the user. This function should be
18806c3fb27SDimitry Andric     /// called only when the current constraint is satisfied by the argument.
18906c3fb27SDimitry Andric     /// It should produce a more precise description than the constraint itself.
19006c3fb27SDimitry Andric     /// The actual value of the argument and the program state can be used to
19106c3fb27SDimitry Andric     /// make the description more precise. In the most simple case, if the
19206c3fb27SDimitry Andric     /// argument has a fixed known value this value can be printed into \p Out,
19306c3fb27SDimitry Andric     /// this is done by default.
19406c3fb27SDimitry Andric     /// The function should return true if a description was printed to \p Out,
19506c3fb27SDimitry Andric     /// otherwise false.
19606c3fb27SDimitry Andric     /// See StdLibraryFunctionsChecker::reportBug about how this function is
19706c3fb27SDimitry Andric     /// used.
19806c3fb27SDimitry Andric     virtual bool describeArgumentValue(const CallEvent &Call,
19906c3fb27SDimitry Andric                                        ProgramStateRef State,
20006c3fb27SDimitry Andric                                        const Summary &Summary,
20106c3fb27SDimitry Andric                                        llvm::raw_ostream &Out) const {
20206c3fb27SDimitry Andric       if (auto N = getArgSVal(Call, getArgNo()).getAs<NonLoc>()) {
20306c3fb27SDimitry Andric         if (const llvm::APSInt *Int = N->getAsInteger()) {
20406c3fb27SDimitry Andric           Out << *Int;
20506c3fb27SDimitry Andric           return true;
20606c3fb27SDimitry Andric         }
20706c3fb27SDimitry Andric       }
20806c3fb27SDimitry Andric       return false;
20906c3fb27SDimitry Andric     }
21006c3fb27SDimitry Andric 
21106c3fb27SDimitry Andric     /// Return those arguments that should be tracked when we report a bug about
21206c3fb27SDimitry Andric     /// argument constraint violation. By default it is the argument that is
21306c3fb27SDimitry Andric     /// constrained, however, in some special cases we need to track other
21406c3fb27SDimitry Andric     /// arguments as well. E.g. a buffer size might be encoded in another
21506c3fb27SDimitry Andric     /// argument.
21606c3fb27SDimitry Andric     /// The "return value" argument number can not occur as returned value.
21706c3fb27SDimitry Andric     virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
21806c3fb27SDimitry Andric 
21906c3fb27SDimitry 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 
22406c3fb27SDimitry Andric     /// Check whether the constraint is malformed or not. It is malformed if the
22506c3fb27SDimitry Andric     /// specified argument has a mismatch with the given FunctionDecl (e.g. the
22606c3fb27SDimitry Andric     /// arg number is out-of-range of the function's argument list).
22706c3fb27SDimitry Andric     /// This condition can indicate if a probably wrong or unexpected function
22806c3fb27SDimitry 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     }
23706c3fb27SDimitry Andric 
23806c3fb27SDimitry Andric     /// Return the argument number (may be placeholder for "return value").
2395ffd83dbSDimitry Andric     ArgNo getArgNo() const { return ArgN; }
2405ffd83dbSDimitry Andric 
2415ffd83dbSDimitry Andric   protected:
24206c3fb27SDimitry Andric     /// Argument to which to apply the constraint. It can be a real argument of
24306c3fb27SDimitry Andric     /// the function to check, or a special value to indicate the return value
24406c3fb27SDimitry Andric     /// of the function.
24506c3fb27SDimitry Andric     /// Every constraint is assigned to one main argument, even if other
24606c3fb27SDimitry Andric     /// arguments are involved.
24706c3fb27SDimitry Andric     ArgNo ArgN;
2485ffd83dbSDimitry Andric 
24906c3fb27SDimitry 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 
25506c3fb27SDimitry Andric   /// Check if a single argument falls into a specific "range".
25606c3fb27SDimitry Andric   /// A range is formed as a set of intervals.
25706c3fb27SDimitry Andric   /// E.g. \code {['A', 'Z'], ['a', 'z'], ['_', '_']} \endcode
25806c3fb27SDimitry Andric   /// The intervals are closed intervals that contain one or more values.
25906c3fb27SDimitry Andric   ///
26006c3fb27SDimitry Andric   /// The default constructed RangeConstraint has an empty range, applying
26106c3fb27SDimitry Andric   /// such constraint does not involve any assumptions, thus the State remains
26206c3fb27SDimitry Andric   /// unchanged. This is meaningful, if the range is dependent on a looked up
26306c3fb27SDimitry Andric   /// type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
26406c3fb27SDimitry Andric   /// is default initialized to be empty.
2655ffd83dbSDimitry Andric   class RangeConstraint : public ValueConstraint {
26606c3fb27SDimitry Andric     /// The constraint can be specified by allowing or disallowing the range.
26706c3fb27SDimitry Andric     /// WithinRange indicates allowing the range, OutOfRange indicates
26806c3fb27SDimitry Andric     /// disallowing it (allowing the complementary range).
269e8d8bef9SDimitry Andric     RangeKind Kind;
27006c3fb27SDimitry Andric 
27106c3fb27SDimitry Andric     /// A set of intervals.
272e8d8bef9SDimitry Andric     IntRangeVector Ranges;
2730b57cec5SDimitry Andric 
27406c3fb27SDimitry Andric     /// A textual description of this constraint for the specific case where the
27506c3fb27SDimitry Andric     /// constraint is used. If empty a generated description will be used that
27606c3fb27SDimitry Andric     /// is built from the range of the constraint.
27706c3fb27SDimitry Andric     StringRef Description;
2780b57cec5SDimitry Andric 
27906c3fb27SDimitry Andric   public:
28006c3fb27SDimitry Andric     RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges,
28106c3fb27SDimitry Andric                     StringRef Desc = "")
28206c3fb27SDimitry Andric         : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges), Description(Desc) {
28306c3fb27SDimitry 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,
28906c3fb27SDimitry Andric                           CheckerContext &C) const override;
29006c3fb27SDimitry Andric 
29106c3fb27SDimitry Andric     void describe(DescriptionKind DK, const CallEvent &Call,
29206c3fb27SDimitry Andric                   ProgramStateRef State, const Summary &Summary,
29306c3fb27SDimitry Andric                   llvm::raw_ostream &Out) const override;
29406c3fb27SDimitry Andric 
29506c3fb27SDimitry Andric     bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
29606c3fb27SDimitry Andric                                const Summary &Summary,
29706c3fb27SDimitry Andric                                llvm::raw_ostream &Out) const override;
2985ffd83dbSDimitry Andric 
2995ffd83dbSDimitry Andric     ValueConstraintPtr negate() const override {
3005ffd83dbSDimitry Andric       RangeConstraint Tmp(*this);
30106c3fb27SDimitry Andric       Tmp.Kind = negateKind(Kind);
3025ffd83dbSDimitry Andric       return std::make_shared<RangeConstraint>(Tmp);
3035ffd83dbSDimitry Andric     }
3045ffd83dbSDimitry Andric 
30506c3fb27SDimitry 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     }
31306c3fb27SDimitry Andric 
31406c3fb27SDimitry Andric   private:
31506c3fb27SDimitry Andric     /// A callback function that is used when iterating over the range
31606c3fb27SDimitry Andric     /// intervals. It gets the begin and end (inclusive) of one interval.
31706c3fb27SDimitry Andric     /// This is used to make any kind of task possible that needs an iteration
31806c3fb27SDimitry Andric     /// over the intervals.
31906c3fb27SDimitry Andric     using RangeApplyFunction =
32006c3fb27SDimitry Andric         std::function<bool(const llvm::APSInt &Min, const llvm::APSInt &Max)>;
32106c3fb27SDimitry Andric 
32206c3fb27SDimitry Andric     /// Call a function on the intervals of the range.
32306c3fb27SDimitry Andric     /// The function is called with all intervals in the range.
32406c3fb27SDimitry Andric     void applyOnWithinRange(BasicValueFactory &BVF, QualType ArgT,
32506c3fb27SDimitry Andric                             const RangeApplyFunction &F) const;
32606c3fb27SDimitry Andric     /// Call a function on all intervals in the complementary range.
32706c3fb27SDimitry Andric     /// The function is called with all intervals that fall out of the range.
32806c3fb27SDimitry Andric     /// E.g. consider an interval list [A, B] and [C, D]
32906c3fb27SDimitry Andric     /// \code
33006c3fb27SDimitry Andric     /// -------+--------+------------------+------------+----------->
33106c3fb27SDimitry Andric     ///        A        B                  C            D
33206c3fb27SDimitry Andric     /// \endcode
33306c3fb27SDimitry Andric     /// We get the ranges [-inf, A - 1], [D + 1, +inf], [B + 1, C - 1].
33406c3fb27SDimitry Andric     /// The \p ArgT is used to determine the min and max of the type that is
33506c3fb27SDimitry Andric     /// used as "-inf" and "+inf".
33606c3fb27SDimitry Andric     void applyOnOutOfRange(BasicValueFactory &BVF, QualType ArgT,
33706c3fb27SDimitry Andric                            const RangeApplyFunction &F) const;
33806c3fb27SDimitry Andric     /// Call a function on the intervals of the range or the complementary
33906c3fb27SDimitry Andric     /// range.
34006c3fb27SDimitry Andric     void applyOnRange(RangeKind Kind, BasicValueFactory &BVF, QualType ArgT,
34106c3fb27SDimitry Andric                       const RangeApplyFunction &F) const {
34206c3fb27SDimitry Andric       switch (Kind) {
34306c3fb27SDimitry Andric       case OutOfRange:
34406c3fb27SDimitry Andric         applyOnOutOfRange(BVF, ArgT, F);
34506c3fb27SDimitry Andric         break;
34606c3fb27SDimitry Andric       case WithinRange:
34706c3fb27SDimitry Andric         applyOnWithinRange(BVF, ArgT, F);
34806c3fb27SDimitry Andric         break;
34906c3fb27SDimitry Andric       };
35006c3fb27SDimitry Andric     }
3510b57cec5SDimitry Andric   };
3520b57cec5SDimitry Andric 
35306c3fb27SDimitry 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 
36906c3fb27SDimitry 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) {}
37806c3fb27SDimitry Andric 
3795ffd83dbSDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
3805ffd83dbSDimitry Andric                           const Summary &Summary,
38106c3fb27SDimitry Andric                           CheckerContext &C) const override;
3825ffd83dbSDimitry Andric 
38306c3fb27SDimitry Andric     void describe(DescriptionKind DK, const CallEvent &Call,
38406c3fb27SDimitry Andric                   ProgramStateRef State, const Summary &Summary,
38506c3fb27SDimitry Andric                   llvm::raw_ostream &Out) const override;
3865ffd83dbSDimitry Andric 
38706c3fb27SDimitry Andric     bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
38806c3fb27SDimitry Andric                                const Summary &Summary,
38906c3fb27SDimitry 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 
39706c3fb27SDimitry Andric   protected:
39806c3fb27SDimitry Andric     bool checkSpecificValidity(const FunctionDecl *FD) const override {
39906c3fb27SDimitry Andric       const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
40006c3fb27SDimitry Andric       assert(ValidArg &&
40106c3fb27SDimitry Andric              "This constraint should be applied only on a pointer type");
40206c3fb27SDimitry Andric       return ValidArg;
40306c3fb27SDimitry Andric     }
40406c3fb27SDimitry Andric   };
40506c3fb27SDimitry Andric 
40606c3fb27SDimitry Andric   /// Check null or non-null-ness of an argument that is of pointer type.
40706c3fb27SDimitry Andric   /// The argument is meant to be a buffer that has a size constraint, and it
40806c3fb27SDimitry Andric   /// is allowed to have a NULL value if the size is 0. The size can depend on
40906c3fb27SDimitry Andric   /// 1 or 2 additional arguments, if one of these is 0 the buffer is allowed to
41006c3fb27SDimitry Andric   /// be NULL. This is useful for functions like `fread` which have this special
41106c3fb27SDimitry Andric   /// property.
41206c3fb27SDimitry Andric   class NotNullBufferConstraint : public ValueConstraint {
41306c3fb27SDimitry Andric     using ValueConstraint::ValueConstraint;
41406c3fb27SDimitry Andric     ArgNo SizeArg1N;
41506c3fb27SDimitry Andric     std::optional<ArgNo> SizeArg2N;
41606c3fb27SDimitry Andric     // This variable has a role when we negate the constraint.
41706c3fb27SDimitry Andric     bool CannotBeNull = true;
41806c3fb27SDimitry Andric 
41906c3fb27SDimitry Andric   public:
42006c3fb27SDimitry Andric     NotNullBufferConstraint(ArgNo ArgN, ArgNo SizeArg1N,
42106c3fb27SDimitry Andric                             std::optional<ArgNo> SizeArg2N,
42206c3fb27SDimitry Andric                             bool CannotBeNull = true)
42306c3fb27SDimitry Andric         : ValueConstraint(ArgN), SizeArg1N(SizeArg1N), SizeArg2N(SizeArg2N),
42406c3fb27SDimitry Andric           CannotBeNull(CannotBeNull) {}
42506c3fb27SDimitry Andric 
42606c3fb27SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
42706c3fb27SDimitry Andric                           const Summary &Summary,
42806c3fb27SDimitry Andric                           CheckerContext &C) const override;
42906c3fb27SDimitry Andric 
43006c3fb27SDimitry Andric     void describe(DescriptionKind DK, const CallEvent &Call,
43106c3fb27SDimitry Andric                   ProgramStateRef State, const Summary &Summary,
43206c3fb27SDimitry Andric                   llvm::raw_ostream &Out) const override;
43306c3fb27SDimitry Andric 
43406c3fb27SDimitry Andric     bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
43506c3fb27SDimitry Andric                                const Summary &Summary,
43606c3fb27SDimitry Andric                                llvm::raw_ostream &Out) const override;
43706c3fb27SDimitry Andric 
43806c3fb27SDimitry Andric     ValueConstraintPtr negate() const override {
43906c3fb27SDimitry Andric       NotNullBufferConstraint Tmp(*this);
44006c3fb27SDimitry Andric       Tmp.CannotBeNull = !this->CannotBeNull;
44106c3fb27SDimitry Andric       return std::make_shared<NotNullBufferConstraint>(Tmp);
44206c3fb27SDimitry Andric     }
44306c3fb27SDimitry Andric 
44406c3fb27SDimitry 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 
48406c3fb27SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
48506c3fb27SDimitry Andric                           const Summary &Summary,
48606c3fb27SDimitry Andric                           CheckerContext &C) const override;
48706c3fb27SDimitry Andric 
48806c3fb27SDimitry Andric     void describe(DescriptionKind DK, const CallEvent &Call,
48906c3fb27SDimitry Andric                   ProgramStateRef State, const Summary &Summary,
49006c3fb27SDimitry Andric                   llvm::raw_ostream &Out) const override;
49106c3fb27SDimitry Andric 
49206c3fb27SDimitry Andric     bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
49306c3fb27SDimitry Andric                                const Summary &Summary,
49406c3fb27SDimitry Andric                                llvm::raw_ostream &Out) const override;
49506c3fb27SDimitry 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 
51106c3fb27SDimitry 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;
5365f757f3fSDimitry Andric     /// Get a description about what happens with 'errno' here and how it causes
5375f757f3fSDimitry Andric     /// a later bug report created by ErrnoChecker.
5385f757f3fSDimitry Andric     /// Empty return value means that 'errno' related bug may not happen from
5395f757f3fSDimitry Andric     /// the current analyzed function.
5405f757f3fSDimitry Andric     virtual const std::string describe(CheckerContext &C) const { return ""; }
54181ad6265SDimitry Andric 
54281ad6265SDimitry Andric     virtual ~ErrnoConstraintBase() {}
54381ad6265SDimitry Andric 
54481ad6265SDimitry Andric   protected:
545bdd1243dSDimitry Andric     ErrnoConstraintBase() = default;
54681ad6265SDimitry Andric 
54781ad6265SDimitry Andric     /// This is used for conjure symbol for errno to differentiate from the
54881ad6265SDimitry Andric     /// original call expression (same expression is used for the errno symbol).
54981ad6265SDimitry Andric     static int Tag;
55081ad6265SDimitry Andric   };
55181ad6265SDimitry Andric 
552bdd1243dSDimitry Andric   /// Reset errno constraints to irrelevant.
553bdd1243dSDimitry Andric   /// This is applicable to functions that may change 'errno' and are not
554bdd1243dSDimitry Andric   /// modeled elsewhere.
555bdd1243dSDimitry Andric   class ResetErrnoConstraint : public ErrnoConstraintBase {
55681ad6265SDimitry Andric   public:
557bdd1243dSDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
558bdd1243dSDimitry Andric                           const Summary &Summary,
559bdd1243dSDimitry Andric                           CheckerContext &C) const override {
560bdd1243dSDimitry Andric       return errno_modeling::setErrnoState(State, errno_modeling::Irrelevant);
56181ad6265SDimitry Andric     }
562bdd1243dSDimitry Andric   };
56381ad6265SDimitry Andric 
564bdd1243dSDimitry Andric   /// Do not change errno constraints.
565bdd1243dSDimitry Andric   /// This is applicable to functions that are modeled in another checker
566bdd1243dSDimitry Andric   /// and the already set errno constraints should not be changed in the
567bdd1243dSDimitry Andric   /// post-call event.
568bdd1243dSDimitry Andric   class NoErrnoConstraint : public ErrnoConstraintBase {
569bdd1243dSDimitry Andric   public:
570bdd1243dSDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
571bdd1243dSDimitry Andric                           const Summary &Summary,
572bdd1243dSDimitry Andric                           CheckerContext &C) const override {
573bdd1243dSDimitry Andric       return State;
574bdd1243dSDimitry Andric     }
575bdd1243dSDimitry Andric   };
576bdd1243dSDimitry Andric 
577bdd1243dSDimitry Andric   /// Set errno constraint at failure cases of standard functions.
578bdd1243dSDimitry Andric   /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
579bdd1243dSDimitry Andric   /// by the program. \c ErrnoChecker does not emit a bug report after such a
580bdd1243dSDimitry Andric   /// function call.
581bdd1243dSDimitry Andric   class FailureErrnoConstraint : public ErrnoConstraintBase {
582bdd1243dSDimitry Andric   public:
58381ad6265SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
58481ad6265SDimitry Andric                           const Summary &Summary,
58581ad6265SDimitry Andric                           CheckerContext &C) const override {
58681ad6265SDimitry Andric       SValBuilder &SVB = C.getSValBuilder();
58781ad6265SDimitry Andric       NonLoc ErrnoSVal =
58881ad6265SDimitry Andric           SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
58981ad6265SDimitry Andric                                C.getLocationContext(), C.getASTContext().IntTy,
59081ad6265SDimitry Andric                                C.blockCount())
59181ad6265SDimitry Andric               .castAs<NonLoc>();
592bdd1243dSDimitry Andric       return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
59381ad6265SDimitry Andric     }
59481ad6265SDimitry Andric   };
59581ad6265SDimitry Andric 
596bdd1243dSDimitry Andric   /// Set errno constraint at success cases of standard functions.
5975f757f3fSDimitry Andric   /// Success case: 'errno' is not allowed to be used because the value is
5985f757f3fSDimitry Andric   /// undefined after successful call.
599bdd1243dSDimitry Andric   /// \c ErrnoChecker can emit bug report after such a function call if errno
600bdd1243dSDimitry Andric   /// is used.
60181ad6265SDimitry Andric   class SuccessErrnoConstraint : public ErrnoConstraintBase {
60281ad6265SDimitry Andric   public:
60381ad6265SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
60481ad6265SDimitry Andric                           const Summary &Summary,
60581ad6265SDimitry Andric                           CheckerContext &C) const override {
606bdd1243dSDimitry Andric       return errno_modeling::setErrnoForStdSuccess(State, C);
60781ad6265SDimitry Andric     }
60881ad6265SDimitry Andric 
6095f757f3fSDimitry Andric     const std::string describe(CheckerContext &C) const override {
6105f757f3fSDimitry Andric       return "'errno' becomes undefined after the call";
61181ad6265SDimitry Andric     }
61281ad6265SDimitry Andric   };
61381ad6265SDimitry Andric 
6145f757f3fSDimitry Andric   /// Set errno constraint at functions that indicate failure only with 'errno'.
6155f757f3fSDimitry Andric   /// In this case 'errno' is required to be observed.
6165f757f3fSDimitry Andric   /// \c ErrnoChecker can emit bug report after such a function call if errno
6175f757f3fSDimitry Andric   /// is overwritten without a read before.
618bdd1243dSDimitry Andric   class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
61981ad6265SDimitry Andric   public:
62081ad6265SDimitry Andric     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
62181ad6265SDimitry Andric                           const Summary &Summary,
62281ad6265SDimitry Andric                           CheckerContext &C) const override {
623bdd1243dSDimitry Andric       return errno_modeling::setErrnoStdMustBeChecked(State, C,
624bdd1243dSDimitry Andric                                                       Call.getOriginExpr());
625bdd1243dSDimitry Andric     }
626bdd1243dSDimitry Andric 
6275f757f3fSDimitry Andric     const std::string describe(CheckerContext &C) const override {
6285f757f3fSDimitry Andric       return "reading 'errno' is required to find out if the call has failed";
62981ad6265SDimitry Andric     }
63081ad6265SDimitry Andric   };
63181ad6265SDimitry Andric 
63281ad6265SDimitry Andric   /// A single branch of a function summary.
63381ad6265SDimitry Andric   ///
63481ad6265SDimitry Andric   /// A branch is defined by a series of constraints - "assumptions" -
63581ad6265SDimitry Andric   /// that together form a single possible outcome of invoking the function.
63681ad6265SDimitry Andric   /// When static analyzer considers a branch, it tries to introduce
63781ad6265SDimitry Andric   /// a child node in the Exploded Graph. The child node has to include
63881ad6265SDimitry Andric   /// constraints that define the branch. If the constraints contradict
63981ad6265SDimitry Andric   /// existing constraints in the state, the node is not created and the branch
64081ad6265SDimitry Andric   /// is dropped; otherwise it's queued for future exploration.
64181ad6265SDimitry Andric   /// The branch is accompanied by a note text that may be displayed
64281ad6265SDimitry Andric   /// to the user when a bug is found on a path that takes this branch.
64381ad6265SDimitry Andric   ///
64481ad6265SDimitry Andric   /// For example, consider the branches in `isalpha(x)`:
64581ad6265SDimitry Andric   ///   Branch 1)
64681ad6265SDimitry Andric   ///     x is in range ['A', 'Z'] or in ['a', 'z']
64781ad6265SDimitry Andric   ///     then the return value is not 0. (I.e. out-of-range [0, 0])
64881ad6265SDimitry Andric   ///     and the note may say "Assuming the character is alphabetical"
64981ad6265SDimitry Andric   ///   Branch 2)
65081ad6265SDimitry Andric   ///     x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
65181ad6265SDimitry Andric   ///     then the return value is 0
65281ad6265SDimitry Andric   ///     and the note may say "Assuming the character is non-alphabetical".
65381ad6265SDimitry Andric   class SummaryCase {
65481ad6265SDimitry Andric     ConstraintSet Constraints;
65581ad6265SDimitry Andric     const ErrnoConstraintBase &ErrnoConstraint;
65681ad6265SDimitry Andric     StringRef Note;
65781ad6265SDimitry Andric 
65881ad6265SDimitry Andric   public:
65981ad6265SDimitry Andric     SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,
66081ad6265SDimitry Andric                 StringRef Note)
66181ad6265SDimitry Andric         : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),
66281ad6265SDimitry Andric           Note(Note) {}
66381ad6265SDimitry Andric 
66481ad6265SDimitry Andric     SummaryCase(const ConstraintSet &Constraints,
66581ad6265SDimitry Andric                 const ErrnoConstraintBase &ErrnoC, StringRef Note)
66681ad6265SDimitry Andric         : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}
66781ad6265SDimitry Andric 
66881ad6265SDimitry Andric     const ConstraintSet &getConstraints() const { return Constraints; }
66981ad6265SDimitry Andric     const ErrnoConstraintBase &getErrnoConstraint() const {
67081ad6265SDimitry Andric       return ErrnoConstraint;
67181ad6265SDimitry Andric     }
67281ad6265SDimitry Andric     StringRef getNote() const { return Note; }
67381ad6265SDimitry Andric   };
6745ffd83dbSDimitry Andric 
675*0fca6ea1SDimitry Andric   using ArgTypes = ArrayRef<std::optional<QualType>>;
676bdd1243dSDimitry Andric   using RetType = std::optional<QualType>;
6775ffd83dbSDimitry Andric 
6785ffd83dbSDimitry Andric   // A placeholder type, we use it whenever we do not care about the concrete
6795ffd83dbSDimitry Andric   // type in a Signature.
6805ffd83dbSDimitry Andric   const QualType Irrelevant{};
6815ffd83dbSDimitry Andric   bool static isIrrelevant(QualType T) { return T.isNull(); }
6825ffd83dbSDimitry Andric 
6835ffd83dbSDimitry Andric   // The signature of a function we want to describe with a summary. This is a
6845ffd83dbSDimitry Andric   // concessive signature, meaning there may be irrelevant types in the
6855ffd83dbSDimitry Andric   // signature which we do not check against a function with concrete types.
686e8d8bef9SDimitry Andric   // All types in the spec need to be canonical.
687e8d8bef9SDimitry Andric   class Signature {
688e8d8bef9SDimitry Andric     using ArgQualTypes = std::vector<QualType>;
689e8d8bef9SDimitry Andric     ArgQualTypes ArgTys;
690e8d8bef9SDimitry Andric     QualType RetTy;
691e8d8bef9SDimitry Andric     // True if any component type is not found by lookup.
692e8d8bef9SDimitry Andric     bool Invalid = false;
693e8d8bef9SDimitry Andric 
694e8d8bef9SDimitry Andric   public:
695e8d8bef9SDimitry Andric     // Construct a signature from optional types. If any of the optional types
696e8d8bef9SDimitry Andric     // are not set then the signature will be invalid.
697e8d8bef9SDimitry Andric     Signature(ArgTypes ArgTys, RetType RetTy) {
698bdd1243dSDimitry Andric       for (std::optional<QualType> Arg : ArgTys) {
699e8d8bef9SDimitry Andric         if (!Arg) {
700e8d8bef9SDimitry Andric           Invalid = true;
701e8d8bef9SDimitry Andric           return;
702e8d8bef9SDimitry Andric         } else {
703e8d8bef9SDimitry Andric           assertArgTypeSuitableForSignature(*Arg);
704e8d8bef9SDimitry Andric           this->ArgTys.push_back(*Arg);
7055ffd83dbSDimitry Andric         }
7065ffd83dbSDimitry Andric       }
707e8d8bef9SDimitry Andric       if (!RetTy) {
708e8d8bef9SDimitry Andric         Invalid = true;
709e8d8bef9SDimitry Andric         return;
710e8d8bef9SDimitry Andric       } else {
711e8d8bef9SDimitry Andric         assertRetTypeSuitableForSignature(*RetTy);
712e8d8bef9SDimitry Andric         this->RetTy = *RetTy;
713e8d8bef9SDimitry Andric       }
714e8d8bef9SDimitry Andric     }
715e8d8bef9SDimitry Andric 
716e8d8bef9SDimitry Andric     bool isInvalid() const { return Invalid; }
7175ffd83dbSDimitry Andric     bool matches(const FunctionDecl *FD) const;
7185ffd83dbSDimitry Andric 
7195ffd83dbSDimitry Andric   private:
7205ffd83dbSDimitry Andric     static void assertArgTypeSuitableForSignature(QualType T) {
7215ffd83dbSDimitry Andric       assert((T.isNull() || !T->isVoidType()) &&
7225ffd83dbSDimitry Andric              "We should have no void types in the spec");
7235ffd83dbSDimitry Andric       assert((T.isNull() || T.isCanonical()) &&
7245ffd83dbSDimitry Andric              "We should only have canonical types in the spec");
7255ffd83dbSDimitry Andric     }
7265ffd83dbSDimitry Andric     static void assertRetTypeSuitableForSignature(QualType T) {
7275ffd83dbSDimitry Andric       assert((T.isNull() || T.isCanonical()) &&
7285ffd83dbSDimitry Andric              "We should only have canonical types in the spec");
7295ffd83dbSDimitry Andric     }
7305ffd83dbSDimitry Andric   };
7315ffd83dbSDimitry Andric 
7325ffd83dbSDimitry Andric   static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
7335ffd83dbSDimitry Andric     assert(FD && "Function must be set");
7345ffd83dbSDimitry Andric     QualType T = (ArgN == Ret)
7355ffd83dbSDimitry Andric                      ? FD->getReturnType().getCanonicalType()
7365ffd83dbSDimitry Andric                      : FD->getParamDecl(ArgN)->getType().getCanonicalType();
7370b57cec5SDimitry Andric     return T;
7380b57cec5SDimitry Andric   }
7390b57cec5SDimitry Andric 
74081ad6265SDimitry Andric   using SummaryCases = std::vector<SummaryCase>;
7410b57cec5SDimitry Andric 
7425ffd83dbSDimitry Andric   /// A summary includes information about
7435ffd83dbSDimitry Andric   ///   * function prototype (signature)
7445ffd83dbSDimitry Andric   ///   * approach to invalidation,
74581ad6265SDimitry Andric   ///   * a list of branches - so, a list of list of ranges,
7465ffd83dbSDimitry Andric   ///   * a list of argument constraints, that must be true on every branch.
7475ffd83dbSDimitry Andric   ///     If these constraints are not satisfied that means a fatal error
7485ffd83dbSDimitry Andric   ///     usually resulting in undefined behaviour.
7495ffd83dbSDimitry Andric   ///
7505ffd83dbSDimitry Andric   /// Application of a summary:
7515ffd83dbSDimitry Andric   ///   The signature and argument constraints together contain information
7525ffd83dbSDimitry Andric   ///   about which functions are handled by the summary. The signature can use
7535ffd83dbSDimitry Andric   ///   "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
7545ffd83dbSDimitry Andric   ///   a signature means that type is not compared to the type of the parameter
7555ffd83dbSDimitry Andric   ///   in the found FunctionDecl. Argument constraints may specify additional
7565ffd83dbSDimitry Andric   ///   rules for the given parameter's type, those rules are checked once the
7575ffd83dbSDimitry Andric   ///   signature is matched.
7585ffd83dbSDimitry Andric   class Summary {
7595ffd83dbSDimitry Andric     const InvalidationKind InvalidationKd;
76081ad6265SDimitry Andric     SummaryCases Cases;
7615ffd83dbSDimitry Andric     ConstraintSet ArgConstraints;
7625ffd83dbSDimitry Andric 
7635ffd83dbSDimitry Andric     // The function to which the summary applies. This is set after lookup and
7645ffd83dbSDimitry Andric     // match to the signature.
7655ffd83dbSDimitry Andric     const FunctionDecl *FD = nullptr;
7665ffd83dbSDimitry Andric 
7675ffd83dbSDimitry Andric   public:
768e8d8bef9SDimitry Andric     Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
7695ffd83dbSDimitry Andric 
77081ad6265SDimitry Andric     Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,
77181ad6265SDimitry Andric                   StringRef Note = "") {
77281ad6265SDimitry Andric       Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));
7735ffd83dbSDimitry Andric       return *this;
7745ffd83dbSDimitry Andric     }
77581ad6265SDimitry Andric     Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,
77681ad6265SDimitry Andric                   StringRef Note = "") {
77781ad6265SDimitry Andric       Cases.push_back(SummaryCase(CS, ErrnoC, Note));
778e8d8bef9SDimitry Andric       return *this;
779e8d8bef9SDimitry Andric     }
7805ffd83dbSDimitry Andric     Summary &ArgConstraint(ValueConstraintPtr VC) {
781e8d8bef9SDimitry Andric       assert(VC->getArgNo() != Ret &&
782e8d8bef9SDimitry Andric              "Arg constraint should not refer to the return value");
7835ffd83dbSDimitry Andric       ArgConstraints.push_back(VC);
7845ffd83dbSDimitry Andric       return *this;
7855ffd83dbSDimitry Andric     }
7865ffd83dbSDimitry Andric 
7875ffd83dbSDimitry Andric     InvalidationKind getInvalidationKd() const { return InvalidationKd; }
78881ad6265SDimitry Andric     const SummaryCases &getCases() const { return Cases; }
7895ffd83dbSDimitry Andric     const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
7905ffd83dbSDimitry Andric 
7915ffd83dbSDimitry Andric     QualType getArgType(ArgNo ArgN) const {
7925ffd83dbSDimitry Andric       return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
7935ffd83dbSDimitry Andric     }
7945ffd83dbSDimitry Andric 
7955ffd83dbSDimitry Andric     // Returns true if the summary should be applied to the given function.
7965ffd83dbSDimitry Andric     // And if yes then store the function declaration.
797e8d8bef9SDimitry Andric     bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
7985ffd83dbSDimitry Andric       bool Result = Sign.matches(FD) && validateByConstraints(FD);
7995ffd83dbSDimitry Andric       if (Result) {
8005ffd83dbSDimitry Andric         assert(!this->FD && "FD must not be set more than once");
8015ffd83dbSDimitry Andric         this->FD = FD;
8025ffd83dbSDimitry Andric       }
8035ffd83dbSDimitry Andric       return Result;
8045ffd83dbSDimitry Andric     }
8055ffd83dbSDimitry Andric 
8065ffd83dbSDimitry Andric   private:
8075e801ac6SDimitry Andric     // Once we know the exact type of the function then do validation check on
8085e801ac6SDimitry Andric     // all the given constraints.
8095ffd83dbSDimitry Andric     bool validateByConstraints(const FunctionDecl *FD) const {
81081ad6265SDimitry Andric       for (const SummaryCase &Case : Cases)
81181ad6265SDimitry Andric         for (const ValueConstraintPtr &Constraint : Case.getConstraints())
8125ffd83dbSDimitry Andric           if (!Constraint->checkValidity(FD))
8135ffd83dbSDimitry Andric             return false;
8145ffd83dbSDimitry Andric       for (const ValueConstraintPtr &Constraint : ArgConstraints)
8155ffd83dbSDimitry Andric         if (!Constraint->checkValidity(FD))
8165ffd83dbSDimitry Andric           return false;
8175ffd83dbSDimitry Andric       return true;
8185ffd83dbSDimitry Andric     }
8195ffd83dbSDimitry Andric   };
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric   // The map of all functions supported by the checker. It is initialized
8220b57cec5SDimitry Andric   // lazily, and it doesn't change after initialization.
8235ffd83dbSDimitry Andric   using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
8245ffd83dbSDimitry Andric   mutable FunctionSummaryMapType FunctionSummaryMap;
8250b57cec5SDimitry Andric 
826647cbc5dSDimitry Andric   const BugType BT_InvalidArg{this, "Function call with invalid argument"};
827fe6060f1SDimitry Andric   mutable bool SummariesInitialized = false;
8285ffd83dbSDimitry Andric 
8295ffd83dbSDimitry Andric   static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
8305ffd83dbSDimitry Andric     return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
8310b57cec5SDimitry Andric   }
83206c3fb27SDimitry Andric   static std::string getFunctionName(const CallEvent &Call) {
83306c3fb27SDimitry Andric     assert(Call.getDecl() &&
83406c3fb27SDimitry Andric            "Call was found by a summary, should have declaration");
83506c3fb27SDimitry Andric     return cast<NamedDecl>(Call.getDecl())->getNameAsString();
83606c3fb27SDimitry Andric   }
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric public:
8395ffd83dbSDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
8400b57cec5SDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
8410b57cec5SDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
8420b57cec5SDimitry Andric 
84306c3fb27SDimitry Andric   CheckerNameRef CheckName;
84406c3fb27SDimitry Andric   bool AddTestFunctions = false;
8455ffd83dbSDimitry Andric 
8465ffd83dbSDimitry Andric   bool DisplayLoadedSummaries = false;
8475ffd83dbSDimitry Andric   bool ModelPOSIX = false;
848349cc55cSDimitry Andric   bool ShouldAssumeControlledEnvironment = false;
8495ffd83dbSDimitry Andric 
8500b57cec5SDimitry Andric private:
851bdd1243dSDimitry Andric   std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,
8525ffd83dbSDimitry Andric                                              CheckerContext &C) const;
853bdd1243dSDimitry Andric   std::optional<Summary> findFunctionSummary(const CallEvent &Call,
8540b57cec5SDimitry Andric                                              CheckerContext &C) const;
8550b57cec5SDimitry Andric 
8565ffd83dbSDimitry Andric   void initFunctionSummaries(CheckerContext &C) const;
8575ffd83dbSDimitry Andric 
8585ffd83dbSDimitry Andric   void reportBug(const CallEvent &Call, ExplodedNode *N,
85906c3fb27SDimitry Andric                  const ValueConstraint *VC, const ValueConstraint *NegatedVC,
86006c3fb27SDimitry Andric                  const Summary &Summary, CheckerContext &C) const {
86106c3fb27SDimitry Andric     assert(Call.getDecl() &&
86206c3fb27SDimitry Andric            "Function found in summary must have a declaration available");
86306c3fb27SDimitry Andric     SmallString<256> Msg;
86406c3fb27SDimitry Andric     llvm::raw_svector_ostream MsgOs(Msg);
86506c3fb27SDimitry Andric 
86606c3fb27SDimitry Andric     MsgOs << "The ";
86706c3fb27SDimitry Andric     printArgDesc(VC->getArgNo(), MsgOs);
86806c3fb27SDimitry Andric     MsgOs << " to '" << getFunctionName(Call) << "' ";
86906c3fb27SDimitry Andric     bool ValuesPrinted =
87006c3fb27SDimitry Andric         NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);
87106c3fb27SDimitry Andric     if (ValuesPrinted)
87206c3fb27SDimitry Andric       MsgOs << " but ";
87306c3fb27SDimitry Andric     else
87406c3fb27SDimitry Andric       MsgOs << "is out of the accepted range; It ";
87506c3fb27SDimitry Andric     VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,
87606c3fb27SDimitry Andric                  MsgOs);
87706c3fb27SDimitry Andric     Msg[0] = toupper(Msg[0]);
878647cbc5dSDimitry Andric     auto R = std::make_unique<PathSensitiveBugReport>(BT_InvalidArg, Msg, N);
879fe6060f1SDimitry Andric 
88006c3fb27SDimitry Andric     for (ArgNo ArgN : VC->getArgsToTrack()) {
881fe6060f1SDimitry Andric       bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
88206c3fb27SDimitry Andric       R->markInteresting(Call.getArgSVal(ArgN));
88306c3fb27SDimitry Andric       // All tracked arguments are important, highlight them.
88406c3fb27SDimitry Andric       R->addRange(Call.getArgSourceRange(ArgN));
88506c3fb27SDimitry Andric     }
886fe6060f1SDimitry Andric 
8875ffd83dbSDimitry Andric     C.emitReport(std::move(R));
8885ffd83dbSDimitry Andric   }
88981ad6265SDimitry Andric 
89081ad6265SDimitry Andric   /// These are the errno constraints that can be passed to summary cases.
89181ad6265SDimitry Andric   /// One of these should fit for a single summary case.
89281ad6265SDimitry Andric   /// Usually if a failure return value exists for function, that function
89381ad6265SDimitry Andric   /// needs different cases for success and failure with different errno
89481ad6265SDimitry Andric   /// constraints (and different return value constraints).
895bdd1243dSDimitry Andric   const NoErrnoConstraint ErrnoUnchanged{};
896bdd1243dSDimitry Andric   const ResetErrnoConstraint ErrnoIrrelevant{};
897bdd1243dSDimitry Andric   const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
898bdd1243dSDimitry Andric   const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
899bdd1243dSDimitry Andric   const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
9000b57cec5SDimitry Andric };
9015ffd83dbSDimitry Andric 
90281ad6265SDimitry Andric int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
90381ad6265SDimitry Andric 
9045ffd83dbSDimitry Andric const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
9055ffd83dbSDimitry Andric     std::numeric_limits<ArgNo>::max();
9065ffd83dbSDimitry Andric 
907fe6060f1SDimitry Andric static BasicValueFactory &getBVF(ProgramStateRef State) {
908fe6060f1SDimitry Andric   ProgramStateManager &Mgr = State->getStateManager();
909fe6060f1SDimitry Andric   SValBuilder &SVB = Mgr.getSValBuilder();
910fe6060f1SDimitry Andric   return SVB.getBasicValueFactory();
911fe6060f1SDimitry Andric }
912fe6060f1SDimitry Andric 
91306c3fb27SDimitry Andric } // end of anonymous namespace
91406c3fb27SDimitry Andric 
91506c3fb27SDimitry Andric void StdLibraryFunctionsChecker::printArgDesc(
91606c3fb27SDimitry Andric     StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
91706c3fb27SDimitry Andric   Out << std::to_string(ArgN + 1);
91806c3fb27SDimitry Andric   Out << llvm::getOrdinalSuffix(ArgN + 1);
91906c3fb27SDimitry Andric   Out << " argument";
920fe6060f1SDimitry Andric }
921fe6060f1SDimitry Andric 
92206c3fb27SDimitry Andric void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
92306c3fb27SDimitry Andric                                                    ProgramStateRef State,
92406c3fb27SDimitry Andric                                                    const CallEvent &Call,
92506c3fb27SDimitry Andric                                                    llvm::raw_ostream &Out) {
92606c3fb27SDimitry Andric   if (const llvm::APSInt *Val =
92706c3fb27SDimitry Andric           State->getStateManager().getSValBuilder().getKnownValue(
92806c3fb27SDimitry Andric               State, getArgSVal(Call, ArgN)))
92906c3fb27SDimitry Andric     Out << " (which is " << *Val << ")";
93006c3fb27SDimitry Andric }
93106c3fb27SDimitry Andric 
93206c3fb27SDimitry Andric void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
93306c3fb27SDimitry Andric                                                        llvm::APSInt RMax,
93406c3fb27SDimitry Andric                                                        QualType ArgT,
93506c3fb27SDimitry Andric                                                        BasicValueFactory &BVF,
93606c3fb27SDimitry Andric                                                        llvm::raw_ostream &Out) {
93706c3fb27SDimitry Andric   if (RMin.isZero() && RMax.isZero())
93806c3fb27SDimitry Andric     Out << "zero";
93906c3fb27SDimitry Andric   else if (RMin == RMax)
94006c3fb27SDimitry Andric     Out << RMin;
94106c3fb27SDimitry Andric   else if (RMin == BVF.getMinValue(ArgT)) {
94206c3fb27SDimitry Andric     if (RMax == -1)
94306c3fb27SDimitry Andric       Out << "< 0";
94406c3fb27SDimitry Andric     else
94506c3fb27SDimitry Andric       Out << "<= " << RMax;
94606c3fb27SDimitry Andric   } else if (RMax == BVF.getMaxValue(ArgT)) {
94706c3fb27SDimitry Andric     if (RMin.isOne())
94806c3fb27SDimitry Andric       Out << "> 0";
94906c3fb27SDimitry Andric     else
95006c3fb27SDimitry Andric       Out << ">= " << RMin;
95106c3fb27SDimitry Andric   } else if (RMin.isNegative() == RMax.isNegative() &&
95206c3fb27SDimitry Andric              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
95306c3fb27SDimitry Andric     Out << RMin << " or " << RMax;
95406c3fb27SDimitry Andric   } else {
95506c3fb27SDimitry Andric     Out << "between " << RMin << " and " << RMax;
95606c3fb27SDimitry Andric   }
95706c3fb27SDimitry Andric }
95806c3fb27SDimitry Andric 
95906c3fb27SDimitry Andric void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
96006c3fb27SDimitry Andric                                                       llvm::APSInt RMax,
96106c3fb27SDimitry Andric                                                       QualType ArgT,
96206c3fb27SDimitry Andric                                                       BasicValueFactory &BVF,
96306c3fb27SDimitry Andric                                                       llvm::raw_ostream &Out) {
96406c3fb27SDimitry Andric   if (RMin.isZero() && RMax.isZero())
96506c3fb27SDimitry Andric     Out << "nonzero";
96606c3fb27SDimitry Andric   else if (RMin == RMax) {
96706c3fb27SDimitry Andric     Out << "not equal to " << RMin;
96806c3fb27SDimitry Andric   } else if (RMin == BVF.getMinValue(ArgT)) {
96906c3fb27SDimitry Andric     if (RMax == -1)
97006c3fb27SDimitry Andric       Out << ">= 0";
97106c3fb27SDimitry Andric     else
97206c3fb27SDimitry Andric       Out << "> " << RMax;
97306c3fb27SDimitry Andric   } else if (RMax == BVF.getMaxValue(ArgT)) {
97406c3fb27SDimitry Andric     if (RMin.isOne())
97506c3fb27SDimitry Andric       Out << "<= 0";
97606c3fb27SDimitry Andric     else
97706c3fb27SDimitry Andric       Out << "< " << RMin;
97806c3fb27SDimitry Andric   } else if (RMin.isNegative() == RMax.isNegative() &&
97906c3fb27SDimitry Andric              RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
98006c3fb27SDimitry Andric     Out << "not " << RMin << " and not " << RMax;
98106c3fb27SDimitry Andric   } else {
98206c3fb27SDimitry Andric     Out << "not between " << RMin << " and " << RMax;
98306c3fb27SDimitry Andric   }
98406c3fb27SDimitry Andric }
98506c3fb27SDimitry Andric 
98606c3fb27SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
98706c3fb27SDimitry Andric     BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
98806c3fb27SDimitry Andric   if (Ranges.empty())
98906c3fb27SDimitry Andric     return;
99006c3fb27SDimitry Andric 
99106c3fb27SDimitry Andric   for (auto [Start, End] : getRanges()) {
99206c3fb27SDimitry Andric     const llvm::APSInt &Min = BVF.getValue(Start, ArgT);
99306c3fb27SDimitry Andric     const llvm::APSInt &Max = BVF.getValue(End, ArgT);
99406c3fb27SDimitry Andric     assert(Min <= Max);
99506c3fb27SDimitry Andric     if (!F(Min, Max))
99606c3fb27SDimitry Andric       return;
99706c3fb27SDimitry Andric   }
99806c3fb27SDimitry Andric }
99906c3fb27SDimitry Andric 
100006c3fb27SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
100106c3fb27SDimitry Andric     BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
100206c3fb27SDimitry Andric   if (Ranges.empty())
100306c3fb27SDimitry Andric     return;
100406c3fb27SDimitry Andric 
100506c3fb27SDimitry Andric   const IntRangeVector &R = getRanges();
100606c3fb27SDimitry Andric   size_t E = R.size();
100706c3fb27SDimitry Andric 
100806c3fb27SDimitry Andric   const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);
100906c3fb27SDimitry Andric   const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);
101006c3fb27SDimitry Andric 
101106c3fb27SDimitry Andric   const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);
101206c3fb27SDimitry Andric   const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);
101306c3fb27SDimitry Andric 
101406c3fb27SDimitry Andric   // Iterate over the "holes" between intervals.
101506c3fb27SDimitry Andric   for (size_t I = 1; I != E; ++I) {
101606c3fb27SDimitry Andric     const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);
101706c3fb27SDimitry Andric     const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);
101806c3fb27SDimitry Andric     if (Min <= Max) {
101906c3fb27SDimitry Andric       if (!F(Min, Max))
102006c3fb27SDimitry Andric         return;
102106c3fb27SDimitry Andric     }
102206c3fb27SDimitry Andric   }
102306c3fb27SDimitry Andric   // Check the interval [T_MIN, min(R) - 1].
102406c3fb27SDimitry Andric   if (RangeLeft != PlusInf) {
102506c3fb27SDimitry Andric     assert(MinusInf <= RangeLeft);
102606c3fb27SDimitry Andric     if (!F(MinusInf, RangeLeft))
102706c3fb27SDimitry Andric       return;
102806c3fb27SDimitry Andric   }
102906c3fb27SDimitry Andric   // Check the interval [max(R) + 1, T_MAX],
103006c3fb27SDimitry Andric   if (RangeRight != MinusInf) {
103106c3fb27SDimitry Andric     assert(RangeRight <= PlusInf);
103206c3fb27SDimitry Andric     if (!F(RangeRight, PlusInf))
103306c3fb27SDimitry Andric       return;
103406c3fb27SDimitry Andric   }
103506c3fb27SDimitry Andric }
103606c3fb27SDimitry Andric 
103706c3fb27SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
103806c3fb27SDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
103906c3fb27SDimitry Andric     CheckerContext &C) const {
104006c3fb27SDimitry Andric   ConstraintManager &CM = C.getConstraintManager();
104106c3fb27SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
104206c3fb27SDimitry Andric   QualType T = Summary.getArgType(getArgNo());
104306c3fb27SDimitry Andric 
104406c3fb27SDimitry Andric   if (auto N = V.getAs<NonLoc>()) {
104506c3fb27SDimitry Andric     auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,
104606c3fb27SDimitry Andric                                    const llvm::APSInt &Max) {
104706c3fb27SDimitry Andric       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
104806c3fb27SDimitry Andric       return static_cast<bool>(State);
104906c3fb27SDimitry Andric     };
105006c3fb27SDimitry Andric     // "OutOfRange R" is handled by excluding all ranges in R.
105106c3fb27SDimitry Andric     // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
105206c3fb27SDimitry Andric     applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,
105306c3fb27SDimitry Andric                  ExcludeRangeFromArg);
105406c3fb27SDimitry Andric   }
105506c3fb27SDimitry Andric 
105606c3fb27SDimitry Andric   return State;
105706c3fb27SDimitry Andric }
105806c3fb27SDimitry Andric 
105906c3fb27SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::describe(
106006c3fb27SDimitry Andric     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
106106c3fb27SDimitry Andric     const Summary &Summary, llvm::raw_ostream &Out) const {
1062fe6060f1SDimitry Andric 
1063fe6060f1SDimitry Andric   BasicValueFactory &BVF = getBVF(State);
1064fe6060f1SDimitry Andric   QualType T = Summary.getArgType(getArgNo());
1065fe6060f1SDimitry Andric 
106606c3fb27SDimitry Andric   Out << ((DK == Violation) ? "should be " : "is ");
106706c3fb27SDimitry Andric   if (!Description.empty()) {
106806c3fb27SDimitry Andric     Out << Description;
106906c3fb27SDimitry Andric   } else {
1070fe6060f1SDimitry Andric     unsigned I = Ranges.size();
107106c3fb27SDimitry Andric     if (Kind == WithinRange) {
1072fe6060f1SDimitry Andric       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
107306c3fb27SDimitry Andric         appendInsideRangeDesc(BVF.getValue(R.first, T),
107406c3fb27SDimitry Andric                               BVF.getValue(R.second, T), T, BVF, Out);
1075fe6060f1SDimitry Andric         if (--I > 0)
107606c3fb27SDimitry Andric           Out << " or ";
1077fe6060f1SDimitry Andric       }
107806c3fb27SDimitry Andric     } else {
107906c3fb27SDimitry Andric       for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
108006c3fb27SDimitry Andric         appendOutOfRangeDesc(BVF.getValue(R.first, T),
108106c3fb27SDimitry Andric                              BVF.getValue(R.second, T), T, BVF, Out);
108206c3fb27SDimitry Andric         if (--I > 0)
108306c3fb27SDimitry Andric           Out << " and ";
108406c3fb27SDimitry Andric       }
108506c3fb27SDimitry Andric     }
108606c3fb27SDimitry Andric   }
1087fe6060f1SDimitry Andric }
1088fe6060f1SDimitry Andric 
108906c3fb27SDimitry Andric bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
109006c3fb27SDimitry Andric     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
109106c3fb27SDimitry Andric     llvm::raw_ostream &Out) const {
109206c3fb27SDimitry Andric   unsigned int NRanges = 0;
109306c3fb27SDimitry Andric   bool HaveAllRanges = true;
10940b57cec5SDimitry Andric 
10950b57cec5SDimitry Andric   ProgramStateManager &Mgr = State->getStateManager();
109606c3fb27SDimitry Andric   BasicValueFactory &BVF = Mgr.getSValBuilder().getBasicValueFactory();
10970b57cec5SDimitry Andric   ConstraintManager &CM = Mgr.getConstraintManager();
10980b57cec5SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
10990b57cec5SDimitry Andric 
11000b57cec5SDimitry Andric   if (auto N = V.getAs<NonLoc>()) {
110106c3fb27SDimitry Andric     if (const llvm::APSInt *Int = N->getAsInteger()) {
110206c3fb27SDimitry Andric       Out << "is ";
110306c3fb27SDimitry Andric       Out << *Int;
110406c3fb27SDimitry Andric       return true;
11050b57cec5SDimitry Andric     }
11065ffd83dbSDimitry Andric     QualType T = Summary.getArgType(getArgNo());
110706c3fb27SDimitry Andric     SmallString<128> MoreInfo;
110806c3fb27SDimitry Andric     llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
110906c3fb27SDimitry Andric     auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
111006c3fb27SDimitry Andric       if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
111106c3fb27SDimitry Andric         if (NRanges > 0)
111206c3fb27SDimitry Andric           MoreInfoOs << " or ";
111306c3fb27SDimitry Andric         appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
111406c3fb27SDimitry Andric         ++NRanges;
111506c3fb27SDimitry Andric       } else {
111606c3fb27SDimitry Andric         HaveAllRanges = false;
11170b57cec5SDimitry Andric       }
111806c3fb27SDimitry Andric       return true;
111906c3fb27SDimitry Andric     };
11200b57cec5SDimitry Andric 
112106c3fb27SDimitry Andric     applyOnRange(Kind, BVF, T, ApplyF);
112206c3fb27SDimitry Andric     assert(NRanges > 0);
112306c3fb27SDimitry Andric     if (!HaveAllRanges || NRanges == 1) {
112406c3fb27SDimitry Andric       Out << "is ";
112506c3fb27SDimitry Andric       Out << MoreInfo;
112606c3fb27SDimitry Andric       return true;
11270b57cec5SDimitry Andric     }
11280b57cec5SDimitry Andric   }
112906c3fb27SDimitry Andric   return false;
11300b57cec5SDimitry Andric }
11310b57cec5SDimitry Andric 
11325ffd83dbSDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
11335ffd83dbSDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
11345ffd83dbSDimitry Andric     CheckerContext &C) const {
11350b57cec5SDimitry Andric 
11360b57cec5SDimitry Andric   ProgramStateManager &Mgr = State->getStateManager();
11370b57cec5SDimitry Andric   SValBuilder &SVB = Mgr.getSValBuilder();
11380b57cec5SDimitry Andric   QualType CondT = SVB.getConditionType();
11395ffd83dbSDimitry Andric   QualType T = Summary.getArgType(getArgNo());
11400b57cec5SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
11410b57cec5SDimitry Andric 
11420b57cec5SDimitry Andric   BinaryOperator::Opcode Op = getOpcode();
11435ffd83dbSDimitry Andric   ArgNo OtherArg = getOtherArgNo();
11440b57cec5SDimitry Andric   SVal OtherV = getArgSVal(Call, OtherArg);
11455ffd83dbSDimitry Andric   QualType OtherT = Summary.getArgType(OtherArg);
11460b57cec5SDimitry Andric   // Note: we avoid integral promotion for comparison.
11470b57cec5SDimitry Andric   OtherV = SVB.evalCast(OtherV, T, OtherT);
11480b57cec5SDimitry Andric   if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
11490b57cec5SDimitry Andric                        .getAs<DefinedOrUnknownSVal>())
11500b57cec5SDimitry Andric     State = State->assume(*CompV, true);
11510b57cec5SDimitry Andric   return State;
11520b57cec5SDimitry Andric }
11530b57cec5SDimitry Andric 
115406c3fb27SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::NotNullConstraint::apply(
115506c3fb27SDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
115606c3fb27SDimitry Andric     CheckerContext &C) const {
115706c3fb27SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
115806c3fb27SDimitry Andric   if (V.isUndef())
115906c3fb27SDimitry Andric     return State;
116006c3fb27SDimitry Andric 
116106c3fb27SDimitry Andric   DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
116206c3fb27SDimitry Andric   if (!isa<Loc>(L))
116306c3fb27SDimitry Andric     return State;
116406c3fb27SDimitry Andric 
116506c3fb27SDimitry Andric   return State->assume(L, CannotBeNull);
116606c3fb27SDimitry Andric }
116706c3fb27SDimitry Andric 
116806c3fb27SDimitry Andric void StdLibraryFunctionsChecker::NotNullConstraint::describe(
116906c3fb27SDimitry Andric     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
117006c3fb27SDimitry Andric     const Summary &Summary, llvm::raw_ostream &Out) const {
117106c3fb27SDimitry Andric   assert(CannotBeNull &&
117206c3fb27SDimitry Andric          "Describe should not be used when the value must be NULL");
117306c3fb27SDimitry Andric   if (DK == Violation)
117406c3fb27SDimitry Andric     Out << "should not be NULL";
117506c3fb27SDimitry Andric   else
117606c3fb27SDimitry Andric     Out << "is not NULL";
117706c3fb27SDimitry Andric }
117806c3fb27SDimitry Andric 
117906c3fb27SDimitry Andric bool StdLibraryFunctionsChecker::NotNullConstraint::describeArgumentValue(
118006c3fb27SDimitry Andric     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
118106c3fb27SDimitry Andric     llvm::raw_ostream &Out) const {
118206c3fb27SDimitry Andric   assert(!CannotBeNull && "This function is used when the value is NULL");
118306c3fb27SDimitry Andric   Out << "is NULL";
118406c3fb27SDimitry Andric   return true;
118506c3fb27SDimitry Andric }
118606c3fb27SDimitry Andric 
118706c3fb27SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::NotNullBufferConstraint::apply(
118806c3fb27SDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
118906c3fb27SDimitry Andric     CheckerContext &C) const {
119006c3fb27SDimitry Andric   SVal V = getArgSVal(Call, getArgNo());
119106c3fb27SDimitry Andric   if (V.isUndef())
119206c3fb27SDimitry Andric     return State;
119306c3fb27SDimitry Andric   DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
119406c3fb27SDimitry Andric   if (!isa<Loc>(L))
119506c3fb27SDimitry Andric     return State;
119606c3fb27SDimitry Andric 
119706c3fb27SDimitry Andric   std::optional<DefinedOrUnknownSVal> SizeArg1 =
119806c3fb27SDimitry Andric       getArgSVal(Call, SizeArg1N).getAs<DefinedOrUnknownSVal>();
119906c3fb27SDimitry Andric   std::optional<DefinedOrUnknownSVal> SizeArg2;
120006c3fb27SDimitry Andric   if (SizeArg2N)
120106c3fb27SDimitry Andric     SizeArg2 = getArgSVal(Call, *SizeArg2N).getAs<DefinedOrUnknownSVal>();
120206c3fb27SDimitry Andric 
120306c3fb27SDimitry Andric   auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {
120406c3fb27SDimitry Andric     if (!Val)
120506c3fb27SDimitry Andric       return false;
120606c3fb27SDimitry Andric     auto [IsNonNull, IsNull] = State->assume(*Val);
120706c3fb27SDimitry Andric     return IsNull && !IsNonNull;
120806c3fb27SDimitry Andric   };
120906c3fb27SDimitry Andric 
121006c3fb27SDimitry Andric   if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))
121106c3fb27SDimitry Andric     return State;
121206c3fb27SDimitry Andric 
121306c3fb27SDimitry Andric   return State->assume(L, CannotBeNull);
121406c3fb27SDimitry Andric }
121506c3fb27SDimitry Andric 
121606c3fb27SDimitry Andric void StdLibraryFunctionsChecker::NotNullBufferConstraint::describe(
121706c3fb27SDimitry Andric     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
121806c3fb27SDimitry Andric     const Summary &Summary, llvm::raw_ostream &Out) const {
121906c3fb27SDimitry Andric   assert(CannotBeNull &&
122006c3fb27SDimitry Andric          "Describe should not be used when the value must be NULL");
122106c3fb27SDimitry Andric   if (DK == Violation)
122206c3fb27SDimitry Andric     Out << "should not be NULL";
122306c3fb27SDimitry Andric   else
122406c3fb27SDimitry Andric     Out << "is not NULL";
122506c3fb27SDimitry Andric }
122606c3fb27SDimitry Andric 
122706c3fb27SDimitry Andric bool StdLibraryFunctionsChecker::NotNullBufferConstraint::describeArgumentValue(
122806c3fb27SDimitry Andric     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
122906c3fb27SDimitry Andric     llvm::raw_ostream &Out) const {
123006c3fb27SDimitry Andric   assert(!CannotBeNull && "This function is used when the value is NULL");
123106c3fb27SDimitry Andric   Out << "is NULL";
123206c3fb27SDimitry Andric   return true;
123306c3fb27SDimitry Andric }
123406c3fb27SDimitry Andric 
123506c3fb27SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
123606c3fb27SDimitry Andric     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
123706c3fb27SDimitry Andric     CheckerContext &C) const {
123806c3fb27SDimitry Andric   SValBuilder &SvalBuilder = C.getSValBuilder();
123906c3fb27SDimitry Andric   // The buffer argument.
124006c3fb27SDimitry Andric   SVal BufV = getArgSVal(Call, getArgNo());
124106c3fb27SDimitry Andric 
124206c3fb27SDimitry Andric   // Get the size constraint.
124306c3fb27SDimitry Andric   const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
124406c3fb27SDimitry Andric     if (ConcreteSize) {
124506c3fb27SDimitry Andric       return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
124606c3fb27SDimitry Andric     }
124706c3fb27SDimitry Andric     assert(SizeArgN && "The constraint must be either a concrete value or "
124806c3fb27SDimitry Andric                        "encoded in an argument.");
124906c3fb27SDimitry Andric     // The size argument.
125006c3fb27SDimitry Andric     SVal SizeV = getArgSVal(Call, *SizeArgN);
125106c3fb27SDimitry Andric     // Multiply with another argument if given.
125206c3fb27SDimitry Andric     if (SizeMultiplierArgN) {
125306c3fb27SDimitry Andric       SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
125406c3fb27SDimitry Andric       SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
125506c3fb27SDimitry Andric                                     Summary.getArgType(*SizeArgN));
125606c3fb27SDimitry Andric     }
125706c3fb27SDimitry Andric     return SizeV;
125806c3fb27SDimitry Andric   }();
125906c3fb27SDimitry Andric 
126006c3fb27SDimitry Andric   // The dynamic size of the buffer argument, got from the analyzer engine.
126106c3fb27SDimitry Andric   SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
126206c3fb27SDimitry Andric 
126306c3fb27SDimitry Andric   SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
126406c3fb27SDimitry Andric                                         SvalBuilder.getContext().BoolTy);
126506c3fb27SDimitry Andric   if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
126606c3fb27SDimitry Andric     return State->assume(*F, true);
126706c3fb27SDimitry Andric 
126806c3fb27SDimitry Andric   // We can get here only if the size argument or the dynamic size is
126906c3fb27SDimitry Andric   // undefined. But the dynamic size should never be undefined, only
127006c3fb27SDimitry Andric   // unknown. So, here, the size of the argument is undefined, i.e. we
127106c3fb27SDimitry Andric   // cannot apply the constraint. Actually, other checkers like
127206c3fb27SDimitry Andric   // CallAndMessage should catch this situation earlier, because we call a
127306c3fb27SDimitry Andric   // function with an uninitialized argument.
127406c3fb27SDimitry Andric   llvm_unreachable("Size argument or the dynamic size is Undefined");
127506c3fb27SDimitry Andric }
127606c3fb27SDimitry Andric 
127706c3fb27SDimitry Andric void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
127806c3fb27SDimitry Andric     DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
127906c3fb27SDimitry Andric     const Summary &Summary, llvm::raw_ostream &Out) const {
128006c3fb27SDimitry Andric   Out << ((DK == Violation) ? "should be " : "is ");
128106c3fb27SDimitry Andric   Out << "a buffer with size equal to or greater than ";
128206c3fb27SDimitry Andric   if (ConcreteSize) {
128306c3fb27SDimitry Andric     Out << *ConcreteSize;
128406c3fb27SDimitry Andric   } else if (SizeArgN) {
128506c3fb27SDimitry Andric     Out << "the value of the ";
128606c3fb27SDimitry Andric     printArgDesc(*SizeArgN, Out);
128706c3fb27SDimitry Andric     printArgValueInfo(*SizeArgN, State, Call, Out);
128806c3fb27SDimitry Andric     if (SizeMultiplierArgN) {
128906c3fb27SDimitry Andric       Out << " times the ";
129006c3fb27SDimitry Andric       printArgDesc(*SizeMultiplierArgN, Out);
129106c3fb27SDimitry Andric       printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
129206c3fb27SDimitry Andric     }
129306c3fb27SDimitry Andric   }
129406c3fb27SDimitry Andric }
129506c3fb27SDimitry Andric 
129606c3fb27SDimitry Andric bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
129706c3fb27SDimitry Andric     const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
129806c3fb27SDimitry Andric     llvm::raw_ostream &Out) const {
129906c3fb27SDimitry Andric   SVal BufV = getArgSVal(Call, getArgNo());
130006c3fb27SDimitry Andric   SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
130106c3fb27SDimitry Andric   if (const llvm::APSInt *Val =
130206c3fb27SDimitry Andric           State->getStateManager().getSValBuilder().getKnownValue(State,
130306c3fb27SDimitry Andric                                                                   BufDynSize)) {
130406c3fb27SDimitry Andric     Out << "is a buffer with size " << *Val;
130506c3fb27SDimitry Andric     return true;
130606c3fb27SDimitry Andric   }
130706c3fb27SDimitry Andric   return false;
130806c3fb27SDimitry Andric }
130906c3fb27SDimitry Andric 
13105ffd83dbSDimitry Andric void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
13110b57cec5SDimitry Andric                                               CheckerContext &C) const {
1312bdd1243dSDimitry Andric   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
13130b57cec5SDimitry Andric   if (!FoundSummary)
13140b57cec5SDimitry Andric     return;
13150b57cec5SDimitry Andric 
13165ffd83dbSDimitry Andric   const Summary &Summary = *FoundSummary;
13170b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
13180b57cec5SDimitry Andric 
13190b57cec5SDimitry Andric   ProgramStateRef NewState = State;
1320bdd1243dSDimitry Andric   ExplodedNode *NewNode = C.getPredecessor();
13215ffd83dbSDimitry Andric   for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
132206c3fb27SDimitry Andric     ValueConstraintPtr NegatedConstraint = Constraint->negate();
13235ffd83dbSDimitry Andric     ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
13245ffd83dbSDimitry Andric     ProgramStateRef FailureSt =
132506c3fb27SDimitry Andric         NegatedConstraint->apply(NewState, Call, Summary, C);
13265ffd83dbSDimitry Andric     // The argument constraint is not satisfied.
13275ffd83dbSDimitry Andric     if (FailureSt && !SuccessSt) {
132806c3fb27SDimitry Andric       if (ExplodedNode *N = C.generateErrorNode(State, NewNode))
132906c3fb27SDimitry Andric         reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,
133006c3fb27SDimitry Andric                   C);
13315ffd83dbSDimitry Andric       break;
1332bdd1243dSDimitry Andric     }
13335ffd83dbSDimitry Andric     // We will apply the constraint even if we cannot reason about the
13345ffd83dbSDimitry Andric     // argument. This means both SuccessSt and FailureSt can be true. If we
13355ffd83dbSDimitry Andric     // weren't applying the constraint that would mean that symbolic
13365ffd83dbSDimitry Andric     // execution continues on a code whose behaviour is undefined.
13375ffd83dbSDimitry Andric     assert(SuccessSt);
13385ffd83dbSDimitry Andric     NewState = SuccessSt;
1339bdd1243dSDimitry Andric     if (NewState != State) {
134006c3fb27SDimitry Andric       SmallString<128> Msg;
134106c3fb27SDimitry Andric       llvm::raw_svector_ostream Os(Msg);
134206c3fb27SDimitry Andric       Os << "Assuming that the ";
134306c3fb27SDimitry Andric       printArgDesc(Constraint->getArgNo(), Os);
134406c3fb27SDimitry Andric       Os << " to '";
134506c3fb27SDimitry Andric       Os << getFunctionName(Call);
134606c3fb27SDimitry Andric       Os << "' ";
134706c3fb27SDimitry Andric       Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
134806c3fb27SDimitry Andric                            Os);
1349bdd1243dSDimitry Andric       const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
1350bdd1243dSDimitry Andric       NewNode = C.addTransition(
1351bdd1243dSDimitry Andric           NewState, NewNode,
1352bdd1243dSDimitry Andric           C.getNoteTag([Msg = std::move(Msg), ArgSVal](
1353bdd1243dSDimitry Andric                            PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1354bdd1243dSDimitry Andric             if (BR.isInteresting(ArgSVal))
1355bdd1243dSDimitry Andric               OS << Msg;
1356bdd1243dSDimitry Andric           }));
13575ffd83dbSDimitry Andric     }
13585ffd83dbSDimitry Andric   }
13595ffd83dbSDimitry Andric }
13605ffd83dbSDimitry Andric 
13615ffd83dbSDimitry Andric void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
13625ffd83dbSDimitry Andric                                                CheckerContext &C) const {
1363bdd1243dSDimitry Andric   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
13645ffd83dbSDimitry Andric   if (!FoundSummary)
13655ffd83dbSDimitry Andric     return;
13665ffd83dbSDimitry Andric 
13675ffd83dbSDimitry Andric   // Now apply the constraints.
13685ffd83dbSDimitry Andric   const Summary &Summary = *FoundSummary;
13695ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
137006c3fb27SDimitry Andric   ExplodedNode *Node = C.getPredecessor();
13715ffd83dbSDimitry Andric 
13725ffd83dbSDimitry Andric   // Apply case/branch specifications.
137381ad6265SDimitry Andric   for (const SummaryCase &Case : Summary.getCases()) {
13745ffd83dbSDimitry Andric     ProgramStateRef NewState = State;
137581ad6265SDimitry Andric     for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
13765ffd83dbSDimitry Andric       NewState = Constraint->apply(NewState, Call, Summary, C);
13770b57cec5SDimitry Andric       if (!NewState)
13780b57cec5SDimitry Andric         break;
13790b57cec5SDimitry Andric     }
13800b57cec5SDimitry Andric 
138181ad6265SDimitry Andric     if (NewState)
138281ad6265SDimitry Andric       NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
138381ad6265SDimitry Andric 
138406c3fb27SDimitry Andric     if (!NewState)
138506c3fb27SDimitry Andric       continue;
138606c3fb27SDimitry Andric 
13875f757f3fSDimitry Andric     // Here it's possible that NewState == State, e.g. when other checkers
13885f757f3fSDimitry Andric     // already applied the same constraints (or stricter ones).
138906c3fb27SDimitry Andric     // Still add these note tags, the other checker should add only its
139006c3fb27SDimitry Andric     // specialized note tags. These general note tags are handled always by
139106c3fb27SDimitry Andric     // StdLibraryFunctionsChecker.
13925f757f3fSDimitry Andric 
139306c3fb27SDimitry Andric     ExplodedNode *Pred = Node;
13945f757f3fSDimitry Andric     DeclarationName FunctionName =
13955f757f3fSDimitry Andric         cast<NamedDecl>(Call.getDecl())->getDeclName();
13965f757f3fSDimitry Andric 
13975f757f3fSDimitry Andric     std::string ErrnoNote = Case.getErrnoConstraint().describe(C);
13985f757f3fSDimitry Andric     std::string CaseNote;
13995f757f3fSDimitry Andric     if (Case.getNote().empty()) {
14005f757f3fSDimitry Andric       if (!ErrnoNote.empty())
14015f757f3fSDimitry Andric         ErrnoNote =
14025f757f3fSDimitry Andric             llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);
14035f757f3fSDimitry Andric     } else {
14045f757f3fSDimitry Andric       CaseNote = llvm::formatv(Case.getNote().str().c_str(), FunctionName);
14055f757f3fSDimitry Andric     }
140606c3fb27SDimitry Andric     const SVal RV = Call.getReturnValue();
14075f757f3fSDimitry Andric 
140806c3fb27SDimitry Andric     if (Summary.getInvalidationKd() == EvalCallAsPure) {
14095f757f3fSDimitry Andric       // Do not expect that errno is interesting (the "pure" functions do not
14105f757f3fSDimitry Andric       // affect it).
14115f757f3fSDimitry Andric       if (!CaseNote.empty()) {
141281ad6265SDimitry Andric         const NoteTag *Tag = C.getNoteTag(
14135f757f3fSDimitry Andric             [Node, CaseNote, RV](PathSensitiveBugReport &BR) -> std::string {
141406c3fb27SDimitry Andric               // Try to omit the note if we know in advance which branch is
141506c3fb27SDimitry Andric               // taken (this means, only one branch exists).
141606c3fb27SDimitry Andric               // This check is performed inside the lambda, after other
141706c3fb27SDimitry Andric               // (or this) checkers had a chance to add other successors.
141806c3fb27SDimitry Andric               // Dereferencing the saved node object is valid because it's part
141906c3fb27SDimitry Andric               // of a bug report call sequence.
142006c3fb27SDimitry Andric               // FIXME: This check is not exact. We may be here after a state
142106c3fb27SDimitry Andric               // split that was performed by another checker (and can not find
142206c3fb27SDimitry Andric               // the successors). This is why this check is only used in the
142306c3fb27SDimitry Andric               // EvalCallAsPure case.
142406c3fb27SDimitry Andric               if (BR.isInteresting(RV) && Node->succ_size() > 1)
14255f757f3fSDimitry Andric                 return CaseNote;
142606c3fb27SDimitry Andric               return "";
142706c3fb27SDimitry Andric             });
142806c3fb27SDimitry Andric         Pred = C.addTransition(NewState, Pred, Tag);
14295f757f3fSDimitry Andric       }
143006c3fb27SDimitry Andric     } else {
14315f757f3fSDimitry Andric       if (!CaseNote.empty() || !ErrnoNote.empty()) {
143206c3fb27SDimitry Andric         const NoteTag *Tag =
14335f757f3fSDimitry Andric             C.getNoteTag([CaseNote, ErrnoNote,
14345f757f3fSDimitry Andric                           RV](PathSensitiveBugReport &BR) -> std::string {
14355f757f3fSDimitry Andric               // If 'errno' is interesting, show the user a note about the case
14365f757f3fSDimitry Andric               // (what happened at the function call) and about how 'errno'
14375f757f3fSDimitry Andric               // causes the problem. ErrnoChecker sets the errno (but not RV) to
14385f757f3fSDimitry Andric               // interesting.
14395f757f3fSDimitry Andric               // If only the return value is interesting, show only the case
14405f757f3fSDimitry Andric               // note.
14415f757f3fSDimitry Andric               std::optional<Loc> ErrnoLoc =
14425f757f3fSDimitry Andric                   errno_modeling::getErrnoLoc(BR.getErrorNode()->getState());
14435f757f3fSDimitry Andric               bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&
14445f757f3fSDimitry Andric                                     BR.isInteresting(ErrnoLoc->getAsRegion());
14455f757f3fSDimitry Andric               if (ErrnoImportant) {
14465f757f3fSDimitry Andric                 BR.markNotInteresting(ErrnoLoc->getAsRegion());
14475f757f3fSDimitry Andric                 if (CaseNote.empty())
14485f757f3fSDimitry Andric                   return ErrnoNote;
14495f757f3fSDimitry Andric                 return llvm::formatv("{0}; {1}", CaseNote, ErrnoNote);
14505f757f3fSDimitry Andric               } else {
145106c3fb27SDimitry Andric                 if (BR.isInteresting(RV))
14525f757f3fSDimitry Andric                   return CaseNote;
14535f757f3fSDimitry Andric               }
145406c3fb27SDimitry Andric               return "";
145506c3fb27SDimitry Andric             });
145606c3fb27SDimitry Andric         Pred = C.addTransition(NewState, Pred, Tag);
145781ad6265SDimitry Andric       }
145806c3fb27SDimitry Andric     }
145906c3fb27SDimitry Andric 
14605f757f3fSDimitry Andric     // Add the transition if no note tag was added.
146106c3fb27SDimitry Andric     if (Pred == Node && NewState != State)
146206c3fb27SDimitry Andric       C.addTransition(NewState);
14630b57cec5SDimitry Andric   }
14640b57cec5SDimitry Andric }
14650b57cec5SDimitry Andric 
14660b57cec5SDimitry Andric bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
14670b57cec5SDimitry Andric                                           CheckerContext &C) const {
1468bdd1243dSDimitry Andric   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
14690b57cec5SDimitry Andric   if (!FoundSummary)
14700b57cec5SDimitry Andric     return false;
14710b57cec5SDimitry Andric 
14725ffd83dbSDimitry Andric   const Summary &Summary = *FoundSummary;
14735ffd83dbSDimitry Andric   switch (Summary.getInvalidationKd()) {
14740b57cec5SDimitry Andric   case EvalCallAsPure: {
14750b57cec5SDimitry Andric     ProgramStateRef State = C.getState();
14760b57cec5SDimitry Andric     const LocationContext *LC = C.getLocationContext();
1477e8d8bef9SDimitry Andric     const auto *CE = cast<CallExpr>(Call.getOriginExpr());
14780b57cec5SDimitry Andric     SVal V = C.getSValBuilder().conjureSymbolVal(
14790b57cec5SDimitry Andric         CE, LC, CE->getType().getCanonicalType(), C.blockCount());
14800b57cec5SDimitry Andric     State = State->BindExpr(CE, LC, V);
148181ad6265SDimitry Andric 
14820b57cec5SDimitry Andric     C.addTransition(State);
148381ad6265SDimitry Andric 
14840b57cec5SDimitry Andric     return true;
14850b57cec5SDimitry Andric   }
14860b57cec5SDimitry Andric   case NoEvalCall:
14870b57cec5SDimitry Andric     // Summary tells us to avoid performing eval::Call. The function is possibly
14880b57cec5SDimitry Andric     // evaluated by another checker, or evaluated conservatively.
14890b57cec5SDimitry Andric     return false;
14900b57cec5SDimitry Andric   }
14910b57cec5SDimitry Andric   llvm_unreachable("Unknown invalidation kind!");
14920b57cec5SDimitry Andric }
14930b57cec5SDimitry Andric 
14945ffd83dbSDimitry Andric bool StdLibraryFunctionsChecker::Signature::matches(
14955ffd83dbSDimitry Andric     const FunctionDecl *FD) const {
1496e8d8bef9SDimitry Andric   assert(!isInvalid());
1497e8d8bef9SDimitry Andric   // Check the number of arguments.
14985ffd83dbSDimitry Andric   if (FD->param_size() != ArgTys.size())
14990b57cec5SDimitry Andric     return false;
15000b57cec5SDimitry Andric 
1501e8d8bef9SDimitry Andric   // The "restrict" keyword is illegal in C++, however, many libc
1502e8d8bef9SDimitry Andric   // implementations use the "__restrict" compiler intrinsic in functions
1503e8d8bef9SDimitry Andric   // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1504e8d8bef9SDimitry Andric   // even in C++.
1505e8d8bef9SDimitry Andric   // In case of any non-C99 languages, we don't want to match based on the
1506e8d8bef9SDimitry Andric   // restrict qualifier because we cannot know if the given libc implementation
1507e8d8bef9SDimitry Andric   // qualifies the paramter type or not.
1508e8d8bef9SDimitry Andric   auto RemoveRestrict = [&FD](QualType T) {
1509e8d8bef9SDimitry Andric     if (!FD->getASTContext().getLangOpts().C99)
1510e8d8bef9SDimitry Andric       T.removeLocalRestrict();
1511e8d8bef9SDimitry Andric     return T;
1512e8d8bef9SDimitry Andric   };
15130b57cec5SDimitry Andric 
1514e8d8bef9SDimitry Andric   // Check the return type.
1515e8d8bef9SDimitry Andric   if (!isIrrelevant(RetTy)) {
1516e8d8bef9SDimitry Andric     QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1517e8d8bef9SDimitry Andric     if (RetTy != FDRetTy)
1518e8d8bef9SDimitry Andric       return false;
1519e8d8bef9SDimitry Andric   }
1520e8d8bef9SDimitry Andric 
1521e8d8bef9SDimitry Andric   // Check the argument types.
152206c3fb27SDimitry Andric   for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {
15235ffd83dbSDimitry Andric     if (isIrrelevant(ArgTy))
15240b57cec5SDimitry Andric       continue;
1525e8d8bef9SDimitry Andric     QualType FDArgTy =
152606c3fb27SDimitry Andric         RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());
1527e8d8bef9SDimitry Andric     if (ArgTy != FDArgTy)
15280b57cec5SDimitry Andric       return false;
15290b57cec5SDimitry Andric   }
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric   return true;
15320b57cec5SDimitry Andric }
15330b57cec5SDimitry Andric 
1534bdd1243dSDimitry Andric std::optional<StdLibraryFunctionsChecker::Summary>
15350b57cec5SDimitry Andric StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
15360b57cec5SDimitry Andric                                                 CheckerContext &C) const {
15370b57cec5SDimitry Andric   if (!FD)
1538bdd1243dSDimitry Andric     return std::nullopt;
15390b57cec5SDimitry Andric 
15405ffd83dbSDimitry Andric   initFunctionSummaries(C);
15410b57cec5SDimitry Andric 
15425ffd83dbSDimitry Andric   auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
15430b57cec5SDimitry Andric   if (FSMI == FunctionSummaryMap.end())
1544bdd1243dSDimitry Andric     return std::nullopt;
15455ffd83dbSDimitry Andric   return FSMI->second;
15465ffd83dbSDimitry Andric }
15470b57cec5SDimitry Andric 
1548bdd1243dSDimitry Andric std::optional<StdLibraryFunctionsChecker::Summary>
15495ffd83dbSDimitry Andric StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
15505ffd83dbSDimitry Andric                                                 CheckerContext &C) const {
15515ffd83dbSDimitry Andric   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
15525ffd83dbSDimitry Andric   if (!FD)
1553bdd1243dSDimitry Andric     return std::nullopt;
15545ffd83dbSDimitry Andric   return findFunctionSummary(FD, C);
15555ffd83dbSDimitry Andric }
15560b57cec5SDimitry Andric 
1557e8d8bef9SDimitry Andric void StdLibraryFunctionsChecker::initFunctionSummaries(
1558e8d8bef9SDimitry Andric     CheckerContext &C) const {
1559fe6060f1SDimitry Andric   if (SummariesInitialized)
1560e8d8bef9SDimitry Andric     return;
156106c3fb27SDimitry Andric   SummariesInitialized = true;
1562e8d8bef9SDimitry Andric 
1563e8d8bef9SDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
1564e8d8bef9SDimitry Andric   BasicValueFactory &BVF = SVB.getBasicValueFactory();
1565e8d8bef9SDimitry Andric   const ASTContext &ACtx = BVF.getContext();
156606c3fb27SDimitry Andric   Preprocessor &PP = C.getPreprocessor();
1567e8d8bef9SDimitry Andric 
1568e8d8bef9SDimitry Andric   // Helper class to lookup a type by its name.
1569e8d8bef9SDimitry Andric   class LookupType {
1570e8d8bef9SDimitry Andric     const ASTContext &ACtx;
1571e8d8bef9SDimitry Andric 
1572e8d8bef9SDimitry Andric   public:
1573e8d8bef9SDimitry Andric     LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1574e8d8bef9SDimitry Andric 
1575e8d8bef9SDimitry Andric     // Find the type. If not found then the optional is not set.
1576bdd1243dSDimitry Andric     std::optional<QualType> operator()(StringRef Name) {
15775ffd83dbSDimitry Andric       IdentifierInfo &II = ACtx.Idents.get(Name);
15785ffd83dbSDimitry Andric       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1579fe6060f1SDimitry Andric       if (LookupRes.empty())
1580bdd1243dSDimitry Andric         return std::nullopt;
15815ffd83dbSDimitry Andric 
15825ffd83dbSDimitry Andric       // Prioritze typedef declarations.
15835ffd83dbSDimitry Andric       // This is needed in case of C struct typedefs. E.g.:
15845ffd83dbSDimitry Andric       //   typedef struct FILE FILE;
1585e8d8bef9SDimitry Andric       // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1586e8d8bef9SDimitry Andric       // and we have a TypedefDecl with the name 'FILE'.
15875ffd83dbSDimitry Andric       for (Decl *D : LookupRes)
15885ffd83dbSDimitry Andric         if (auto *TD = dyn_cast<TypedefNameDecl>(D))
15895ffd83dbSDimitry Andric           return ACtx.getTypeDeclType(TD).getCanonicalType();
15905ffd83dbSDimitry Andric 
15915ffd83dbSDimitry Andric       // Find the first TypeDecl.
15925ffd83dbSDimitry Andric       // There maybe cases when a function has the same name as a struct.
15935ffd83dbSDimitry Andric       // E.g. in POSIX: `struct stat` and the function `stat()`:
15945ffd83dbSDimitry Andric       //   int stat(const char *restrict path, struct stat *restrict buf);
15955ffd83dbSDimitry Andric       for (Decl *D : LookupRes)
15965ffd83dbSDimitry Andric         if (auto *TD = dyn_cast<TypeDecl>(D))
15975ffd83dbSDimitry Andric           return ACtx.getTypeDeclType(TD).getCanonicalType();
1598bdd1243dSDimitry Andric       return std::nullopt;
15990b57cec5SDimitry Andric     }
1600e8d8bef9SDimitry Andric   } lookupTy(ACtx);
16010b57cec5SDimitry Andric 
1602e8d8bef9SDimitry Andric   // Below are auxiliary classes to handle optional types that we get as a
1603e8d8bef9SDimitry Andric   // result of the lookup.
1604e8d8bef9SDimitry Andric   class GetRestrictTy {
1605e8d8bef9SDimitry Andric     const ASTContext &ACtx;
16060b57cec5SDimitry Andric 
1607e8d8bef9SDimitry Andric   public:
1608e8d8bef9SDimitry Andric     GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1609e8d8bef9SDimitry Andric     QualType operator()(QualType Ty) {
1610e8d8bef9SDimitry Andric       return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1611e8d8bef9SDimitry Andric     }
1612bdd1243dSDimitry Andric     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1613e8d8bef9SDimitry Andric       if (Ty)
1614e8d8bef9SDimitry Andric         return operator()(*Ty);
1615bdd1243dSDimitry Andric       return std::nullopt;
1616e8d8bef9SDimitry Andric     }
1617e8d8bef9SDimitry Andric   } getRestrictTy(ACtx);
1618e8d8bef9SDimitry Andric   class GetPointerTy {
1619e8d8bef9SDimitry Andric     const ASTContext &ACtx;
1620e8d8bef9SDimitry Andric 
1621e8d8bef9SDimitry Andric   public:
1622e8d8bef9SDimitry Andric     GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1623e8d8bef9SDimitry Andric     QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1624bdd1243dSDimitry Andric     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1625e8d8bef9SDimitry Andric       if (Ty)
1626e8d8bef9SDimitry Andric         return operator()(*Ty);
1627bdd1243dSDimitry Andric       return std::nullopt;
1628e8d8bef9SDimitry Andric     }
1629e8d8bef9SDimitry Andric   } getPointerTy(ACtx);
1630e8d8bef9SDimitry Andric   class {
1631e8d8bef9SDimitry Andric   public:
1632bdd1243dSDimitry Andric     std::optional<QualType> operator()(std::optional<QualType> Ty) {
1633bdd1243dSDimitry Andric       return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1634e8d8bef9SDimitry Andric     }
1635e8d8bef9SDimitry Andric     QualType operator()(QualType Ty) { return Ty.withConst(); }
1636e8d8bef9SDimitry Andric   } getConstTy;
1637e8d8bef9SDimitry Andric   class GetMaxValue {
1638e8d8bef9SDimitry Andric     BasicValueFactory &BVF;
1639e8d8bef9SDimitry Andric 
1640e8d8bef9SDimitry Andric   public:
1641e8d8bef9SDimitry Andric     GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1642bdd1243dSDimitry Andric     std::optional<RangeInt> operator()(QualType Ty) {
1643e8d8bef9SDimitry Andric       return BVF.getMaxValue(Ty).getLimitedValue();
1644e8d8bef9SDimitry Andric     }
1645bdd1243dSDimitry Andric     std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1646e8d8bef9SDimitry Andric       if (Ty) {
1647e8d8bef9SDimitry Andric         return operator()(*Ty);
1648e8d8bef9SDimitry Andric       }
1649bdd1243dSDimitry Andric       return std::nullopt;
1650e8d8bef9SDimitry Andric     }
1651e8d8bef9SDimitry Andric   } getMaxValue(BVF);
16520b57cec5SDimitry Andric 
16530b57cec5SDimitry Andric   // These types are useful for writing specifications quickly,
16540b57cec5SDimitry Andric   // New specifications should probably introduce more types.
16550b57cec5SDimitry Andric   // Some types are hard to obtain from the AST, eg. "ssize_t".
16560b57cec5SDimitry Andric   // In such cases it should be possible to provide multiple variants
16570b57cec5SDimitry Andric   // of function summary for common cases (eg. ssize_t could be int or long
16580b57cec5SDimitry Andric   // or long long, so three summary variants would be enough).
16590b57cec5SDimitry Andric   // Of course, function variants are also useful for C++ overloads.
16605ffd83dbSDimitry Andric   const QualType VoidTy = ACtx.VoidTy;
1661e8d8bef9SDimitry Andric   const QualType CharTy = ACtx.CharTy;
1662e8d8bef9SDimitry Andric   const QualType WCharTy = ACtx.WCharTy;
16635ffd83dbSDimitry Andric   const QualType IntTy = ACtx.IntTy;
16645ffd83dbSDimitry Andric   const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
16655ffd83dbSDimitry Andric   const QualType LongTy = ACtx.LongTy;
16665ffd83dbSDimitry Andric   const QualType SizeTy = ACtx.getSizeType();
16670b57cec5SDimitry Andric 
1668e8d8bef9SDimitry Andric   const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1669e8d8bef9SDimitry Andric   const QualType IntPtrTy = getPointerTy(IntTy);   // int *
16705ffd83dbSDimitry Andric   const QualType UnsignedIntPtrTy =
1671e8d8bef9SDimitry Andric       getPointerTy(UnsignedIntTy); // unsigned int *
1672e8d8bef9SDimitry Andric   const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
16735ffd83dbSDimitry Andric   const QualType ConstVoidPtrTy =
1674e8d8bef9SDimitry Andric       getPointerTy(getConstTy(VoidTy));            // const void *
1675e8d8bef9SDimitry Andric   const QualType CharPtrTy = getPointerTy(CharTy); // char *
1676e8d8bef9SDimitry Andric   const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
16775ffd83dbSDimitry Andric   const QualType ConstCharPtrTy =
1678e8d8bef9SDimitry Andric       getPointerTy(getConstTy(CharTy)); // const char *
1679e8d8bef9SDimitry Andric   const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1680e8d8bef9SDimitry Andric   const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
16815ffd83dbSDimitry Andric   const QualType ConstWchar_tPtrTy =
1682e8d8bef9SDimitry Andric       getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1683e8d8bef9SDimitry Andric   const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1684e8d8bef9SDimitry Andric   const QualType SizePtrTy = getPointerTy(SizeTy);
1685e8d8bef9SDimitry Andric   const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
16865ffd83dbSDimitry Andric 
16875ffd83dbSDimitry Andric   const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
16885ffd83dbSDimitry Andric   const RangeInt UnsignedIntMax =
16895ffd83dbSDimitry Andric       BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
16905ffd83dbSDimitry Andric   const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
16915ffd83dbSDimitry Andric   const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
16925ffd83dbSDimitry Andric 
16935ffd83dbSDimitry Andric   // Set UCharRangeMax to min of int or uchar maximum value.
16945ffd83dbSDimitry Andric   // The C standard states that the arguments of functions like isalpha must
16955ffd83dbSDimitry Andric   // be representable as an unsigned char. Their type is 'int', so the max
16965ffd83dbSDimitry Andric   // value of the argument should be min(UCharMax, IntMax). This just happen
16975ffd83dbSDimitry Andric   // to be true for commonly used and well tested instruction set
16985ffd83dbSDimitry Andric   // architectures, but not for others.
16995ffd83dbSDimitry Andric   const RangeInt UCharRangeMax =
17005ffd83dbSDimitry Andric       std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
17015ffd83dbSDimitry Andric 
170206c3fb27SDimitry Andric   // Get platform dependent values of some macros.
170306c3fb27SDimitry Andric   // Try our best to parse this from the Preprocessor, otherwise fallback to a
170406c3fb27SDimitry Andric   // default value (what is found in a library header).
170506c3fb27SDimitry Andric   const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
170606c3fb27SDimitry Andric   const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
17075ffd83dbSDimitry Andric 
17085ffd83dbSDimitry Andric   // Auxiliary class to aid adding summaries to the summary map.
17095ffd83dbSDimitry Andric   struct AddToFunctionSummaryMap {
17105ffd83dbSDimitry Andric     const ASTContext &ACtx;
17115ffd83dbSDimitry Andric     FunctionSummaryMapType &Map;
17125ffd83dbSDimitry Andric     bool DisplayLoadedSummaries;
17135ffd83dbSDimitry Andric     AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
17145ffd83dbSDimitry Andric                             bool DisplayLoadedSummaries)
17155ffd83dbSDimitry Andric         : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
17165ffd83dbSDimitry Andric     }
17175ffd83dbSDimitry Andric 
17185ffd83dbSDimitry Andric     // Add a summary to a FunctionDecl found by lookup. The lookup is performed
17195ffd83dbSDimitry Andric     // by the given Name, and in the global scope. The summary will be attached
17205ffd83dbSDimitry Andric     // to the found FunctionDecl only if the signatures match.
1721e8d8bef9SDimitry Andric     //
1722e8d8bef9SDimitry Andric     // Returns true if the summary has been added, false otherwise.
1723e8d8bef9SDimitry Andric     bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1724e8d8bef9SDimitry Andric       if (Sign.isInvalid())
1725e8d8bef9SDimitry Andric         return false;
17265ffd83dbSDimitry Andric       IdentifierInfo &II = ACtx.Idents.get(Name);
17275ffd83dbSDimitry Andric       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1728fe6060f1SDimitry Andric       if (LookupRes.empty())
1729e8d8bef9SDimitry Andric         return false;
17305ffd83dbSDimitry Andric       for (Decl *D : LookupRes) {
17315ffd83dbSDimitry Andric         if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1732e8d8bef9SDimitry Andric           if (Sum.matchesAndSet(Sign, FD)) {
1733e8d8bef9SDimitry Andric             auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
17345ffd83dbSDimitry Andric             assert(Res.second && "Function already has a summary set!");
17355ffd83dbSDimitry Andric             (void)Res;
17365ffd83dbSDimitry Andric             if (DisplayLoadedSummaries) {
17375ffd83dbSDimitry Andric               llvm::errs() << "Loaded summary for: ";
17385ffd83dbSDimitry Andric               FD->print(llvm::errs());
17395ffd83dbSDimitry Andric               llvm::errs() << "\n";
17405ffd83dbSDimitry Andric             }
1741e8d8bef9SDimitry Andric             return true;
17425ffd83dbSDimitry Andric           }
17435ffd83dbSDimitry Andric         }
17445ffd83dbSDimitry Andric       }
1745e8d8bef9SDimitry Andric       return false;
17465ffd83dbSDimitry Andric     }
1747e8d8bef9SDimitry Andric     // Add the same summary for different names with the Signature explicitly
1748e8d8bef9SDimitry Andric     // given.
1749*0fca6ea1SDimitry Andric     void operator()(ArrayRef<StringRef> Names, Signature Sign, Summary Sum) {
1750e8d8bef9SDimitry Andric       for (StringRef Name : Names)
1751e8d8bef9SDimitry Andric         operator()(Name, Sign, Sum);
17525ffd83dbSDimitry Andric     }
17535ffd83dbSDimitry Andric   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
17540b57cec5SDimitry Andric 
17555ffd83dbSDimitry Andric   // Below are helpers functions to create the summaries.
175606c3fb27SDimitry Andric   auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
175706c3fb27SDimitry Andric                               StringRef Desc = "") {
175806c3fb27SDimitry Andric     return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
17595ffd83dbSDimitry Andric   };
17605ffd83dbSDimitry Andric   auto BufferSize = [](auto... Args) {
17615ffd83dbSDimitry Andric     return std::make_shared<BufferSizeConstraint>(Args...);
17625ffd83dbSDimitry Andric   };
17635ffd83dbSDimitry Andric   struct {
17645ffd83dbSDimitry Andric     auto operator()(RangeKind Kind, IntRangeVector Ranges) {
17655ffd83dbSDimitry Andric       return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
17665ffd83dbSDimitry Andric     }
17675ffd83dbSDimitry Andric     auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
17685ffd83dbSDimitry Andric       return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
17695ffd83dbSDimitry Andric     }
17705ffd83dbSDimitry Andric   } ReturnValueCondition;
1771e8d8bef9SDimitry Andric   struct {
1772e8d8bef9SDimitry Andric     auto operator()(RangeInt b, RangeInt e) {
17735ffd83dbSDimitry Andric       return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1774e8d8bef9SDimitry Andric     }
1775bdd1243dSDimitry Andric     auto operator()(RangeInt b, std::optional<RangeInt> e) {
1776e8d8bef9SDimitry Andric       if (e)
1777e8d8bef9SDimitry Andric         return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1778e8d8bef9SDimitry Andric       return IntRangeVector{};
1779e8d8bef9SDimitry Andric     }
1780e8d8bef9SDimitry Andric     auto operator()(std::pair<RangeInt, RangeInt> i0,
1781bdd1243dSDimitry Andric                     std::pair<RangeInt, std::optional<RangeInt>> i1) {
1782e8d8bef9SDimitry Andric       if (i1.second)
1783e8d8bef9SDimitry Andric         return IntRangeVector{i0, {i1.first, *(i1.second)}};
1784e8d8bef9SDimitry Andric       return IntRangeVector{i0};
1785e8d8bef9SDimitry Andric     }
1786e8d8bef9SDimitry Andric   } Range;
17875ffd83dbSDimitry Andric   auto SingleValue = [](RangeInt v) {
17885ffd83dbSDimitry Andric     return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
17895ffd83dbSDimitry Andric   };
17905ffd83dbSDimitry Andric   auto LessThanOrEq = BO_LE;
17915ffd83dbSDimitry Andric   auto NotNull = [&](ArgNo ArgN) {
17925ffd83dbSDimitry Andric     return std::make_shared<NotNullConstraint>(ArgN);
17935ffd83dbSDimitry Andric   };
1794bdd1243dSDimitry Andric   auto IsNull = [&](ArgNo ArgN) {
1795bdd1243dSDimitry Andric     return std::make_shared<NotNullConstraint>(ArgN, false);
1796bdd1243dSDimitry Andric   };
179706c3fb27SDimitry Andric   auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N, ArgNo SizeArg2N) {
179806c3fb27SDimitry Andric     return std::make_shared<NotNullBufferConstraint>(ArgN, SizeArg1N,
179906c3fb27SDimitry Andric                                                      SizeArg2N);
180006c3fb27SDimitry Andric   };
18010b57cec5SDimitry Andric 
1802bdd1243dSDimitry Andric   std::optional<QualType> FileTy = lookupTy("FILE");
1803bdd1243dSDimitry Andric   std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
1804bdd1243dSDimitry Andric   std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1805bdd1243dSDimitry Andric 
1806bdd1243dSDimitry Andric   std::optional<QualType> FPosTTy = lookupTy("fpos_t");
1807bdd1243dSDimitry Andric   std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
1808bdd1243dSDimitry Andric   std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
1809bdd1243dSDimitry Andric   std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
18105ffd83dbSDimitry Andric 
181106c3fb27SDimitry Andric   constexpr llvm::StringLiteral GenericSuccessMsg(
181206c3fb27SDimitry Andric       "Assuming that '{0}' is successful");
181306c3fb27SDimitry Andric   constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");
181406c3fb27SDimitry Andric 
1815e8d8bef9SDimitry Andric   // We are finally ready to define specifications for all supported functions.
1816e8d8bef9SDimitry Andric   //
1817e8d8bef9SDimitry Andric   // Argument ranges should always cover all variants. If return value
1818e8d8bef9SDimitry Andric   // is completely unknown, omit it from the respective range set.
1819e8d8bef9SDimitry Andric   //
1820e8d8bef9SDimitry Andric   // Every item in the list of range sets represents a particular
1821e8d8bef9SDimitry Andric   // execution path the analyzer would need to explore once
1822e8d8bef9SDimitry Andric   // the call is modeled - a new program state is constructed
1823e8d8bef9SDimitry Andric   // for every range set, and each range line in the range set
1824e8d8bef9SDimitry Andric   // corresponds to a specific constraint within this state.
18255ffd83dbSDimitry Andric 
18260b57cec5SDimitry Andric   // The isascii() family of functions.
18275ffd83dbSDimitry Andric   // The behavior is undefined if the value of the argument is not
18285ffd83dbSDimitry Andric   // representable as unsigned char or is not equal to EOF. See e.g. C99
18295ffd83dbSDimitry Andric   // 7.4.1.2 The isalpha function (p: 181-182).
18305ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1831e8d8bef9SDimitry Andric       "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1832e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18335ffd83dbSDimitry Andric           // Boils down to isupper() or islower() or isdigit().
18345ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange,
18355ffd83dbSDimitry Andric                                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
183681ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
183781ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is alphanumeric")
18385ffd83dbSDimitry Andric           // The locale-specific range.
18390b57cec5SDimitry Andric           // No post-condition. We are completely unaware of
18400b57cec5SDimitry Andric           // locale-specific return values.
184181ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
184281ad6265SDimitry Andric                 ErrnoIrrelevant)
18435ffd83dbSDimitry Andric           .Case(
18445ffd83dbSDimitry Andric               {ArgumentCondition(
18455ffd83dbSDimitry Andric                    0U, OutOfRange,
18465ffd83dbSDimitry Andric                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
184781ad6265SDimitry Andric                ReturnValueCondition(WithinRange, SingleValue(0))},
184881ad6265SDimitry Andric               ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
184906c3fb27SDimitry Andric           .ArgConstraint(ArgumentCondition(0U, WithinRange,
185006c3fb27SDimitry Andric                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
185106c3fb27SDimitry Andric                                            "an unsigned char value or EOF")));
18525ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1853e8d8bef9SDimitry Andric       "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1854e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18555ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
185681ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
185781ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is alphabetical")
18585ffd83dbSDimitry Andric           // The locale-specific range.
185981ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
186081ad6265SDimitry Andric                 ErrnoIrrelevant)
18615ffd83dbSDimitry Andric           .Case({ArgumentCondition(
18625ffd83dbSDimitry Andric                      0U, OutOfRange,
18635ffd83dbSDimitry Andric                      {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
186481ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
186581ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
18665ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1867e8d8bef9SDimitry Andric       "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1868e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18695ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
187081ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
187181ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is an ASCII character")
18725ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
187381ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
187481ad6265SDimitry Andric                 ErrnoIrrelevant,
187581ad6265SDimitry Andric                 "Assuming the character is not an ASCII character"));
18765ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1877e8d8bef9SDimitry Andric       "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1878e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18795ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
188081ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
188181ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is a blank character")
18825ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
188381ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
188481ad6265SDimitry Andric                 ErrnoIrrelevant,
188581ad6265SDimitry Andric                 "Assuming the character is not a blank character"));
18865ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1887e8d8bef9SDimitry Andric       "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1888e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
18895ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
189081ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
189181ad6265SDimitry Andric                 ErrnoIrrelevant,
189281ad6265SDimitry Andric                 "Assuming the character is a control character")
18935ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
189481ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
189581ad6265SDimitry Andric                 ErrnoIrrelevant,
189681ad6265SDimitry Andric                 "Assuming the character is not a control character"));
18975ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1898e8d8bef9SDimitry Andric       "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1899e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19005ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
190181ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
190281ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is a digit")
19035ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
190481ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
190581ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is not a digit"));
19065ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1907e8d8bef9SDimitry Andric       "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1908e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19095ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
191081ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
191181ad6265SDimitry Andric                 ErrnoIrrelevant,
191281ad6265SDimitry Andric                 "Assuming the character has graphical representation")
191381ad6265SDimitry Andric           .Case(
191481ad6265SDimitry Andric               {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
191581ad6265SDimitry Andric                ReturnValueCondition(WithinRange, SingleValue(0))},
191681ad6265SDimitry Andric               ErrnoIrrelevant,
191781ad6265SDimitry Andric               "Assuming the character does not have graphical representation"));
19185ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1919e8d8bef9SDimitry Andric       "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1920e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19215ffd83dbSDimitry Andric           // Is certainly lowercase.
19225ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
192381ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
192481ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is a lowercase letter")
19255ffd83dbSDimitry Andric           // Is ascii but not lowercase.
19265ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
19275ffd83dbSDimitry Andric                  ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
192881ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
192981ad6265SDimitry Andric                 ErrnoIrrelevant,
193081ad6265SDimitry Andric                 "Assuming the character is not a lowercase letter")
19315ffd83dbSDimitry Andric           // The locale-specific range.
193281ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
193381ad6265SDimitry Andric                 ErrnoIrrelevant)
19345ffd83dbSDimitry Andric           // Is not an unsigned char.
19355ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
193681ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
193781ad6265SDimitry Andric                 ErrnoIrrelevant));
19385ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1939e8d8bef9SDimitry Andric       "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1940e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19415ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
194281ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
194381ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is printable")
19445ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
194581ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
194681ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is non-printable"));
19475ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1948e8d8bef9SDimitry Andric       "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1949e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19505ffd83dbSDimitry Andric           .Case({ArgumentCondition(
19515ffd83dbSDimitry Andric                      0U, WithinRange,
19525ffd83dbSDimitry Andric                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
195381ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
195481ad6265SDimitry Andric                 ErrnoIrrelevant, "Assuming the character is a punctuation mark")
19555ffd83dbSDimitry Andric           .Case({ArgumentCondition(
19565ffd83dbSDimitry Andric                      0U, OutOfRange,
19575ffd83dbSDimitry Andric                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
195881ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
195981ad6265SDimitry Andric                 ErrnoIrrelevant,
196081ad6265SDimitry Andric                 "Assuming the character is not a punctuation mark"));
19615ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1962e8d8bef9SDimitry Andric       "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1963e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19645ffd83dbSDimitry Andric           // Space, '\f', '\n', '\r', '\t', '\v'.
19655ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
196681ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
196781ad6265SDimitry Andric                 ErrnoIrrelevant,
196881ad6265SDimitry Andric                 "Assuming the character is a whitespace character")
19695ffd83dbSDimitry Andric           // The locale-specific range.
197081ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
197181ad6265SDimitry Andric                 ErrnoIrrelevant)
19725ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange,
19735ffd83dbSDimitry Andric                                    {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
197481ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
197581ad6265SDimitry Andric                 ErrnoIrrelevant,
197681ad6265SDimitry Andric                 "Assuming the character is not a whitespace character"));
19775ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1978e8d8bef9SDimitry Andric       "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1979e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19805ffd83dbSDimitry Andric           // Is certainly uppercase.
19815ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
198281ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
198381ad6265SDimitry Andric                 ErrnoIrrelevant,
198481ad6265SDimitry Andric                 "Assuming the character is an uppercase letter")
19855ffd83dbSDimitry Andric           // The locale-specific range.
198681ad6265SDimitry Andric           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
198781ad6265SDimitry Andric                 ErrnoIrrelevant)
19885ffd83dbSDimitry Andric           // Other.
19895ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange,
19905ffd83dbSDimitry Andric                                    {{'A', 'Z'}, {128, UCharRangeMax}}),
199181ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
199281ad6265SDimitry Andric                 ErrnoIrrelevant,
199381ad6265SDimitry Andric                 "Assuming the character is not an uppercase letter"));
19945ffd83dbSDimitry Andric   addToFunctionSummaryMap(
1995e8d8bef9SDimitry Andric       "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1996e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
19975ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, WithinRange,
19985ffd83dbSDimitry Andric                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
199981ad6265SDimitry Andric                  ReturnValueCondition(OutOfRange, SingleValue(0))},
200081ad6265SDimitry Andric                 ErrnoIrrelevant,
200181ad6265SDimitry Andric                 "Assuming the character is a hexadecimal digit")
20025ffd83dbSDimitry Andric           .Case({ArgumentCondition(0U, OutOfRange,
20035ffd83dbSDimitry Andric                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
200481ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
200581ad6265SDimitry Andric                 ErrnoIrrelevant,
200681ad6265SDimitry Andric                 "Assuming the character is not a hexadecimal digit"));
2007e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2008e8d8bef9SDimitry Andric       "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2009e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
201006c3fb27SDimitry Andric           .ArgConstraint(ArgumentCondition(0U, WithinRange,
201106c3fb27SDimitry Andric                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
201206c3fb27SDimitry Andric                                            "an unsigned char value or EOF")));
2013e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2014e8d8bef9SDimitry Andric       "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2015e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
201606c3fb27SDimitry Andric           .ArgConstraint(ArgumentCondition(0U, WithinRange,
201706c3fb27SDimitry Andric                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
201806c3fb27SDimitry Andric                                            "an unsigned char value or EOF")));
2019e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2020e8d8bef9SDimitry Andric       "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2021e8d8bef9SDimitry Andric       Summary(EvalCallAsPure)
202206c3fb27SDimitry Andric           .ArgConstraint(ArgumentCondition(0U, WithinRange,
202306c3fb27SDimitry Andric                                            {{EOFv, EOFv}, {0, UCharRangeMax}},
202406c3fb27SDimitry Andric                                            "an unsigned char value or EOF")));
20250b57cec5SDimitry Andric 
2026e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2027e8d8bef9SDimitry Andric       "getchar", Signature(ArgTypes{}, RetType{IntTy}),
2028e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2029e8d8bef9SDimitry Andric           .Case({ReturnValueCondition(WithinRange,
203081ad6265SDimitry Andric                                       {{EOFv, EOFv}, {0, UCharRangeMax}})},
203181ad6265SDimitry Andric                 ErrnoIrrelevant));
20320b57cec5SDimitry Andric 
20330b57cec5SDimitry Andric   // read()-like functions that never return more than buffer size.
2034e8d8bef9SDimitry Andric   auto FreadSummary =
2035e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2036bdd1243dSDimitry Andric           .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2037bdd1243dSDimitry Andric                  ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
2038bdd1243dSDimitry Andric                  ReturnValueCondition(BO_LT, ArgNo(2)),
203981ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
204006c3fb27SDimitry Andric                 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2041bdd1243dSDimitry Andric           .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2042bdd1243dSDimitry Andric                  ReturnValueCondition(BO_EQ, ArgNo(2)),
2043bdd1243dSDimitry Andric                  ReturnValueCondition(WithinRange, Range(0, SizeMax))},
204406c3fb27SDimitry Andric                 ErrnoMustNotBeChecked, GenericSuccessMsg)
2045bdd1243dSDimitry Andric           .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
2046bdd1243dSDimitry Andric                  ReturnValueCondition(WithinRange, SingleValue(0))},
20475f757f3fSDimitry Andric                 ErrnoMustNotBeChecked,
20485f757f3fSDimitry Andric                 "Assuming that argument 'size' to '{0}' is 0")
204906c3fb27SDimitry Andric           .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2050e8d8bef9SDimitry Andric           .ArgConstraint(NotNull(ArgNo(3)))
2051e8d8bef9SDimitry Andric           .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2052e8d8bef9SDimitry Andric                                     /*BufSizeMultiplier=*/ArgNo(2)));
20535ffd83dbSDimitry Andric 
2054e8d8bef9SDimitry Andric   // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2055e8d8bef9SDimitry Andric   //              FILE *restrict stream);
2056e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2057e8d8bef9SDimitry Andric       "fread",
2058e8d8bef9SDimitry Andric       Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
2059e8d8bef9SDimitry Andric                 RetType{SizeTy}),
2060e8d8bef9SDimitry Andric       FreadSummary);
2061e8d8bef9SDimitry Andric   // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2062e8d8bef9SDimitry Andric   //               FILE *restrict stream);
2063e8d8bef9SDimitry Andric   addToFunctionSummaryMap("fwrite",
2064e8d8bef9SDimitry Andric                           Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
2065e8d8bef9SDimitry Andric                                              SizeTy, FilePtrRestrictTy},
2066e8d8bef9SDimitry Andric                                     RetType{SizeTy}),
2067e8d8bef9SDimitry Andric                           FreadSummary);
2068e8d8bef9SDimitry Andric 
2069bdd1243dSDimitry Andric   std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
2070bdd1243dSDimitry Andric   std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
2071e8d8bef9SDimitry Andric 
2072e8d8bef9SDimitry Andric   auto ReadSummary =
2073e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2074e8d8bef9SDimitry Andric           .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
207581ad6265SDimitry Andric                  ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
207681ad6265SDimitry Andric                 ErrnoIrrelevant);
2077e8d8bef9SDimitry Andric 
20785ffd83dbSDimitry Andric   // FIXME these are actually defined by POSIX and not by the C standard, we
20795ffd83dbSDimitry Andric   // should handle them together with the rest of the POSIX functions.
2080e8d8bef9SDimitry Andric   // ssize_t read(int fildes, void *buf, size_t nbyte);
2081e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2082e8d8bef9SDimitry Andric       "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2083e8d8bef9SDimitry Andric       ReadSummary);
2084e8d8bef9SDimitry Andric   // ssize_t write(int fildes, const void *buf, size_t nbyte);
2085e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2086e8d8bef9SDimitry Andric       "write",
2087e8d8bef9SDimitry Andric       Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2088e8d8bef9SDimitry Andric       ReadSummary);
2089e8d8bef9SDimitry Andric 
2090e8d8bef9SDimitry Andric   auto GetLineSummary =
2091e8d8bef9SDimitry Andric       Summary(NoEvalCall)
2092e8d8bef9SDimitry Andric           .Case({ReturnValueCondition(WithinRange,
209381ad6265SDimitry Andric                                       Range({-1, -1}, {1, Ssize_tMax}))},
209481ad6265SDimitry Andric                 ErrnoIrrelevant);
2095e8d8bef9SDimitry Andric 
2096e8d8bef9SDimitry Andric   QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
20970b57cec5SDimitry Andric 
20980b57cec5SDimitry Andric   // getline()-like functions either fail or read at least the delimiter.
20995ffd83dbSDimitry Andric   // FIXME these are actually defined by POSIX and not by the C standard, we
21005ffd83dbSDimitry Andric   // should handle them together with the rest of the POSIX functions.
2101e8d8bef9SDimitry Andric   // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2102e8d8bef9SDimitry Andric   //                 FILE *restrict stream);
2103e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2104e8d8bef9SDimitry Andric       "getline",
2105e8d8bef9SDimitry Andric       Signature(
2106e8d8bef9SDimitry Andric           ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
2107e8d8bef9SDimitry Andric           RetType{Ssize_tTy}),
2108e8d8bef9SDimitry Andric       GetLineSummary);
2109e8d8bef9SDimitry Andric   // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2110e8d8bef9SDimitry Andric   //                  int delimiter, FILE *restrict stream);
2111e8d8bef9SDimitry Andric   addToFunctionSummaryMap(
2112e8d8bef9SDimitry Andric       "getdelim",
2113e8d8bef9SDimitry Andric       Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2114e8d8bef9SDimitry Andric                          FilePtrRestrictTy},
2115e8d8bef9SDimitry Andric                 RetType{Ssize_tTy}),
2116e8d8bef9SDimitry Andric       GetLineSummary);
21175ffd83dbSDimitry Andric 
2118349cc55cSDimitry Andric   {
211981ad6265SDimitry Andric     Summary GetenvSummary =
212081ad6265SDimitry Andric         Summary(NoEvalCall)
2121349cc55cSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
212281ad6265SDimitry Andric             .Case({NotNull(Ret)}, ErrnoIrrelevant,
212381ad6265SDimitry Andric                   "Assuming the environment variable exists");
2124349cc55cSDimitry Andric     // In untrusted environments the envvar might not exist.
2125349cc55cSDimitry Andric     if (!ShouldAssumeControlledEnvironment)
212681ad6265SDimitry Andric       GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
212781ad6265SDimitry Andric                          "Assuming the environment variable does not exist");
2128349cc55cSDimitry Andric 
2129349cc55cSDimitry Andric     // char *getenv(const char *name);
2130349cc55cSDimitry Andric     addToFunctionSummaryMap(
2131349cc55cSDimitry Andric         "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2132349cc55cSDimitry Andric         std::move(GetenvSummary));
2133349cc55cSDimitry Andric   }
2134349cc55cSDimitry Andric 
2135*0fca6ea1SDimitry Andric   if (!ModelPOSIX) {
2136*0fca6ea1SDimitry Andric     // Without POSIX use of 'errno' is not specified (in these cases).
2137*0fca6ea1SDimitry Andric     // Add these functions without 'errno' checks.
2138*0fca6ea1SDimitry Andric     addToFunctionSummaryMap(
2139*0fca6ea1SDimitry Andric         {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2140*0fca6ea1SDimitry Andric         Summary(NoEvalCall)
2141*0fca6ea1SDimitry Andric             .Case({ReturnValueCondition(WithinRange,
2142*0fca6ea1SDimitry Andric                                         {{EOFv, EOFv}, {0, UCharRangeMax}})},
2143*0fca6ea1SDimitry Andric                   ErrnoIrrelevant)
2144*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2145*0fca6ea1SDimitry Andric   } else {
2146bdd1243dSDimitry Andric     const auto ReturnsZeroOrMinusOne =
2147bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
2148bdd1243dSDimitry Andric     const auto ReturnsZero =
2149bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2150bdd1243dSDimitry Andric     const auto ReturnsMinusOne =
2151bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
21527a6dacacSDimitry Andric     const auto ReturnsEOF =
21537a6dacacSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(EOFv))};
2154bdd1243dSDimitry Andric     const auto ReturnsNonnegative =
2155bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2156bdd1243dSDimitry Andric     const auto ReturnsNonZero =
2157bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2158bdd1243dSDimitry Andric     const auto ReturnsFileDescriptor =
2159bdd1243dSDimitry Andric         ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
2160bdd1243dSDimitry Andric     const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2161bdd1243dSDimitry Andric 
216206c3fb27SDimitry Andric     auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
216306c3fb27SDimitry Andric       return std::make_shared<RangeConstraint>(
216406c3fb27SDimitry Andric           ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
216506c3fb27SDimitry Andric           "a valid file descriptor or AT_FDCWD");
216606c3fb27SDimitry Andric     };
216706c3fb27SDimitry Andric 
2168bdd1243dSDimitry Andric     // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2169bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2170bdd1243dSDimitry Andric         "fopen",
2171bdd1243dSDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2172bdd1243dSDimitry Andric                   RetType{FilePtrTy}),
2173bdd1243dSDimitry Andric         Summary(NoEvalCall)
217406c3fb27SDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
217506c3fb27SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2176bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2177bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2178bdd1243dSDimitry Andric 
21797a6dacacSDimitry Andric     // FILE *fdopen(int fd, const char *mode);
21807a6dacacSDimitry Andric     addToFunctionSummaryMap(
21817a6dacacSDimitry Andric         "fdopen",
21827a6dacacSDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
21837a6dacacSDimitry Andric         Summary(NoEvalCall)
21847a6dacacSDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
21857a6dacacSDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
21867a6dacacSDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
21877a6dacacSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
21887a6dacacSDimitry Andric 
2189bdd1243dSDimitry Andric     // FILE *tmpfile(void);
219006c3fb27SDimitry Andric     addToFunctionSummaryMap(
219106c3fb27SDimitry Andric         "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2192bdd1243dSDimitry Andric         Summary(NoEvalCall)
219306c3fb27SDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
219406c3fb27SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2195bdd1243dSDimitry Andric 
2196bdd1243dSDimitry Andric     // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2197bdd1243dSDimitry Andric     //               FILE *restrict stream);
2198bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2199bdd1243dSDimitry Andric         "freopen",
2200bdd1243dSDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2201bdd1243dSDimitry Andric                            FilePtrRestrictTy},
2202bdd1243dSDimitry Andric                   RetType{FilePtrTy}),
2203bdd1243dSDimitry Andric         Summary(NoEvalCall)
2204bdd1243dSDimitry Andric             .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
220506c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
220606c3fb27SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2207bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
2208bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
2209bdd1243dSDimitry Andric 
2210*0fca6ea1SDimitry Andric     // FILE *popen(const char *command, const char *type);
2211*0fca6ea1SDimitry Andric     addToFunctionSummaryMap(
2212*0fca6ea1SDimitry Andric         "popen",
2213*0fca6ea1SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2214*0fca6ea1SDimitry Andric         Summary(NoEvalCall)
2215*0fca6ea1SDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2216*0fca6ea1SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2217*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2218*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2219*0fca6ea1SDimitry Andric 
2220bdd1243dSDimitry Andric     // int fclose(FILE *stream);
2221bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2222bdd1243dSDimitry Andric         "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2223bdd1243dSDimitry Andric         Summary(NoEvalCall)
222406c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
22257a6dacacSDimitry Andric             .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2226bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2227bdd1243dSDimitry Andric 
2228*0fca6ea1SDimitry Andric     // int pclose(FILE *stream);
2229*0fca6ea1SDimitry Andric     addToFunctionSummaryMap(
2230*0fca6ea1SDimitry Andric         "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2231*0fca6ea1SDimitry Andric         Summary(NoEvalCall)
2232*0fca6ea1SDimitry Andric             .Case({ReturnValueCondition(WithinRange, {{0, IntMax}})},
2233*0fca6ea1SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2234*0fca6ea1SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2235*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2236*0fca6ea1SDimitry Andric 
2237*0fca6ea1SDimitry Andric     std::optional<QualType> Off_tTy = lookupTy("off_t");
2238*0fca6ea1SDimitry Andric     std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
2239*0fca6ea1SDimitry Andric 
2240*0fca6ea1SDimitry Andric     // int fgetc(FILE *stream);
2241*0fca6ea1SDimitry Andric     // 'getc' is the same as 'fgetc' but may be a macro
2242*0fca6ea1SDimitry Andric     addToFunctionSummaryMap(
2243*0fca6ea1SDimitry Andric         {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2244*0fca6ea1SDimitry Andric         Summary(NoEvalCall)
2245*0fca6ea1SDimitry Andric             .Case({ReturnValueCondition(WithinRange, {{0, UCharRangeMax}})},
2246*0fca6ea1SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2247*0fca6ea1SDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2248*0fca6ea1SDimitry Andric                   ErrnoIrrelevant, GenericFailureMsg)
2249*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2250*0fca6ea1SDimitry Andric 
2251*0fca6ea1SDimitry Andric     // int fputc(int c, FILE *stream);
2252*0fca6ea1SDimitry Andric     // 'putc' is the same as 'fputc' but may be a macro
2253*0fca6ea1SDimitry Andric     addToFunctionSummaryMap(
2254*0fca6ea1SDimitry Andric         {"putc", "fputc"},
2255*0fca6ea1SDimitry Andric         Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2256*0fca6ea1SDimitry Andric         Summary(NoEvalCall)
2257*0fca6ea1SDimitry Andric             .Case({ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)),
2258*0fca6ea1SDimitry Andric                    ReturnValueCondition(BO_EQ, ArgNo(0))},
2259*0fca6ea1SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2260*0fca6ea1SDimitry Andric             .Case({ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)),
2261*0fca6ea1SDimitry Andric                    ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))},
2262*0fca6ea1SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2263*0fca6ea1SDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2264*0fca6ea1SDimitry Andric                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2265*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2266*0fca6ea1SDimitry Andric 
2267*0fca6ea1SDimitry Andric     // char *fgets(char *restrict s, int n, FILE *restrict stream);
2268*0fca6ea1SDimitry Andric     addToFunctionSummaryMap(
2269*0fca6ea1SDimitry Andric         "fgets",
2270*0fca6ea1SDimitry Andric         Signature(ArgTypes{CharPtrRestrictTy, IntTy, FilePtrRestrictTy},
2271*0fca6ea1SDimitry Andric                   RetType{CharPtrTy}),
2272*0fca6ea1SDimitry Andric         Summary(NoEvalCall)
2273*0fca6ea1SDimitry Andric             .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},
2274*0fca6ea1SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2275*0fca6ea1SDimitry Andric             .Case({IsNull(Ret)}, ErrnoIrrelevant, GenericFailureMsg)
2276*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2277*0fca6ea1SDimitry Andric             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
2278*0fca6ea1SDimitry Andric             .ArgConstraint(
2279*0fca6ea1SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2280*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
2281*0fca6ea1SDimitry Andric 
2282*0fca6ea1SDimitry Andric     // int fputs(const char *restrict s, FILE *restrict stream);
2283*0fca6ea1SDimitry Andric     addToFunctionSummaryMap(
2284*0fca6ea1SDimitry Andric         "fputs",
2285*0fca6ea1SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, FilePtrRestrictTy},
2286*0fca6ea1SDimitry Andric                   RetType{IntTy}),
2287*0fca6ea1SDimitry Andric         Summary(NoEvalCall)
2288*0fca6ea1SDimitry Andric             .Case(ReturnsNonnegative, ErrnoMustNotBeChecked, GenericSuccessMsg)
2289*0fca6ea1SDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2290*0fca6ea1SDimitry Andric                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2291*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2292*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2293*0fca6ea1SDimitry Andric 
2294297eecfbSDimitry Andric     // int ungetc(int c, FILE *stream);
2295297eecfbSDimitry Andric     addToFunctionSummaryMap(
2296297eecfbSDimitry Andric         "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2297297eecfbSDimitry Andric         Summary(NoEvalCall)
2298297eecfbSDimitry Andric             .Case({ReturnValueCondition(BO_EQ, ArgNo(0)),
2299297eecfbSDimitry Andric                    ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2300297eecfbSDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
2301297eecfbSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
23027a6dacacSDimitry Andric                    ArgumentCondition(0, WithinRange, SingleValue(EOFv))},
2303297eecfbSDimitry Andric                   ErrnoNEZeroIrrelevant,
2304297eecfbSDimitry Andric                   "Assuming that 'ungetc' fails because EOF was passed as "
2305297eecfbSDimitry Andric                   "character")
2306297eecfbSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2307297eecfbSDimitry Andric                    ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2308297eecfbSDimitry Andric                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
2309297eecfbSDimitry Andric             .ArgConstraint(ArgumentCondition(
2310297eecfbSDimitry Andric                 0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))
2311297eecfbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2312297eecfbSDimitry Andric 
2313bdd1243dSDimitry Andric     // int fseek(FILE *stream, long offset, int whence);
2314bdd1243dSDimitry Andric     // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2315bdd1243dSDimitry Andric     // these for condition of arg 2.
2316bdd1243dSDimitry Andric     // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2317bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2318bdd1243dSDimitry Andric         "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2319bdd1243dSDimitry Andric         Summary(NoEvalCall)
232006c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
232106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2322bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2323bdd1243dSDimitry Andric             .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2324bdd1243dSDimitry Andric 
23257a6dacacSDimitry Andric     // int fseeko(FILE *stream, off_t offset, int whence);
23267a6dacacSDimitry Andric     addToFunctionSummaryMap(
23277a6dacacSDimitry Andric         "fseeko",
23287a6dacacSDimitry Andric         Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
23297a6dacacSDimitry Andric         Summary(NoEvalCall)
23307a6dacacSDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
23317a6dacacSDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23327a6dacacSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
23337a6dacacSDimitry Andric             .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
23347a6dacacSDimitry Andric 
2335bdd1243dSDimitry Andric     // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2336bdd1243dSDimitry Andric     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2337bdd1243dSDimitry Andric     // "The fgetpos() function shall not change the setting of errno if
2338bdd1243dSDimitry Andric     // successful."
2339bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2340bdd1243dSDimitry Andric         "fgetpos",
2341bdd1243dSDimitry Andric         Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2342bdd1243dSDimitry Andric                   RetType{IntTy}),
2343bdd1243dSDimitry Andric         Summary(NoEvalCall)
234406c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
234506c3fb27SDimitry Andric             .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2346bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2347bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2348bdd1243dSDimitry Andric 
2349bdd1243dSDimitry Andric     // int fsetpos(FILE *stream, const fpos_t *pos);
2350bdd1243dSDimitry Andric     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2351bdd1243dSDimitry Andric     // "The fsetpos() function shall not change the setting of errno if
2352bdd1243dSDimitry Andric     // successful."
2353bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2354bdd1243dSDimitry Andric         "fsetpos",
2355bdd1243dSDimitry Andric         Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2356bdd1243dSDimitry Andric         Summary(NoEvalCall)
235706c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
235806c3fb27SDimitry Andric             .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2359bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2360bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
2361bdd1243dSDimitry Andric 
2362647cbc5dSDimitry Andric     // int fflush(FILE *stream);
2363647cbc5dSDimitry Andric     addToFunctionSummaryMap(
2364647cbc5dSDimitry Andric         "fflush", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2365647cbc5dSDimitry Andric         Summary(NoEvalCall)
2366647cbc5dSDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
23677a6dacacSDimitry Andric             .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2368647cbc5dSDimitry Andric 
2369bdd1243dSDimitry Andric     // long ftell(FILE *stream);
2370bdd1243dSDimitry Andric     // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2371bdd1243dSDimitry Andric     // "The ftell() function shall not change the setting of errno if
2372bdd1243dSDimitry Andric     // successful."
2373bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2374bdd1243dSDimitry Andric         "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2375bdd1243dSDimitry Andric         Summary(NoEvalCall)
2376297eecfbSDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))},
237706c3fb27SDimitry Andric                   ErrnoUnchanged, GenericSuccessMsg)
237806c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2379bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2380bdd1243dSDimitry Andric 
23817a6dacacSDimitry Andric     // off_t ftello(FILE *stream);
23827a6dacacSDimitry Andric     addToFunctionSummaryMap(
23837a6dacacSDimitry Andric         "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
23847a6dacacSDimitry Andric         Summary(NoEvalCall)
23857a6dacacSDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(0, Off_tMax))},
23867a6dacacSDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
23877a6dacacSDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23887a6dacacSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
23897a6dacacSDimitry Andric 
2390bdd1243dSDimitry Andric     // int fileno(FILE *stream);
2391*0fca6ea1SDimitry Andric     // According to POSIX 'fileno' may fail and set 'errno'.
2392*0fca6ea1SDimitry Andric     // But in Linux it may fail only if the specified file pointer is invalid.
2393*0fca6ea1SDimitry Andric     // At many places 'fileno' is used without check for failure and a failure
2394*0fca6ea1SDimitry Andric     // case here would produce a large amount of likely false positive warnings.
2395*0fca6ea1SDimitry Andric     // To avoid this, we assume here that it does not fail.
2396bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2397bdd1243dSDimitry Andric         "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2398bdd1243dSDimitry Andric         Summary(NoEvalCall)
2399*0fca6ea1SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoUnchanged, GenericSuccessMsg)
2400bdd1243dSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
2401bdd1243dSDimitry Andric 
2402bdd1243dSDimitry Andric     // void rewind(FILE *stream);
2403bdd1243dSDimitry Andric     // This function indicates error only by setting of 'errno'.
2404bdd1243dSDimitry Andric     addToFunctionSummaryMap("rewind",
2405bdd1243dSDimitry Andric                             Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2406bdd1243dSDimitry Andric                             Summary(NoEvalCall)
2407bdd1243dSDimitry Andric                                 .Case({}, ErrnoMustBeChecked)
2408bdd1243dSDimitry Andric                                 .ArgConstraint(NotNull(ArgNo(0))));
2409bdd1243dSDimitry Andric 
2410bdd1243dSDimitry Andric     // void clearerr(FILE *stream);
2411bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2412bdd1243dSDimitry Andric         "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2413bdd1243dSDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2414bdd1243dSDimitry Andric 
2415bdd1243dSDimitry Andric     // int feof(FILE *stream);
2416bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2417bdd1243dSDimitry Andric         "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2418bdd1243dSDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2419bdd1243dSDimitry Andric 
2420bdd1243dSDimitry Andric     // int ferror(FILE *stream);
2421bdd1243dSDimitry Andric     addToFunctionSummaryMap(
2422bdd1243dSDimitry Andric         "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2423bdd1243dSDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
24245ffd83dbSDimitry Andric 
24255ffd83dbSDimitry Andric     // long a64l(const char *str64);
24265ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2427e8d8bef9SDimitry Andric         "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2428e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
24295ffd83dbSDimitry Andric 
24305ffd83dbSDimitry Andric     // char *l64a(long value);
2431e8d8bef9SDimitry Andric     addToFunctionSummaryMap("l64a",
2432e8d8bef9SDimitry Andric                             Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2433e8d8bef9SDimitry Andric                             Summary(NoEvalCall)
2434e8d8bef9SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
2435e8d8bef9SDimitry Andric                                     0, WithinRange, Range(0, LongMax))));
2436e8d8bef9SDimitry Andric 
243706c3fb27SDimitry Andric     // int open(const char *path, int oflag, ...);
243806c3fb27SDimitry Andric     addToFunctionSummaryMap(
243906c3fb27SDimitry Andric         "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
244006c3fb27SDimitry Andric         Summary(NoEvalCall)
244106c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
244206c3fb27SDimitry Andric                   GenericSuccessMsg)
244306c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
244406c3fb27SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
244506c3fb27SDimitry Andric 
244606c3fb27SDimitry Andric     // int openat(int fd, const char *path, int oflag, ...);
244706c3fb27SDimitry Andric     addToFunctionSummaryMap(
244806c3fb27SDimitry Andric         "openat",
244906c3fb27SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
245006c3fb27SDimitry Andric         Summary(NoEvalCall)
245106c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
245206c3fb27SDimitry Andric                   GenericSuccessMsg)
245306c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
245406c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
245506c3fb27SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
245606c3fb27SDimitry Andric 
24575ffd83dbSDimitry Andric     // int access(const char *pathname, int amode);
2458e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2459e8d8bef9SDimitry Andric         "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2460e8d8bef9SDimitry Andric         Summary(NoEvalCall)
246106c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
246206c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24635ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
24645ffd83dbSDimitry Andric 
24655ffd83dbSDimitry Andric     // int faccessat(int dirfd, const char *pathname, int mode, int flags);
24665ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2467e8d8bef9SDimitry Andric         "faccessat",
2468e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2469e8d8bef9SDimitry Andric                   RetType{IntTy}),
2470e8d8bef9SDimitry Andric         Summary(NoEvalCall)
247106c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
247206c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
247306c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
24745ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
24755ffd83dbSDimitry Andric 
24765ffd83dbSDimitry Andric     // int dup(int fildes);
247781ad6265SDimitry Andric     addToFunctionSummaryMap(
247881ad6265SDimitry Andric         "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2479e8d8bef9SDimitry Andric         Summary(NoEvalCall)
248006c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
248106c3fb27SDimitry Andric                   GenericSuccessMsg)
248206c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
248381ad6265SDimitry Andric             .ArgConstraint(
248481ad6265SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
24855ffd83dbSDimitry Andric 
24865ffd83dbSDimitry Andric     // int dup2(int fildes1, int filedes2);
24875ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2488e8d8bef9SDimitry Andric         "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2489e8d8bef9SDimitry Andric         Summary(NoEvalCall)
249006c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
249106c3fb27SDimitry Andric                   GenericSuccessMsg)
249206c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24935ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
24945ffd83dbSDimitry Andric             .ArgConstraint(
24955ffd83dbSDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
24965ffd83dbSDimitry Andric 
24975ffd83dbSDimitry Andric     // int fdatasync(int fildes);
249806c3fb27SDimitry Andric     addToFunctionSummaryMap(
249906c3fb27SDimitry Andric         "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2500e8d8bef9SDimitry Andric         Summary(NoEvalCall)
250106c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
250206c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
250306c3fb27SDimitry Andric             .ArgConstraint(
250406c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
25055ffd83dbSDimitry Andric 
25065ffd83dbSDimitry Andric     // int fnmatch(const char *pattern, const char *string, int flags);
25075ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2508e8d8bef9SDimitry Andric         "fnmatch",
2509e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2510e8d8bef9SDimitry Andric                   RetType{IntTy}),
251181ad6265SDimitry Andric         Summary(NoEvalCall)
25125ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
25135ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
25145ffd83dbSDimitry Andric 
25155ffd83dbSDimitry Andric     // int fsync(int fildes);
251606c3fb27SDimitry Andric     addToFunctionSummaryMap(
251706c3fb27SDimitry Andric         "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2518e8d8bef9SDimitry Andric         Summary(NoEvalCall)
251906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
252006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
252106c3fb27SDimitry Andric             .ArgConstraint(
252206c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
25235ffd83dbSDimitry Andric 
25245ffd83dbSDimitry Andric     // int truncate(const char *path, off_t length);
2525e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2526e8d8bef9SDimitry Andric         "truncate",
2527e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2528e8d8bef9SDimitry Andric         Summary(NoEvalCall)
252906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
253006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25315ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
25325ffd83dbSDimitry Andric 
25335ffd83dbSDimitry Andric     // int symlink(const char *oldpath, const char *newpath);
2534e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2535e8d8bef9SDimitry Andric         "symlink",
2536e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2537e8d8bef9SDimitry Andric         Summary(NoEvalCall)
253806c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
253906c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25405ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
25415ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
25425ffd83dbSDimitry Andric 
25435ffd83dbSDimitry Andric     // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
25445ffd83dbSDimitry Andric     addToFunctionSummaryMap(
25455ffd83dbSDimitry Andric         "symlinkat",
2546e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2547e8d8bef9SDimitry Andric                   RetType{IntTy}),
2548e8d8bef9SDimitry Andric         Summary(NoEvalCall)
254906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
255006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25515ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
255206c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
25535ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
25545ffd83dbSDimitry Andric 
25555ffd83dbSDimitry Andric     // int lockf(int fd, int cmd, off_t len);
25565ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2557e8d8bef9SDimitry Andric         "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2558e8d8bef9SDimitry Andric         Summary(NoEvalCall)
255906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
256006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25615ffd83dbSDimitry Andric             .ArgConstraint(
25625ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
25635ffd83dbSDimitry Andric 
2564bdd1243dSDimitry Andric     std::optional<QualType> Mode_tTy = lookupTy("mode_t");
25655ffd83dbSDimitry Andric 
25665ffd83dbSDimitry Andric     // int creat(const char *pathname, mode_t mode);
2567e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2568e8d8bef9SDimitry Andric         "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2569e8d8bef9SDimitry Andric         Summary(NoEvalCall)
257006c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
257106c3fb27SDimitry Andric                   GenericSuccessMsg)
257206c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25735ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
25745ffd83dbSDimitry Andric 
25755ffd83dbSDimitry Andric     // unsigned int sleep(unsigned int seconds);
25765ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2577e8d8bef9SDimitry Andric         "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2578e8d8bef9SDimitry Andric         Summary(NoEvalCall)
25795ffd83dbSDimitry Andric             .ArgConstraint(
25805ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
25815ffd83dbSDimitry Andric 
2582bdd1243dSDimitry Andric     std::optional<QualType> DirTy = lookupTy("DIR");
2583bdd1243dSDimitry Andric     std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
25845ffd83dbSDimitry Andric 
25855ffd83dbSDimitry Andric     // int dirfd(DIR *dirp);
258681ad6265SDimitry Andric     addToFunctionSummaryMap(
258781ad6265SDimitry Andric         "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2588e8d8bef9SDimitry Andric         Summary(NoEvalCall)
258906c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
259006c3fb27SDimitry Andric                   GenericSuccessMsg)
259106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25925ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
25935ffd83dbSDimitry Andric 
25945ffd83dbSDimitry Andric     // unsigned int alarm(unsigned int seconds);
25955ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2596e8d8bef9SDimitry Andric         "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2597e8d8bef9SDimitry Andric         Summary(NoEvalCall)
25985ffd83dbSDimitry Andric             .ArgConstraint(
25995ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
26005ffd83dbSDimitry Andric 
26015ffd83dbSDimitry Andric     // int closedir(DIR *dir);
260206c3fb27SDimitry Andric     addToFunctionSummaryMap(
260306c3fb27SDimitry Andric         "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2604e8d8bef9SDimitry Andric         Summary(NoEvalCall)
260506c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
260606c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26075ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
26085ffd83dbSDimitry Andric 
26095ffd83dbSDimitry Andric     // char *strdup(const char *s);
2610e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2611e8d8bef9SDimitry Andric         "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2612e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
26135ffd83dbSDimitry Andric 
26145ffd83dbSDimitry Andric     // char *strndup(const char *s, size_t n);
26155ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2616e8d8bef9SDimitry Andric         "strndup",
2617e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
2618e8d8bef9SDimitry Andric         Summary(NoEvalCall)
26195ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
2620e8d8bef9SDimitry Andric             .ArgConstraint(
2621e8d8bef9SDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
26225ffd83dbSDimitry Andric 
26235ffd83dbSDimitry Andric     // wchar_t *wcsdup(const wchar_t *s);
2624e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2625e8d8bef9SDimitry Andric         "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2626e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
26275ffd83dbSDimitry Andric 
26285ffd83dbSDimitry Andric     // int mkstemp(char *template);
262981ad6265SDimitry Andric     addToFunctionSummaryMap(
263081ad6265SDimitry Andric         "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2631e8d8bef9SDimitry Andric         Summary(NoEvalCall)
263206c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
263306c3fb27SDimitry Andric                   GenericSuccessMsg)
263406c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26355ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
26365ffd83dbSDimitry Andric 
26375ffd83dbSDimitry Andric     // char *mkdtemp(char *template);
26385ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2639e8d8bef9SDimitry Andric         "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
26401db9f3b2SDimitry Andric         Summary(NoEvalCall)
26411db9f3b2SDimitry Andric             .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},
26421db9f3b2SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
26431db9f3b2SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26441db9f3b2SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
26455ffd83dbSDimitry Andric 
26465ffd83dbSDimitry Andric     // char *getcwd(char *buf, size_t size);
26475ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2648e8d8bef9SDimitry Andric         "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
2649e8d8bef9SDimitry Andric         Summary(NoEvalCall)
26501db9f3b2SDimitry Andric             .Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
26511db9f3b2SDimitry Andric                    ReturnValueCondition(BO_EQ, ArgNo(0))},
26521db9f3b2SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
26531db9f3b2SDimitry Andric             .Case({ArgumentCondition(1, WithinRange, SingleValue(0)),
26541db9f3b2SDimitry Andric                    IsNull(Ret)},
26551db9f3b2SDimitry Andric                   ErrnoNEZeroIrrelevant, "Assuming that argument 'size' is 0")
26561db9f3b2SDimitry Andric             .Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
26571db9f3b2SDimitry Andric                    IsNull(Ret)},
26581db9f3b2SDimitry Andric                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
26591db9f3b2SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
26601db9f3b2SDimitry Andric             .ArgConstraint(
26611db9f3b2SDimitry Andric                 BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
26625ffd83dbSDimitry Andric             .ArgConstraint(
26635ffd83dbSDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
26645ffd83dbSDimitry Andric 
26655ffd83dbSDimitry Andric     // int mkdir(const char *pathname, mode_t mode);
2666e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2667e8d8bef9SDimitry Andric         "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2668e8d8bef9SDimitry Andric         Summary(NoEvalCall)
266906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
267006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26715ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
26725ffd83dbSDimitry Andric 
26735ffd83dbSDimitry Andric     // int mkdirat(int dirfd, const char *pathname, mode_t mode);
26745ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2675e8d8bef9SDimitry Andric         "mkdirat",
2676e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2677e8d8bef9SDimitry Andric         Summary(NoEvalCall)
267806c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
267906c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
268006c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
26815ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
26825ffd83dbSDimitry Andric 
2683bdd1243dSDimitry Andric     std::optional<QualType> Dev_tTy = lookupTy("dev_t");
26845ffd83dbSDimitry Andric 
26855ffd83dbSDimitry Andric     // int mknod(const char *pathname, mode_t mode, dev_t dev);
26865ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2687e8d8bef9SDimitry Andric         "mknod",
2688e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2689e8d8bef9SDimitry Andric         Summary(NoEvalCall)
269006c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
269106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26925ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
26935ffd83dbSDimitry Andric 
26945ffd83dbSDimitry Andric     // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2695e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2696e8d8bef9SDimitry Andric         "mknodat",
2697e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2698e8d8bef9SDimitry Andric                   RetType{IntTy}),
2699e8d8bef9SDimitry Andric         Summary(NoEvalCall)
270006c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
270106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
270206c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
27035ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
27045ffd83dbSDimitry Andric 
27055ffd83dbSDimitry Andric     // int chmod(const char *path, mode_t mode);
2706e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2707e8d8bef9SDimitry Andric         "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2708e8d8bef9SDimitry Andric         Summary(NoEvalCall)
270906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
271006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27115ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
27125ffd83dbSDimitry Andric 
27135ffd83dbSDimitry Andric     // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
27145ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2715e8d8bef9SDimitry Andric         "fchmodat",
2716e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2717e8d8bef9SDimitry Andric                   RetType{IntTy}),
2718e8d8bef9SDimitry Andric         Summary(NoEvalCall)
271906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
272006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
272106c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
27225ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
27235ffd83dbSDimitry Andric 
27245ffd83dbSDimitry Andric     // int fchmod(int fildes, mode_t mode);
27255ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2726e8d8bef9SDimitry Andric         "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2727e8d8bef9SDimitry Andric         Summary(NoEvalCall)
272806c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
272906c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27305ffd83dbSDimitry Andric             .ArgConstraint(
27315ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
27325ffd83dbSDimitry Andric 
2733bdd1243dSDimitry Andric     std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2734bdd1243dSDimitry Andric     std::optional<QualType> Gid_tTy = lookupTy("gid_t");
27355ffd83dbSDimitry Andric 
27365ffd83dbSDimitry Andric     // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
27375ffd83dbSDimitry Andric     //              int flags);
27385ffd83dbSDimitry Andric     addToFunctionSummaryMap(
27395ffd83dbSDimitry Andric         "fchownat",
2740e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2741e8d8bef9SDimitry Andric                   RetType{IntTy}),
2742e8d8bef9SDimitry Andric         Summary(NoEvalCall)
274306c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
274406c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
274506c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
27465ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
27475ffd83dbSDimitry Andric 
27485ffd83dbSDimitry Andric     // int chown(const char *path, uid_t owner, gid_t group);
27495ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2750e8d8bef9SDimitry Andric         "chown",
2751e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2752e8d8bef9SDimitry Andric         Summary(NoEvalCall)
275306c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
275406c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27555ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
27565ffd83dbSDimitry Andric 
27575ffd83dbSDimitry Andric     // int lchown(const char *path, uid_t owner, gid_t group);
27585ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2759e8d8bef9SDimitry Andric         "lchown",
2760e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2761e8d8bef9SDimitry Andric         Summary(NoEvalCall)
276206c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
276306c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27645ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
27655ffd83dbSDimitry Andric 
27665ffd83dbSDimitry Andric     // int fchown(int fildes, uid_t owner, gid_t group);
27675ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2768e8d8bef9SDimitry Andric         "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2769e8d8bef9SDimitry Andric         Summary(NoEvalCall)
277006c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
277106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2772e8d8bef9SDimitry Andric             .ArgConstraint(
2773e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
27745ffd83dbSDimitry Andric 
27755ffd83dbSDimitry Andric     // int rmdir(const char *pathname);
277606c3fb27SDimitry Andric     addToFunctionSummaryMap(
277706c3fb27SDimitry Andric         "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2778e8d8bef9SDimitry Andric         Summary(NoEvalCall)
277906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
278006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27815ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
27825ffd83dbSDimitry Andric 
27835ffd83dbSDimitry Andric     // int chdir(const char *path);
278406c3fb27SDimitry Andric     addToFunctionSummaryMap(
278506c3fb27SDimitry Andric         "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2786e8d8bef9SDimitry Andric         Summary(NoEvalCall)
278706c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
278806c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27895ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
27905ffd83dbSDimitry Andric 
27915ffd83dbSDimitry Andric     // int link(const char *oldpath, const char *newpath);
2792e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2793e8d8bef9SDimitry Andric         "link",
2794e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2795e8d8bef9SDimitry Andric         Summary(NoEvalCall)
279606c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
279706c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27985ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
27995ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
28005ffd83dbSDimitry Andric 
28015ffd83dbSDimitry Andric     // int linkat(int fd1, const char *path1, int fd2, const char *path2,
28025ffd83dbSDimitry Andric     //            int flag);
28035ffd83dbSDimitry Andric     addToFunctionSummaryMap(
28045ffd83dbSDimitry Andric         "linkat",
2805e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2806e8d8bef9SDimitry Andric                   RetType{IntTy}),
2807e8d8bef9SDimitry Andric         Summary(NoEvalCall)
280806c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
280906c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
281006c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
28115ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
281206c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
28135ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(3))));
28145ffd83dbSDimitry Andric 
28155ffd83dbSDimitry Andric     // int unlink(const char *pathname);
281606c3fb27SDimitry Andric     addToFunctionSummaryMap(
281706c3fb27SDimitry Andric         "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2818e8d8bef9SDimitry Andric         Summary(NoEvalCall)
281906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
282006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28215ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
28225ffd83dbSDimitry Andric 
28235ffd83dbSDimitry Andric     // int unlinkat(int fd, const char *path, int flag);
28245ffd83dbSDimitry Andric     addToFunctionSummaryMap(
28255ffd83dbSDimitry Andric         "unlinkat",
2826e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2827e8d8bef9SDimitry Andric         Summary(NoEvalCall)
282806c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
282906c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
283006c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
28315ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
28325ffd83dbSDimitry Andric 
2833bdd1243dSDimitry Andric     std::optional<QualType> StructStatTy = lookupTy("stat");
2834bdd1243dSDimitry Andric     std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2835bdd1243dSDimitry Andric     std::optional<QualType> StructStatPtrRestrictTy =
2836bdd1243dSDimitry Andric         getRestrictTy(StructStatPtrTy);
28375ffd83dbSDimitry Andric 
28385ffd83dbSDimitry Andric     // int fstat(int fd, struct stat *statbuf);
28395ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2840e8d8bef9SDimitry Andric         "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2841e8d8bef9SDimitry Andric         Summary(NoEvalCall)
284206c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
284306c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2844e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
28455ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
28465ffd83dbSDimitry Andric 
28475ffd83dbSDimitry Andric     // int stat(const char *restrict path, struct stat *restrict buf);
28485ffd83dbSDimitry Andric     addToFunctionSummaryMap(
28495ffd83dbSDimitry Andric         "stat",
2850e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2851e8d8bef9SDimitry Andric                   RetType{IntTy}),
2852e8d8bef9SDimitry Andric         Summary(NoEvalCall)
285306c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
285406c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28555ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
28565ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
28575ffd83dbSDimitry Andric 
28585ffd83dbSDimitry Andric     // int lstat(const char *restrict path, struct stat *restrict buf);
28595ffd83dbSDimitry Andric     addToFunctionSummaryMap(
28605ffd83dbSDimitry Andric         "lstat",
2861e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2862e8d8bef9SDimitry Andric                   RetType{IntTy}),
2863e8d8bef9SDimitry Andric         Summary(NoEvalCall)
286406c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
286506c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28665ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
28675ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
28685ffd83dbSDimitry Andric 
28695ffd83dbSDimitry Andric     // int fstatat(int fd, const char *restrict path,
28705ffd83dbSDimitry Andric     //             struct stat *restrict buf, int flag);
28715ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2872e8d8bef9SDimitry Andric         "fstatat",
2873e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2874e8d8bef9SDimitry Andric                            StructStatPtrRestrictTy, IntTy},
2875e8d8bef9SDimitry Andric                   RetType{IntTy}),
2876e8d8bef9SDimitry Andric         Summary(NoEvalCall)
287706c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
287806c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
287906c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
28805ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
28815ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
28825ffd83dbSDimitry Andric 
28835ffd83dbSDimitry Andric     // DIR *opendir(const char *name);
2884e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2885e8d8bef9SDimitry Andric         "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
28867a6dacacSDimitry Andric         Summary(NoEvalCall)
28877a6dacacSDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
28887a6dacacSDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28897a6dacacSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
28905ffd83dbSDimitry Andric 
28915ffd83dbSDimitry Andric     // DIR *fdopendir(int fd);
28927a6dacacSDimitry Andric     addToFunctionSummaryMap(
28937a6dacacSDimitry Andric         "fdopendir", Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2894e8d8bef9SDimitry Andric         Summary(NoEvalCall)
28957a6dacacSDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
28967a6dacacSDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28977a6dacacSDimitry Andric             .ArgConstraint(
28987a6dacacSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
28995ffd83dbSDimitry Andric 
29005ffd83dbSDimitry Andric     // int isatty(int fildes);
29015ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2902e8d8bef9SDimitry Andric         "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2903e8d8bef9SDimitry Andric         Summary(NoEvalCall)
290481ad6265SDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
290581ad6265SDimitry Andric                   ErrnoIrrelevant)
29065ffd83dbSDimitry Andric             .ArgConstraint(
29075ffd83dbSDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
29085ffd83dbSDimitry Andric 
29095ffd83dbSDimitry Andric     // int close(int fildes);
291006c3fb27SDimitry Andric     addToFunctionSummaryMap(
291106c3fb27SDimitry Andric         "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2912e8d8bef9SDimitry Andric         Summary(NoEvalCall)
291306c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
291406c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
291506c3fb27SDimitry Andric             .ArgConstraint(
291606c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(-1, IntMax))));
29175ffd83dbSDimitry Andric 
29185ffd83dbSDimitry Andric     // long fpathconf(int fildes, int name);
2919e8d8bef9SDimitry Andric     addToFunctionSummaryMap("fpathconf",
2920e8d8bef9SDimitry Andric                             Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2921e8d8bef9SDimitry Andric                             Summary(NoEvalCall)
2922e8d8bef9SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
2923e8d8bef9SDimitry Andric                                     0, WithinRange, Range(0, IntMax))));
29245ffd83dbSDimitry Andric 
29255ffd83dbSDimitry Andric     // long pathconf(const char *path, int name);
2926e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2927e8d8bef9SDimitry Andric         "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2928e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
29295ffd83dbSDimitry Andric 
29305ffd83dbSDimitry Andric     // void rewinddir(DIR *dir);
29315ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2932e8d8bef9SDimitry Andric         "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2933e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
29345ffd83dbSDimitry Andric 
29355ffd83dbSDimitry Andric     // void seekdir(DIR *dirp, long loc);
2936e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
2937e8d8bef9SDimitry Andric         "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2938e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
29395ffd83dbSDimitry Andric 
29405ffd83dbSDimitry Andric     // int rand_r(unsigned int *seedp);
29415ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2942e8d8bef9SDimitry Andric         "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2943e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
29445ffd83dbSDimitry Andric 
29455ffd83dbSDimitry Andric     // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
29465ffd83dbSDimitry Andric     // off_t offset);
294781ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
29485ffd83dbSDimitry Andric     addToFunctionSummaryMap(
29495ffd83dbSDimitry Andric         "mmap",
2950e8d8bef9SDimitry Andric         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
2951e8d8bef9SDimitry Andric                   RetType{VoidPtrTy}),
2952e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2953e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
29545ffd83dbSDimitry Andric             .ArgConstraint(
2955e8d8bef9SDimitry Andric                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
29565ffd83dbSDimitry Andric 
2957bdd1243dSDimitry Andric     std::optional<QualType> Off64_tTy = lookupTy("off64_t");
29585ffd83dbSDimitry Andric     // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
29595ffd83dbSDimitry Andric     // off64_t offset);
296081ad6265SDimitry Andric     // FIXME: Improve for errno modeling.
29615ffd83dbSDimitry Andric     addToFunctionSummaryMap(
29625ffd83dbSDimitry Andric         "mmap64",
2963e8d8bef9SDimitry Andric         Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
2964e8d8bef9SDimitry Andric                   RetType{VoidPtrTy}),
2965e8d8bef9SDimitry Andric         Summary(NoEvalCall)
2966e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
29675ffd83dbSDimitry Andric             .ArgConstraint(
2968e8d8bef9SDimitry Andric                 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
29695ffd83dbSDimitry Andric 
29705ffd83dbSDimitry Andric     // int pipe(int fildes[2]);
297106c3fb27SDimitry Andric     addToFunctionSummaryMap(
297206c3fb27SDimitry Andric         "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2973e8d8bef9SDimitry Andric         Summary(NoEvalCall)
297406c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
297506c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
29765ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
29775ffd83dbSDimitry Andric 
29785ffd83dbSDimitry Andric     // off_t lseek(int fildes, off_t offset, int whence);
297981ad6265SDimitry Andric     // In the first case we can not tell for sure if it failed or not.
298081ad6265SDimitry Andric     // A return value different from of the expected offset (that is unknown
298181ad6265SDimitry Andric     // here) may indicate failure. For this reason we do not enforce the errno
298281ad6265SDimitry Andric     // check (can cause false positive).
29835ffd83dbSDimitry Andric     addToFunctionSummaryMap(
2984e8d8bef9SDimitry Andric         "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2985e8d8bef9SDimitry Andric         Summary(NoEvalCall)
298681ad6265SDimitry Andric             .Case(ReturnsNonnegative, ErrnoIrrelevant)
298706c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2988e8d8bef9SDimitry Andric             .ArgConstraint(
2989e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
29905ffd83dbSDimitry Andric 
29915ffd83dbSDimitry Andric     // ssize_t readlink(const char *restrict path, char *restrict buf,
29925ffd83dbSDimitry Andric     //                  size_t bufsize);
29935ffd83dbSDimitry Andric     addToFunctionSummaryMap(
29945ffd83dbSDimitry Andric         "readlink",
2995e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2996e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
2997e8d8bef9SDimitry Andric         Summary(NoEvalCall)
29985f757f3fSDimitry Andric             .Case({ArgumentCondition(2, WithinRange, Range(1, IntMax)),
29995f757f3fSDimitry Andric                    ReturnValueCondition(LessThanOrEq, ArgNo(2)),
30005f757f3fSDimitry Andric                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
300106c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
30025f757f3fSDimitry Andric             .Case({ArgumentCondition(2, WithinRange, SingleValue(0)),
30035f757f3fSDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(0))},
30045f757f3fSDimitry Andric                   ErrnoMustNotBeChecked,
30055f757f3fSDimitry Andric                   "Assuming that argument 'bufsize' is 0")
300606c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
30075ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
30085ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
30095ffd83dbSDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
30105ffd83dbSDimitry Andric                                       /*BufSize=*/ArgNo(2)))
30115ffd83dbSDimitry Andric             .ArgConstraint(
30125ffd83dbSDimitry Andric                 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
30135ffd83dbSDimitry Andric 
30145ffd83dbSDimitry Andric     // ssize_t readlinkat(int fd, const char *restrict path,
30155ffd83dbSDimitry Andric     //                    char *restrict buf, size_t bufsize);
30165ffd83dbSDimitry Andric     addToFunctionSummaryMap(
3017e8d8bef9SDimitry Andric         "readlinkat",
3018e8d8bef9SDimitry Andric         Signature(
3019e8d8bef9SDimitry Andric             ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
3020e8d8bef9SDimitry Andric             RetType{Ssize_tTy}),
3021e8d8bef9SDimitry Andric         Summary(NoEvalCall)
30225f757f3fSDimitry Andric             .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)),
30235f757f3fSDimitry Andric                    ReturnValueCondition(LessThanOrEq, ArgNo(3)),
30245f757f3fSDimitry Andric                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
302506c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
30265f757f3fSDimitry Andric             .Case({ArgumentCondition(3, WithinRange, SingleValue(0)),
30275f757f3fSDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(0))},
30285f757f3fSDimitry Andric                   ErrnoMustNotBeChecked,
30295f757f3fSDimitry Andric                   "Assuming that argument 'bufsize' is 0")
303006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
303106c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
30325ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
30335ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2)))
30345ffd83dbSDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
30355ffd83dbSDimitry Andric                                       /*BufSize=*/ArgNo(3)))
3036e8d8bef9SDimitry Andric             .ArgConstraint(
3037e8d8bef9SDimitry Andric                 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
30385ffd83dbSDimitry Andric 
30395ffd83dbSDimitry Andric     // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
30405ffd83dbSDimitry Andric     // *newpath);
3041e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3042e8d8bef9SDimitry Andric         "renameat",
3043e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
3044e8d8bef9SDimitry Andric                   RetType{IntTy}),
3045e8d8bef9SDimitry Andric         Summary(NoEvalCall)
304606c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
304706c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
304806c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
30495ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
305006c3fb27SDimitry Andric             .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
30515ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(3))));
30525ffd83dbSDimitry Andric 
30535ffd83dbSDimitry Andric     // char *realpath(const char *restrict file_name,
30545ffd83dbSDimitry Andric     //                char *restrict resolved_name);
3055*0fca6ea1SDimitry Andric     // FIXME: If the argument 'resolved_name' is not NULL, macro 'PATH_MAX'
3056*0fca6ea1SDimitry Andric     //        should be defined in "limits.h" to guarrantee a success.
30575ffd83dbSDimitry Andric     addToFunctionSummaryMap(
3058e8d8bef9SDimitry Andric         "realpath",
3059e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
3060e8d8bef9SDimitry Andric                   RetType{CharPtrTy}),
3061*0fca6ea1SDimitry Andric         Summary(NoEvalCall)
3062*0fca6ea1SDimitry Andric             .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
3063*0fca6ea1SDimitry Andric             .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3064*0fca6ea1SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
30655ffd83dbSDimitry Andric 
3066e8d8bef9SDimitry Andric     QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
30675ffd83dbSDimitry Andric 
30685ffd83dbSDimitry Andric     // int execv(const char *path, char *const argv[]);
3069e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3070e8d8bef9SDimitry Andric         "execv",
3071e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3072e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3073*0fca6ea1SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
30745ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
30755ffd83dbSDimitry Andric 
30765ffd83dbSDimitry Andric     // int execvp(const char *file, char *const argv[]);
3077e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3078e8d8bef9SDimitry Andric         "execvp",
3079e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3080e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3081*0fca6ea1SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
30825ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
30835ffd83dbSDimitry Andric 
30845ffd83dbSDimitry Andric     // int getopt(int argc, char * const argv[], const char *optstring);
30855ffd83dbSDimitry Andric     addToFunctionSummaryMap(
30865ffd83dbSDimitry Andric         "getopt",
3087e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
3088e8d8bef9SDimitry Andric                   RetType{IntTy}),
3089e8d8bef9SDimitry Andric         Summary(NoEvalCall)
309081ad6265SDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
309181ad6265SDimitry Andric                   ErrnoIrrelevant)
30925ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
30935ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
30945ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
3095e8d8bef9SDimitry Andric 
3096bdd1243dSDimitry Andric     std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
3097bdd1243dSDimitry Andric     std::optional<QualType> StructSockaddrPtrTy =
3098bdd1243dSDimitry Andric         getPointerTy(StructSockaddrTy);
3099bdd1243dSDimitry Andric     std::optional<QualType> ConstStructSockaddrPtrTy =
3100e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructSockaddrTy));
3101bdd1243dSDimitry Andric     std::optional<QualType> StructSockaddrPtrRestrictTy =
3102e8d8bef9SDimitry Andric         getRestrictTy(StructSockaddrPtrTy);
3103bdd1243dSDimitry Andric     std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
3104e8d8bef9SDimitry Andric         getRestrictTy(ConstStructSockaddrPtrTy);
3105bdd1243dSDimitry Andric     std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
3106bdd1243dSDimitry Andric     std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
3107bdd1243dSDimitry Andric     std::optional<QualType> Socklen_tPtrRestrictTy =
3108bdd1243dSDimitry Andric         getRestrictTy(Socklen_tPtrTy);
3109bdd1243dSDimitry Andric     std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
3110e8d8bef9SDimitry Andric 
3111e8d8bef9SDimitry Andric     // In 'socket.h' of some libc implementations with C99, sockaddr parameter
3112e8d8bef9SDimitry Andric     // is a transparent union of the underlying sockaddr_ family of pointers
3113e8d8bef9SDimitry Andric     // instead of being a pointer to struct sockaddr. In these cases, the
3114e8d8bef9SDimitry Andric     // standardized signature will not match, thus we try to match with another
3115e8d8bef9SDimitry Andric     // signature that has the joker Irrelevant type. We also remove those
3116e8d8bef9SDimitry Andric     // constraints which require pointer types for the sockaddr param.
311706c3fb27SDimitry Andric 
311806c3fb27SDimitry Andric     // int socket(int domain, int type, int protocol);
311906c3fb27SDimitry Andric     addToFunctionSummaryMap(
312006c3fb27SDimitry Andric         "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),
312106c3fb27SDimitry Andric         Summary(NoEvalCall)
312206c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
312306c3fb27SDimitry Andric                   GenericSuccessMsg)
312406c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg));
312506c3fb27SDimitry Andric 
3126e8d8bef9SDimitry Andric     auto Accept =
3127e8d8bef9SDimitry Andric         Summary(NoEvalCall)
312806c3fb27SDimitry Andric             .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
312906c3fb27SDimitry Andric                   GenericSuccessMsg)
313006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3131e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
3132e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3133e8d8bef9SDimitry Andric             "accept",
3134e8d8bef9SDimitry Andric             // int accept(int socket, struct sockaddr *restrict address,
3135e8d8bef9SDimitry Andric             //            socklen_t *restrict address_len);
3136e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3137e8d8bef9SDimitry Andric                                Socklen_tPtrRestrictTy},
3138e8d8bef9SDimitry Andric                       RetType{IntTy}),
3139e8d8bef9SDimitry Andric             Accept))
3140e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3141e8d8bef9SDimitry Andric           "accept",
3142e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3143e8d8bef9SDimitry Andric                     RetType{IntTy}),
3144e8d8bef9SDimitry Andric           Accept);
3145e8d8bef9SDimitry Andric 
3146e8d8bef9SDimitry Andric     // int bind(int socket, const struct sockaddr *address, socklen_t
3147e8d8bef9SDimitry Andric     //          address_len);
3148e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3149e8d8bef9SDimitry Andric             "bind",
3150e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3151e8d8bef9SDimitry Andric                       RetType{IntTy}),
3152e8d8bef9SDimitry Andric             Summary(NoEvalCall)
315306c3fb27SDimitry Andric                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
315406c3fb27SDimitry Andric                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3155e8d8bef9SDimitry Andric                 .ArgConstraint(
3156e8d8bef9SDimitry Andric                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3157e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(1)))
3158e8d8bef9SDimitry Andric                 .ArgConstraint(
3159e8d8bef9SDimitry Andric                     BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3160e8d8bef9SDimitry Andric                 .ArgConstraint(
3161e8d8bef9SDimitry Andric                     ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
3162e8d8bef9SDimitry Andric       // Do not add constraints on sockaddr.
3163e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3164e8d8bef9SDimitry Andric           "bind",
3165e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3166e8d8bef9SDimitry Andric           Summary(NoEvalCall)
316706c3fb27SDimitry Andric               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
316806c3fb27SDimitry Andric               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3169e8d8bef9SDimitry Andric               .ArgConstraint(
3170e8d8bef9SDimitry Andric                   ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3171e8d8bef9SDimitry Andric               .ArgConstraint(
3172e8d8bef9SDimitry Andric                   ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
3173e8d8bef9SDimitry Andric 
3174e8d8bef9SDimitry Andric     // int getpeername(int socket, struct sockaddr *restrict address,
3175e8d8bef9SDimitry Andric     //                 socklen_t *restrict address_len);
3176e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3177e8d8bef9SDimitry Andric             "getpeername",
3178e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3179e8d8bef9SDimitry Andric                                Socklen_tPtrRestrictTy},
3180e8d8bef9SDimitry Andric                       RetType{IntTy}),
3181e8d8bef9SDimitry Andric             Summary(NoEvalCall)
318206c3fb27SDimitry Andric                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
318306c3fb27SDimitry Andric                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3184e8d8bef9SDimitry Andric                 .ArgConstraint(
3185e8d8bef9SDimitry Andric                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3186e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(1)))
3187e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(2)))))
3188e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3189e8d8bef9SDimitry Andric           "getpeername",
3190e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3191e8d8bef9SDimitry Andric                     RetType{IntTy}),
3192e8d8bef9SDimitry Andric           Summary(NoEvalCall)
319306c3fb27SDimitry Andric               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
319406c3fb27SDimitry Andric               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3195e8d8bef9SDimitry Andric               .ArgConstraint(
3196e8d8bef9SDimitry Andric                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3197e8d8bef9SDimitry Andric 
3198e8d8bef9SDimitry Andric     // int getsockname(int socket, struct sockaddr *restrict address,
3199e8d8bef9SDimitry Andric     //                 socklen_t *restrict address_len);
3200e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3201e8d8bef9SDimitry Andric             "getsockname",
3202e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3203e8d8bef9SDimitry Andric                                Socklen_tPtrRestrictTy},
3204e8d8bef9SDimitry Andric                       RetType{IntTy}),
3205e8d8bef9SDimitry Andric             Summary(NoEvalCall)
320606c3fb27SDimitry Andric                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
320706c3fb27SDimitry Andric                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3208e8d8bef9SDimitry Andric                 .ArgConstraint(
3209e8d8bef9SDimitry Andric                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3210e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(1)))
3211e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(2)))))
3212e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3213e8d8bef9SDimitry Andric           "getsockname",
3214e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3215e8d8bef9SDimitry Andric                     RetType{IntTy}),
3216e8d8bef9SDimitry Andric           Summary(NoEvalCall)
321706c3fb27SDimitry Andric               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
321806c3fb27SDimitry Andric               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3219e8d8bef9SDimitry Andric               .ArgConstraint(
3220e8d8bef9SDimitry Andric                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3221e8d8bef9SDimitry Andric 
3222e8d8bef9SDimitry Andric     // int connect(int socket, const struct sockaddr *address, socklen_t
3223e8d8bef9SDimitry Andric     //             address_len);
3224e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3225e8d8bef9SDimitry Andric             "connect",
3226e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3227e8d8bef9SDimitry Andric                       RetType{IntTy}),
3228e8d8bef9SDimitry Andric             Summary(NoEvalCall)
322906c3fb27SDimitry Andric                 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
323006c3fb27SDimitry Andric                 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3231e8d8bef9SDimitry Andric                 .ArgConstraint(
3232e8d8bef9SDimitry Andric                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3233e8d8bef9SDimitry Andric                 .ArgConstraint(NotNull(ArgNo(1)))))
3234e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3235e8d8bef9SDimitry Andric           "connect",
3236e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3237e8d8bef9SDimitry Andric           Summary(NoEvalCall)
323806c3fb27SDimitry Andric               .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
323906c3fb27SDimitry Andric               .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3240e8d8bef9SDimitry Andric               .ArgConstraint(
3241e8d8bef9SDimitry Andric                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3242e8d8bef9SDimitry Andric 
3243e8d8bef9SDimitry Andric     auto Recvfrom =
3244e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3245e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
32465f757f3fSDimitry Andric                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
32475f757f3fSDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
32485f757f3fSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
32495f757f3fSDimitry Andric                    ArgumentCondition(2, WithinRange, SingleValue(0))},
325006c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
325106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3252e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3253e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3254e8d8bef9SDimitry Andric                                       /*BufSize=*/ArgNo(2)));
3255e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3256e8d8bef9SDimitry Andric             "recvfrom",
3257e8d8bef9SDimitry Andric             // ssize_t recvfrom(int socket, void *restrict buffer,
3258e8d8bef9SDimitry Andric             //                  size_t length,
3259e8d8bef9SDimitry Andric             //                  int flags, struct sockaddr *restrict address,
3260e8d8bef9SDimitry Andric             //                  socklen_t *restrict address_len);
3261e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3262e8d8bef9SDimitry Andric                                StructSockaddrPtrRestrictTy,
3263e8d8bef9SDimitry Andric                                Socklen_tPtrRestrictTy},
3264e8d8bef9SDimitry Andric                       RetType{Ssize_tTy}),
3265e8d8bef9SDimitry Andric             Recvfrom))
3266e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3267e8d8bef9SDimitry Andric           "recvfrom",
3268e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3269e8d8bef9SDimitry Andric                              Irrelevant, Socklen_tPtrRestrictTy},
3270e8d8bef9SDimitry Andric                     RetType{Ssize_tTy}),
3271e8d8bef9SDimitry Andric           Recvfrom);
3272e8d8bef9SDimitry Andric 
3273e8d8bef9SDimitry Andric     auto Sendto =
3274e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3275e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
32765f757f3fSDimitry Andric                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
32775f757f3fSDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
32785f757f3fSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
32795f757f3fSDimitry Andric                    ArgumentCondition(2, WithinRange, SingleValue(0))},
328006c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
328106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3282e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3283e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3284e8d8bef9SDimitry Andric                                       /*BufSize=*/ArgNo(2)));
3285e8d8bef9SDimitry Andric     if (!addToFunctionSummaryMap(
3286e8d8bef9SDimitry Andric             "sendto",
3287e8d8bef9SDimitry Andric             // ssize_t sendto(int socket, const void *message, size_t length,
3288e8d8bef9SDimitry Andric             //                int flags, const struct sockaddr *dest_addr,
3289e8d8bef9SDimitry Andric             //                socklen_t dest_len);
3290e8d8bef9SDimitry Andric             Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
3291e8d8bef9SDimitry Andric                                ConstStructSockaddrPtrTy, Socklen_tTy},
3292e8d8bef9SDimitry Andric                       RetType{Ssize_tTy}),
3293e8d8bef9SDimitry Andric             Sendto))
3294e8d8bef9SDimitry Andric       addToFunctionSummaryMap(
3295e8d8bef9SDimitry Andric           "sendto",
3296e8d8bef9SDimitry Andric           Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
3297e8d8bef9SDimitry Andric                              Socklen_tTy},
3298e8d8bef9SDimitry Andric                     RetType{Ssize_tTy}),
3299e8d8bef9SDimitry Andric           Sendto);
3300e8d8bef9SDimitry Andric 
3301e8d8bef9SDimitry Andric     // int listen(int sockfd, int backlog);
330206c3fb27SDimitry Andric     addToFunctionSummaryMap(
330306c3fb27SDimitry Andric         "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3304e8d8bef9SDimitry Andric         Summary(NoEvalCall)
330506c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
330606c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
330706c3fb27SDimitry Andric             .ArgConstraint(
330806c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3309e8d8bef9SDimitry Andric 
3310e8d8bef9SDimitry Andric     // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3311e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3312e8d8bef9SDimitry Andric         "recv",
3313e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
3314e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
3315e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3316e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
33175f757f3fSDimitry Andric                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
33185f757f3fSDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
33195f757f3fSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
33205f757f3fSDimitry Andric                    ArgumentCondition(2, WithinRange, SingleValue(0))},
332106c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
332206c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3323e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3324e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3325e8d8bef9SDimitry Andric                                       /*BufSize=*/ArgNo(2))));
3326e8d8bef9SDimitry Andric 
3327bdd1243dSDimitry Andric     std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3328bdd1243dSDimitry Andric     std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3329bdd1243dSDimitry Andric     std::optional<QualType> ConstStructMsghdrPtrTy =
3330e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructMsghdrTy));
3331e8d8bef9SDimitry Andric 
3332e8d8bef9SDimitry Andric     // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3333e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3334e8d8bef9SDimitry Andric         "recvmsg",
3335e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3336e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
3337e8d8bef9SDimitry Andric         Summary(NoEvalCall)
33385f757f3fSDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
333906c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
334006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3341e8d8bef9SDimitry Andric             .ArgConstraint(
3342e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3343e8d8bef9SDimitry Andric 
3344e8d8bef9SDimitry Andric     // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3345e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3346e8d8bef9SDimitry Andric         "sendmsg",
3347e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3348e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
3349e8d8bef9SDimitry Andric         Summary(NoEvalCall)
33505f757f3fSDimitry Andric             .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
335106c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
335206c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3353e8d8bef9SDimitry Andric             .ArgConstraint(
3354e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3355e8d8bef9SDimitry Andric 
3356e8d8bef9SDimitry Andric     // int setsockopt(int socket, int level, int option_name,
3357e8d8bef9SDimitry Andric     //                const void *option_value, socklen_t option_len);
3358e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3359e8d8bef9SDimitry Andric         "setsockopt",
3360e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3361e8d8bef9SDimitry Andric                   RetType{IntTy}),
3362e8d8bef9SDimitry Andric         Summary(NoEvalCall)
336306c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
336406c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3365e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(3)))
3366e8d8bef9SDimitry Andric             .ArgConstraint(
3367e8d8bef9SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3368e8d8bef9SDimitry Andric             .ArgConstraint(
3369e8d8bef9SDimitry Andric                 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3370e8d8bef9SDimitry Andric 
3371e8d8bef9SDimitry Andric     // int getsockopt(int socket, int level, int option_name,
3372e8d8bef9SDimitry Andric     //                void *restrict option_value,
3373e8d8bef9SDimitry Andric     //                socklen_t *restrict option_len);
3374e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3375e8d8bef9SDimitry Andric         "getsockopt",
3376e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3377e8d8bef9SDimitry Andric                            Socklen_tPtrRestrictTy},
3378e8d8bef9SDimitry Andric                   RetType{IntTy}),
3379e8d8bef9SDimitry Andric         Summary(NoEvalCall)
338006c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
338106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3382e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(3)))
3383e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(4))));
3384e8d8bef9SDimitry Andric 
3385e8d8bef9SDimitry Andric     // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3386e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3387e8d8bef9SDimitry Andric         "send",
3388e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
3389e8d8bef9SDimitry Andric                   RetType{Ssize_tTy}),
3390e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3391e8d8bef9SDimitry Andric             .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
33925f757f3fSDimitry Andric                    ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
33935f757f3fSDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
33945f757f3fSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
33955f757f3fSDimitry Andric                    ArgumentCondition(2, WithinRange, SingleValue(0))},
339606c3fb27SDimitry Andric                   ErrnoMustNotBeChecked, GenericSuccessMsg)
339706c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3398e8d8bef9SDimitry Andric             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3399e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3400e8d8bef9SDimitry Andric                                       /*BufSize=*/ArgNo(2))));
3401e8d8bef9SDimitry Andric 
3402e8d8bef9SDimitry Andric     // int socketpair(int domain, int type, int protocol, int sv[2]);
3403e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3404e8d8bef9SDimitry Andric         "socketpair",
3405e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3406e8d8bef9SDimitry Andric         Summary(NoEvalCall)
340706c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
340806c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3409e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(3))));
3410e8d8bef9SDimitry Andric 
341106c3fb27SDimitry Andric     // int shutdown(int socket, int how);
341206c3fb27SDimitry Andric     addToFunctionSummaryMap(
341306c3fb27SDimitry Andric         "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
341406c3fb27SDimitry Andric         Summary(NoEvalCall)
341506c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
341606c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
341706c3fb27SDimitry Andric             .ArgConstraint(
341806c3fb27SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
341906c3fb27SDimitry Andric 
3420e8d8bef9SDimitry Andric     // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3421e8d8bef9SDimitry Andric     //                 char *restrict node, socklen_t nodelen,
3422e8d8bef9SDimitry Andric     //                 char *restrict service,
3423e8d8bef9SDimitry Andric     //                 socklen_t servicelen, int flags);
3424e8d8bef9SDimitry Andric     //
3425e8d8bef9SDimitry Andric     // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3426e8d8bef9SDimitry Andric     // parameter is never handled as a transparent union in netdb.h
3427e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3428e8d8bef9SDimitry Andric         "getnameinfo",
3429e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3430e8d8bef9SDimitry Andric                            CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3431e8d8bef9SDimitry Andric                            Socklen_tTy, IntTy},
3432e8d8bef9SDimitry Andric                   RetType{IntTy}),
3433e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3434e8d8bef9SDimitry Andric             .ArgConstraint(
3435e8d8bef9SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3436e8d8bef9SDimitry Andric             .ArgConstraint(
3437e8d8bef9SDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3438e8d8bef9SDimitry Andric             .ArgConstraint(
3439e8d8bef9SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3440e8d8bef9SDimitry Andric             .ArgConstraint(
3441e8d8bef9SDimitry Andric                 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3442e8d8bef9SDimitry Andric             .ArgConstraint(
3443e8d8bef9SDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3444e8d8bef9SDimitry Andric             .ArgConstraint(
3445e8d8bef9SDimitry Andric                 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3446e8d8bef9SDimitry Andric 
3447bdd1243dSDimitry Andric     std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3448bdd1243dSDimitry Andric     std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3449e8d8bef9SDimitry Andric 
3450e8d8bef9SDimitry Andric     // int utime(const char *filename, struct utimbuf *buf);
3451e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3452e8d8bef9SDimitry Andric         "utime",
3453e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3454e8d8bef9SDimitry Andric         Summary(NoEvalCall)
345506c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
345606c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3457e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
3458e8d8bef9SDimitry Andric 
3459bdd1243dSDimitry Andric     std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3460bdd1243dSDimitry Andric     std::optional<QualType> StructTimespecPtrTy =
3461bdd1243dSDimitry Andric         getPointerTy(StructTimespecTy);
3462bdd1243dSDimitry Andric     std::optional<QualType> ConstStructTimespecPtrTy =
3463e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructTimespecTy));
3464e8d8bef9SDimitry Andric 
3465e8d8bef9SDimitry Andric     // int futimens(int fd, const struct timespec times[2]);
3466e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3467e8d8bef9SDimitry Andric         "futimens",
3468e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3469e8d8bef9SDimitry Andric         Summary(NoEvalCall)
347006c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
347106c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3472e8d8bef9SDimitry Andric             .ArgConstraint(
3473e8d8bef9SDimitry Andric                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3474e8d8bef9SDimitry Andric 
3475e8d8bef9SDimitry Andric     // int utimensat(int dirfd, const char *pathname,
3476e8d8bef9SDimitry Andric     //               const struct timespec times[2], int flags);
347706c3fb27SDimitry Andric     addToFunctionSummaryMap(
347806c3fb27SDimitry Andric         "utimensat",
347906c3fb27SDimitry Andric         Signature(
348006c3fb27SDimitry Andric             ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
3481e8d8bef9SDimitry Andric             RetType{IntTy}),
3482e8d8bef9SDimitry Andric         Summary(NoEvalCall)
348306c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
348406c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3485e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3486e8d8bef9SDimitry Andric 
3487bdd1243dSDimitry Andric     std::optional<QualType> StructTimevalTy = lookupTy("timeval");
3488bdd1243dSDimitry Andric     std::optional<QualType> ConstStructTimevalPtrTy =
3489e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructTimevalTy));
3490e8d8bef9SDimitry Andric 
3491e8d8bef9SDimitry Andric     // int utimes(const char *filename, const struct timeval times[2]);
3492e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3493e8d8bef9SDimitry Andric         "utimes",
3494e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3495e8d8bef9SDimitry Andric                   RetType{IntTy}),
3496e8d8bef9SDimitry Andric         Summary(NoEvalCall)
349706c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
349806c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3499e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
3500e8d8bef9SDimitry Andric 
3501e8d8bef9SDimitry Andric     // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3502e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3503e8d8bef9SDimitry Andric         "nanosleep",
3504e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3505e8d8bef9SDimitry Andric                   RetType{IntTy}),
3506e8d8bef9SDimitry Andric         Summary(NoEvalCall)
350706c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
350806c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3509e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0))));
3510e8d8bef9SDimitry Andric 
3511bdd1243dSDimitry Andric     std::optional<QualType> Time_tTy = lookupTy("time_t");
3512bdd1243dSDimitry Andric     std::optional<QualType> ConstTime_tPtrTy =
3513bdd1243dSDimitry Andric         getPointerTy(getConstTy(Time_tTy));
3514bdd1243dSDimitry Andric     std::optional<QualType> ConstTime_tPtrRestrictTy =
3515e8d8bef9SDimitry Andric         getRestrictTy(ConstTime_tPtrTy);
3516e8d8bef9SDimitry Andric 
3517bdd1243dSDimitry Andric     std::optional<QualType> StructTmTy = lookupTy("tm");
3518bdd1243dSDimitry Andric     std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3519bdd1243dSDimitry Andric     std::optional<QualType> StructTmPtrRestrictTy =
3520bdd1243dSDimitry Andric         getRestrictTy(StructTmPtrTy);
3521bdd1243dSDimitry Andric     std::optional<QualType> ConstStructTmPtrTy =
3522e8d8bef9SDimitry Andric         getPointerTy(getConstTy(StructTmTy));
3523bdd1243dSDimitry Andric     std::optional<QualType> ConstStructTmPtrRestrictTy =
3524e8d8bef9SDimitry Andric         getRestrictTy(ConstStructTmPtrTy);
3525e8d8bef9SDimitry Andric 
3526e8d8bef9SDimitry Andric     // struct tm * localtime(const time_t *tp);
3527e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3528e8d8bef9SDimitry Andric         "localtime",
3529e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3530e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3531e8d8bef9SDimitry Andric 
3532e8d8bef9SDimitry Andric     // struct tm *localtime_r(const time_t *restrict timer,
3533e8d8bef9SDimitry Andric     //                        struct tm *restrict result);
3534e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3535e8d8bef9SDimitry Andric         "localtime_r",
3536e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3537e8d8bef9SDimitry Andric                   RetType{StructTmPtrTy}),
3538e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3539e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3540e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3541e8d8bef9SDimitry Andric 
3542e8d8bef9SDimitry Andric     // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3543e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3544e8d8bef9SDimitry Andric         "asctime_r",
3545e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3546e8d8bef9SDimitry Andric                   RetType{CharPtrTy}),
3547e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3548e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3549e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
3550e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3551e8d8bef9SDimitry Andric                                       /*MinBufSize=*/BVF.getValue(26, IntTy))));
3552e8d8bef9SDimitry Andric 
3553e8d8bef9SDimitry Andric     // char *ctime_r(const time_t *timep, char *buf);
3554e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3555e8d8bef9SDimitry Andric         "ctime_r",
3556e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3557e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3558e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3559e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1)))
3560e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(
3561e8d8bef9SDimitry Andric                 /*Buffer=*/ArgNo(1),
3562e8d8bef9SDimitry Andric                 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3563e8d8bef9SDimitry Andric 
3564e8d8bef9SDimitry Andric     // struct tm *gmtime_r(const time_t *restrict timer,
3565e8d8bef9SDimitry Andric     //                     struct tm *restrict result);
3566e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3567e8d8bef9SDimitry Andric         "gmtime_r",
3568e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3569e8d8bef9SDimitry Andric                   RetType{StructTmPtrTy}),
3570e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3571e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3572e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3573e8d8bef9SDimitry Andric 
3574e8d8bef9SDimitry Andric     // struct tm * gmtime(const time_t *tp);
3575e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3576e8d8bef9SDimitry Andric         "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3577e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3578e8d8bef9SDimitry Andric 
3579bdd1243dSDimitry Andric     std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3580e8d8bef9SDimitry Andric 
3581e8d8bef9SDimitry Andric     // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3582e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3583e8d8bef9SDimitry Andric         "clock_gettime",
3584e8d8bef9SDimitry Andric         Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3585e8d8bef9SDimitry Andric         Summary(NoEvalCall)
358606c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
358706c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3588e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3589e8d8bef9SDimitry Andric 
3590bdd1243dSDimitry Andric     std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3591bdd1243dSDimitry Andric     std::optional<QualType> StructItimervalPtrTy =
3592bdd1243dSDimitry Andric         getPointerTy(StructItimervalTy);
3593e8d8bef9SDimitry Andric 
3594e8d8bef9SDimitry Andric     // int getitimer(int which, struct itimerval *curr_value);
3595e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3596e8d8bef9SDimitry Andric         "getitimer",
3597e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3598e8d8bef9SDimitry Andric         Summary(NoEvalCall)
359906c3fb27SDimitry Andric             .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
360006c3fb27SDimitry Andric             .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3601e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3602e8d8bef9SDimitry Andric 
3603bdd1243dSDimitry Andric     std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3604bdd1243dSDimitry Andric     std::optional<QualType> Pthread_cond_tPtrTy =
3605bdd1243dSDimitry Andric         getPointerTy(Pthread_cond_tTy);
3606bdd1243dSDimitry Andric     std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3607bdd1243dSDimitry Andric     std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3608bdd1243dSDimitry Andric     std::optional<QualType> Pthread_tPtrRestrictTy =
3609bdd1243dSDimitry Andric         getRestrictTy(Pthread_tPtrTy);
3610bdd1243dSDimitry Andric     std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3611bdd1243dSDimitry Andric     std::optional<QualType> Pthread_mutex_tPtrTy =
3612bdd1243dSDimitry Andric         getPointerTy(Pthread_mutex_tTy);
3613bdd1243dSDimitry Andric     std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3614e8d8bef9SDimitry Andric         getRestrictTy(Pthread_mutex_tPtrTy);
3615bdd1243dSDimitry Andric     std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3616bdd1243dSDimitry Andric     std::optional<QualType> Pthread_attr_tPtrTy =
3617bdd1243dSDimitry Andric         getPointerTy(Pthread_attr_tTy);
3618bdd1243dSDimitry Andric     std::optional<QualType> ConstPthread_attr_tPtrTy =
3619e8d8bef9SDimitry Andric         getPointerTy(getConstTy(Pthread_attr_tTy));
3620bdd1243dSDimitry Andric     std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3621e8d8bef9SDimitry Andric         getRestrictTy(ConstPthread_attr_tPtrTy);
3622bdd1243dSDimitry Andric     std::optional<QualType> Pthread_mutexattr_tTy =
3623bdd1243dSDimitry Andric         lookupTy("pthread_mutexattr_t");
3624bdd1243dSDimitry Andric     std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3625e8d8bef9SDimitry Andric         getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3626bdd1243dSDimitry Andric     std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3627e8d8bef9SDimitry Andric         getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3628e8d8bef9SDimitry Andric 
3629e8d8bef9SDimitry Andric     QualType PthreadStartRoutineTy = getPointerTy(
3630e8d8bef9SDimitry Andric         ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3631e8d8bef9SDimitry Andric                              FunctionProtoType::ExtProtoInfo()));
3632e8d8bef9SDimitry Andric 
3633e8d8bef9SDimitry Andric     // int pthread_cond_signal(pthread_cond_t *cond);
3634e8d8bef9SDimitry Andric     // int pthread_cond_broadcast(pthread_cond_t *cond);
3635e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3636e8d8bef9SDimitry Andric         {"pthread_cond_signal", "pthread_cond_broadcast"},
3637e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3638e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3639e8d8bef9SDimitry Andric 
3640e8d8bef9SDimitry Andric     // int pthread_create(pthread_t *restrict thread,
3641e8d8bef9SDimitry Andric     //                    const pthread_attr_t *restrict attr,
3642e8d8bef9SDimitry Andric     //                    void *(*start_routine)(void*), void *restrict arg);
3643e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3644e8d8bef9SDimitry Andric         "pthread_create",
3645e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_tPtrRestrictTy,
3646e8d8bef9SDimitry Andric                            ConstPthread_attr_tPtrRestrictTy,
3647e8d8bef9SDimitry Andric                            PthreadStartRoutineTy, VoidPtrRestrictTy},
3648e8d8bef9SDimitry Andric                   RetType{IntTy}),
3649e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3650e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3651e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(2))));
3652e8d8bef9SDimitry Andric 
3653e8d8bef9SDimitry Andric     // int pthread_attr_destroy(pthread_attr_t *attr);
3654e8d8bef9SDimitry Andric     // int pthread_attr_init(pthread_attr_t *attr);
3655e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3656e8d8bef9SDimitry Andric         {"pthread_attr_destroy", "pthread_attr_init"},
3657e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3658e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3659e8d8bef9SDimitry Andric 
3660e8d8bef9SDimitry Andric     // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3661e8d8bef9SDimitry Andric     //                               size_t *restrict stacksize);
3662e8d8bef9SDimitry Andric     // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3663e8d8bef9SDimitry Andric     //                               size_t *restrict guardsize);
3664e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3665e8d8bef9SDimitry Andric         {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3666e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3667e8d8bef9SDimitry Andric                   RetType{IntTy}),
3668e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3669e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3670e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
3671e8d8bef9SDimitry Andric 
3672e8d8bef9SDimitry Andric     // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3673e8d8bef9SDimitry Andric     // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3674e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3675e8d8bef9SDimitry Andric         {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3676e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
3677e8d8bef9SDimitry Andric         Summary(NoEvalCall)
3678e8d8bef9SDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
3679e8d8bef9SDimitry Andric             .ArgConstraint(
3680e8d8bef9SDimitry Andric                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3681e8d8bef9SDimitry Andric 
3682e8d8bef9SDimitry Andric     // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3683e8d8bef9SDimitry Andric     //                        pthread_mutexattr_t *restrict attr);
3684e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3685e8d8bef9SDimitry Andric         "pthread_mutex_init",
3686e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3687e8d8bef9SDimitry Andric                            ConstPthread_mutexattr_tPtrRestrictTy},
3688e8d8bef9SDimitry Andric                   RetType{IntTy}),
3689e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3690e8d8bef9SDimitry Andric 
3691e8d8bef9SDimitry Andric     // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3692e8d8bef9SDimitry Andric     // int pthread_mutex_lock(pthread_mutex_t *mutex);
3693e8d8bef9SDimitry Andric     // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3694e8d8bef9SDimitry Andric     // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3695e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3696e8d8bef9SDimitry Andric         {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3697e8d8bef9SDimitry Andric          "pthread_mutex_unlock"},
3698e8d8bef9SDimitry Andric         Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3699e8d8bef9SDimitry Andric         Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
37005ffd83dbSDimitry Andric   }
37015ffd83dbSDimitry Andric 
37025ffd83dbSDimitry Andric   // Functions for testing.
370306c3fb27SDimitry Andric   if (AddTestFunctions) {
370406c3fb27SDimitry Andric     const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue();
370506c3fb27SDimitry Andric 
37065ffd83dbSDimitry Andric     addToFunctionSummaryMap(
3707fe6060f1SDimitry Andric         "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3708fe6060f1SDimitry Andric         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3709fe6060f1SDimitry Andric 
371006c3fb27SDimitry Andric     addToFunctionSummaryMap(
371106c3fb27SDimitry Andric         "__not_null_buffer",
371206c3fb27SDimitry Andric         Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),
371306c3fb27SDimitry Andric         Summary(EvalCallAsPure)
371406c3fb27SDimitry Andric             .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
371506c3fb27SDimitry Andric 
371606c3fb27SDimitry Andric     // Test inside range constraints.
3717fe6060f1SDimitry Andric     addToFunctionSummaryMap(
3718bdd1243dSDimitry Andric         "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3719bdd1243dSDimitry Andric         Summary(EvalCallAsPure)
3720bdd1243dSDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
3721bdd1243dSDimitry Andric     addToFunctionSummaryMap(
3722fe6060f1SDimitry Andric         "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3723fe6060f1SDimitry Andric         Summary(EvalCallAsPure)
3724fe6060f1SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3725fe6060f1SDimitry Andric     addToFunctionSummaryMap(
3726fe6060f1SDimitry Andric         "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3727fe6060f1SDimitry Andric         Summary(EvalCallAsPure)
3728fe6060f1SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
372906c3fb27SDimitry Andric     addToFunctionSummaryMap(
373006c3fb27SDimitry Andric         "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
373106c3fb27SDimitry Andric         Summary(EvalCallAsPure)
373206c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
373306c3fb27SDimitry Andric     addToFunctionSummaryMap(
373406c3fb27SDimitry Andric         "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
373506c3fb27SDimitry Andric         Summary(EvalCallAsPure)
373606c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
373706c3fb27SDimitry Andric     addToFunctionSummaryMap(
373806c3fb27SDimitry Andric         "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
373906c3fb27SDimitry Andric         Summary(EvalCallAsPure)
374006c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
374106c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_m1_inf",
3742fe6060f1SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
3743fe6060f1SDimitry Andric                             Summary(EvalCallAsPure)
3744fe6060f1SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
374506c3fb27SDimitry Andric                                     0U, WithinRange, Range(-1, IntMax))));
374606c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_0_inf",
374706c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
374806c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
374906c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
375006c3fb27SDimitry Andric                                     0U, WithinRange, Range(0, IntMax))));
375106c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_1_inf",
375206c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
375306c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
375406c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
375506c3fb27SDimitry Andric                                     0U, WithinRange, Range(1, IntMax))));
375606c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_minf_m1",
375706c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
375806c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
375906c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
376006c3fb27SDimitry Andric                                     0U, WithinRange, Range(IntMin, -1))));
376106c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_minf_0",
376206c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
376306c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
376406c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
376506c3fb27SDimitry Andric                                     0U, WithinRange, Range(IntMin, 0))));
376606c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_minf_1",
376706c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
376806c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
376906c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
377006c3fb27SDimitry Andric                                     0U, WithinRange, Range(IntMin, 1))));
377106c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_1_2__4_6",
377206c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
377306c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
377406c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
377506c3fb27SDimitry Andric                                     0U, WithinRange, Range({1, 2}, {4, 6}))));
377606c3fb27SDimitry Andric     addToFunctionSummaryMap(
377706c3fb27SDimitry Andric         "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
377806c3fb27SDimitry Andric         Summary(EvalCallAsPure)
377906c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange,
378006c3fb27SDimitry Andric                                              Range({1, 2}, {4, IntMax}))));
378106c3fb27SDimitry Andric 
378206c3fb27SDimitry Andric     // Test out of range constraints.
378306c3fb27SDimitry Andric     addToFunctionSummaryMap(
378406c3fb27SDimitry Andric         "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
378506c3fb27SDimitry Andric         Summary(EvalCallAsPure)
378606c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
378706c3fb27SDimitry Andric     addToFunctionSummaryMap(
378806c3fb27SDimitry Andric         "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
378906c3fb27SDimitry Andric         Summary(EvalCallAsPure)
379006c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
379106c3fb27SDimitry Andric     addToFunctionSummaryMap(
379206c3fb27SDimitry Andric         "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
379306c3fb27SDimitry Andric         Summary(EvalCallAsPure)
379406c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
379506c3fb27SDimitry Andric     addToFunctionSummaryMap(
379606c3fb27SDimitry Andric         "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
379706c3fb27SDimitry Andric         Summary(EvalCallAsPure)
379806c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
379906c3fb27SDimitry Andric     addToFunctionSummaryMap(
380006c3fb27SDimitry Andric         "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
380106c3fb27SDimitry Andric         Summary(EvalCallAsPure)
380206c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
380306c3fb27SDimitry Andric     addToFunctionSummaryMap(
380406c3fb27SDimitry Andric         "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
380506c3fb27SDimitry Andric         Summary(EvalCallAsPure)
380606c3fb27SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
380706c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_m1_inf",
380806c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
380906c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
381006c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
381106c3fb27SDimitry Andric                                     0U, OutOfRange, Range(-1, IntMax))));
381206c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_0_inf",
381306c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
381406c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
381506c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
381606c3fb27SDimitry Andric                                     0U, OutOfRange, Range(0, IntMax))));
381706c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_1_inf",
381806c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
381906c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
382006c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
382106c3fb27SDimitry Andric                                     0U, OutOfRange, Range(1, IntMax))));
382206c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_minf_m1",
382306c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
382406c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
382506c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
382606c3fb27SDimitry Andric                                     0U, OutOfRange, Range(IntMin, -1))));
382706c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_minf_0",
382806c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
382906c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
383006c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
383106c3fb27SDimitry Andric                                     0U, OutOfRange, Range(IntMin, 0))));
383206c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_minf_1",
383306c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
383406c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
383506c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
383606c3fb27SDimitry Andric                                     0U, OutOfRange, Range(IntMin, 1))));
383706c3fb27SDimitry Andric     addToFunctionSummaryMap("__range_out_1_2__4_6",
383806c3fb27SDimitry Andric                             Signature(ArgTypes{IntTy}, RetType{IntTy}),
383906c3fb27SDimitry Andric                             Summary(EvalCallAsPure)
384006c3fb27SDimitry Andric                                 .ArgConstraint(ArgumentCondition(
384106c3fb27SDimitry Andric                                     0U, OutOfRange, Range({1, 2}, {4, 6}))));
384206c3fb27SDimitry Andric     addToFunctionSummaryMap(
384306c3fb27SDimitry Andric         "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
384406c3fb27SDimitry Andric         Summary(EvalCallAsPure)
384506c3fb27SDimitry Andric             .ArgConstraint(
384606c3fb27SDimitry Andric                 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3847fe6060f1SDimitry Andric 
3848fe6060f1SDimitry Andric     // Test range kind.
3849fe6060f1SDimitry Andric     addToFunctionSummaryMap(
3850fe6060f1SDimitry Andric         "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3851fe6060f1SDimitry Andric         Summary(EvalCallAsPure)
3852fe6060f1SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3853fe6060f1SDimitry Andric     addToFunctionSummaryMap(
3854fe6060f1SDimitry Andric         "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3855fe6060f1SDimitry Andric         Summary(EvalCallAsPure)
3856fe6060f1SDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3857fe6060f1SDimitry Andric 
3858fe6060f1SDimitry Andric     addToFunctionSummaryMap(
38595ffd83dbSDimitry Andric         "__two_constrained_args",
3860e8d8bef9SDimitry Andric         Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3861e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
38625ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
38635ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
38645ffd83dbSDimitry Andric     addToFunctionSummaryMap(
3865e8d8bef9SDimitry Andric         "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3866e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
38675ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
38685ffd83dbSDimitry Andric             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
38695ffd83dbSDimitry Andric     addToFunctionSummaryMap(
38705ffd83dbSDimitry Andric         "__defaultparam",
3871e8d8bef9SDimitry Andric         Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3872e8d8bef9SDimitry Andric         Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3873e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3874e8d8bef9SDimitry Andric         "__variadic",
3875e8d8bef9SDimitry Andric         Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3876e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
38775ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(0)))
38785ffd83dbSDimitry Andric             .ArgConstraint(NotNull(ArgNo(1))));
38795ffd83dbSDimitry Andric     addToFunctionSummaryMap(
38805ffd83dbSDimitry Andric         "__buf_size_arg_constraint",
3881e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
3882e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
38835ffd83dbSDimitry Andric             .ArgConstraint(
38845ffd83dbSDimitry Andric                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
38855ffd83dbSDimitry Andric     addToFunctionSummaryMap(
38865ffd83dbSDimitry Andric         "__buf_size_arg_constraint_mul",
3887e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
3888e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
38895ffd83dbSDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
38905ffd83dbSDimitry Andric                                       /*BufSizeMultiplier=*/ArgNo(2))));
3891e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3892e8d8bef9SDimitry Andric         "__buf_size_arg_constraint_concrete",
3893e8d8bef9SDimitry Andric         Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3894e8d8bef9SDimitry Andric         Summary(EvalCallAsPure)
3895e8d8bef9SDimitry Andric             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3896e8d8bef9SDimitry Andric                                       /*BufSize=*/BVF.getValue(10, IntTy))));
3897e8d8bef9SDimitry Andric     addToFunctionSummaryMap(
3898e8d8bef9SDimitry Andric         {"__test_restrict_param_0", "__test_restrict_param_1",
3899e8d8bef9SDimitry Andric          "__test_restrict_param_2"},
3900e8d8bef9SDimitry Andric         Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3901e8d8bef9SDimitry Andric         Summary(EvalCallAsPure));
3902bdd1243dSDimitry Andric 
3903bdd1243dSDimitry Andric     // Test the application of cases.
3904bdd1243dSDimitry Andric     addToFunctionSummaryMap(
3905bdd1243dSDimitry Andric         "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3906bdd1243dSDimitry Andric         Summary(EvalCallAsPure)
3907bdd1243dSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
3908bdd1243dSDimitry Andric                   ErrnoIrrelevant, "Function returns 0")
3909bdd1243dSDimitry Andric             .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
3910bdd1243dSDimitry Andric                   ErrnoIrrelevant, "Function returns 1"));
391106c3fb27SDimitry Andric     addToFunctionSummaryMap(
391206c3fb27SDimitry Andric         "__test_case_range_1_2__4_6",
391306c3fb27SDimitry Andric         Signature(ArgTypes{IntTy}, RetType{IntTy}),
391406c3fb27SDimitry Andric         Summary(EvalCallAsPure)
391506c3fb27SDimitry Andric             .Case({ArgumentCondition(0U, WithinRange,
391606c3fb27SDimitry Andric                                      IntRangeVector{{IntMin, 0}, {3, 3}}),
391706c3fb27SDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(1))},
391806c3fb27SDimitry Andric                   ErrnoIrrelevant)
391906c3fb27SDimitry Andric             .Case({ArgumentCondition(0U, WithinRange,
392006c3fb27SDimitry Andric                                      IntRangeVector{{3, 3}, {7, IntMax}}),
392106c3fb27SDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(2))},
392206c3fb27SDimitry Andric                   ErrnoIrrelevant)
392306c3fb27SDimitry Andric             .Case({ArgumentCondition(0U, WithinRange,
392406c3fb27SDimitry Andric                                      IntRangeVector{{IntMin, 0}, {7, IntMax}}),
392506c3fb27SDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(3))},
392606c3fb27SDimitry Andric                   ErrnoIrrelevant)
392706c3fb27SDimitry Andric             .Case({ArgumentCondition(
392806c3fb27SDimitry Andric                        0U, WithinRange,
392906c3fb27SDimitry Andric                        IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
393006c3fb27SDimitry Andric                    ReturnValueCondition(WithinRange, SingleValue(4))},
393106c3fb27SDimitry Andric                   ErrnoIrrelevant));
39325ffd83dbSDimitry Andric   }
39330b57cec5SDimitry Andric }
39340b57cec5SDimitry Andric 
39350b57cec5SDimitry Andric void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
39365ffd83dbSDimitry Andric   auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
393706c3fb27SDimitry Andric   Checker->CheckName = mgr.getCurrentCheckerName();
3938349cc55cSDimitry Andric   const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
39395ffd83dbSDimitry Andric   Checker->DisplayLoadedSummaries =
3940349cc55cSDimitry Andric       Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3941349cc55cSDimitry Andric   Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3942349cc55cSDimitry Andric   Checker->ShouldAssumeControlledEnvironment =
3943349cc55cSDimitry Andric       Opts.ShouldAssumeControlledEnvironment;
39440b57cec5SDimitry Andric }
39450b57cec5SDimitry Andric 
3946e8d8bef9SDimitry Andric bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3947e8d8bef9SDimitry Andric     const CheckerManager &mgr) {
39480b57cec5SDimitry Andric   return true;
39490b57cec5SDimitry Andric }
39505ffd83dbSDimitry Andric 
395106c3fb27SDimitry Andric void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
395206c3fb27SDimitry Andric   auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
395306c3fb27SDimitry Andric   Checker->AddTestFunctions = true;
395406c3fb27SDimitry Andric }
39555ffd83dbSDimitry Andric 
395606c3fb27SDimitry Andric bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
395706c3fb27SDimitry Andric     const CheckerManager &mgr) {
395806c3fb27SDimitry Andric   return true;
395906c3fb27SDimitry Andric }
3960