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 ⤅ 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