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