1e5dd7070Spatrick //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick // 9e5dd7070Spatrick // This checker improves modeling of a few simple library functions. 10e5dd7070Spatrick // 11ec727ea7Spatrick // This checker provides a specification format - `Summary' - and 12e5dd7070Spatrick // contains descriptions of some library functions in this format. Each 13e5dd7070Spatrick // specification contains a list of branches for splitting the program state 14e5dd7070Spatrick // upon call, and range constraints on argument and return-value symbols that 15e5dd7070Spatrick // are satisfied on each branch. This spec can be expanded to include more 16e5dd7070Spatrick // items, like external effects of the function. 17e5dd7070Spatrick // 18e5dd7070Spatrick // The main difference between this approach and the body farms technique is 19e5dd7070Spatrick // in more explicit control over how many branches are produced. For example, 20e5dd7070Spatrick // consider standard C function `ispunct(int x)', which returns a non-zero value 21e5dd7070Spatrick // iff `x' is a punctuation character, that is, when `x' is in range 22e5dd7070Spatrick // ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~']. 23ec727ea7Spatrick // `Summary' provides only two branches for this function. However, 24e5dd7070Spatrick // any attempt to describe this range with if-statements in the body farm 25e5dd7070Spatrick // would result in many more branches. Because each branch needs to be analyzed 26e5dd7070Spatrick // independently, this significantly reduces performance. Additionally, 27e5dd7070Spatrick // once we consider a branch on which `x' is in range, say, ['!', '/'], 28e5dd7070Spatrick // we assume that such branch is an important separate path through the program, 29e5dd7070Spatrick // which may lead to false positives because considering this particular path 30e5dd7070Spatrick // was not consciously intended, and therefore it might have been unreachable. 31e5dd7070Spatrick // 32ec727ea7Spatrick // This checker uses eval::Call for modeling pure functions (functions without 33ec727ea7Spatrick // side effets), for which their `Summary' is a precise model. This avoids 34ec727ea7Spatrick // unnecessary invalidation passes. Conflicts with other checkers are unlikely 35ec727ea7Spatrick // because if the function has no other effects, other checkers would probably 36ec727ea7Spatrick // never want to improve upon the modeling done by this checker. 37e5dd7070Spatrick // 38ec727ea7Spatrick // Non-pure functions, for which only partial improvement over the default 39e5dd7070Spatrick // behavior is expected, are modeled via check::PostCall, non-intrusively. 40e5dd7070Spatrick // 41e5dd7070Spatrick // The following standard C functions are currently supported: 42e5dd7070Spatrick // 43*a9ac8606Spatrick // fgetc getline isdigit isupper toascii 44e5dd7070Spatrick // fread isalnum isgraph isxdigit 45e5dd7070Spatrick // fwrite isalpha islower read 46e5dd7070Spatrick // getc isascii isprint write 47*a9ac8606Spatrick // getchar isblank ispunct toupper 48*a9ac8606Spatrick // getdelim iscntrl isspace tolower 49e5dd7070Spatrick // 50e5dd7070Spatrick //===----------------------------------------------------------------------===// 51e5dd7070Spatrick 52e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 53ec727ea7Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 54e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h" 55e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h" 56e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 57e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 58ec727ea7Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" 59*a9ac8606Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" 60*a9ac8606Spatrick #include "llvm/ADT/SmallString.h" 61*a9ac8606Spatrick #include "llvm/ADT/StringExtras.h" 62*a9ac8606Spatrick 63*a9ac8606Spatrick #include <string> 64e5dd7070Spatrick 65e5dd7070Spatrick using namespace clang; 66e5dd7070Spatrick using namespace clang::ento; 67e5dd7070Spatrick 68e5dd7070Spatrick namespace { 69ec727ea7Spatrick class StdLibraryFunctionsChecker 70ec727ea7Spatrick : public Checker<check::PreCall, check::PostCall, eval::Call> { 71ec727ea7Spatrick 72ec727ea7Spatrick class Summary; 73e5dd7070Spatrick 74e5dd7070Spatrick /// Specify how much the analyzer engine should entrust modeling this function 75e5dd7070Spatrick /// to us. If he doesn't, he performs additional invalidations. 76ec727ea7Spatrick enum InvalidationKind { NoEvalCall, EvalCallAsPure }; 77e5dd7070Spatrick 78e5dd7070Spatrick // The universal integral type to use in value range descriptions. 79e5dd7070Spatrick // Unsigned to make sure overflows are well-defined. 80ec727ea7Spatrick typedef uint64_t RangeInt; 81e5dd7070Spatrick 82e5dd7070Spatrick /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is 83e5dd7070Spatrick /// a non-negative integer, which less than 5 and not equal to 2. For 84e5dd7070Spatrick /// `ComparesToArgument', holds information about how exactly to compare to 85e5dd7070Spatrick /// the argument. 86ec727ea7Spatrick typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector; 87e5dd7070Spatrick 88e5dd7070Spatrick /// A reference to an argument or return value by its number. 89e5dd7070Spatrick /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but 90e5dd7070Spatrick /// obviously uint32_t should be enough for all practical purposes. 91ec727ea7Spatrick typedef uint32_t ArgNo; 92ec727ea7Spatrick static const ArgNo Ret; 93e5dd7070Spatrick 94*a9ac8606Spatrick /// Returns the string representation of an argument index. 95*a9ac8606Spatrick /// E.g.: (1) -> '1st arg', (2) - > '2nd arg' 96*a9ac8606Spatrick static SmallString<8> getArgDesc(ArgNo); 97*a9ac8606Spatrick 98ec727ea7Spatrick class ValueConstraint; 99ec727ea7Spatrick 100ec727ea7Spatrick // Pointer to the ValueConstraint. We need a copyable, polymorphic and 101ec727ea7Spatrick // default initialize able type (vector needs that). A raw pointer was good, 102ec727ea7Spatrick // however, we cannot default initialize that. unique_ptr makes the Summary 103ec727ea7Spatrick // class non-copyable, therefore not an option. Releasing the copyability 104ec727ea7Spatrick // requirement would render the initialization of the Summary map infeasible. 105ec727ea7Spatrick using ValueConstraintPtr = std::shared_ptr<ValueConstraint>; 106ec727ea7Spatrick 107ec727ea7Spatrick /// Polymorphic base class that represents a constraint on a given argument 108ec727ea7Spatrick /// (or return value) of a function. Derived classes implement different kind 109ec727ea7Spatrick /// of constraints, e.g range constraints or correlation between two 110ec727ea7Spatrick /// arguments. 111ec727ea7Spatrick class ValueConstraint { 112ec727ea7Spatrick public: 113ec727ea7Spatrick ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {} 114ec727ea7Spatrick virtual ~ValueConstraint() {} 115ec727ea7Spatrick /// Apply the effects of the constraint on the given program state. If null 116ec727ea7Spatrick /// is returned then the constraint is not feasible. 117ec727ea7Spatrick virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 118ec727ea7Spatrick const Summary &Summary, 119ec727ea7Spatrick CheckerContext &C) const = 0; 120ec727ea7Spatrick virtual ValueConstraintPtr negate() const { 121ec727ea7Spatrick llvm_unreachable("Not implemented"); 122ec727ea7Spatrick }; 123ec727ea7Spatrick 124ec727ea7Spatrick // Check whether the constraint is malformed or not. It is malformed if the 125ec727ea7Spatrick // specified argument has a mismatch with the given FunctionDecl (e.g. the 126ec727ea7Spatrick // arg number is out-of-range of the function's argument list). 127ec727ea7Spatrick bool checkValidity(const FunctionDecl *FD) const { 128ec727ea7Spatrick const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams(); 129ec727ea7Spatrick assert(ValidArg && "Arg out of range!"); 130ec727ea7Spatrick if (!ValidArg) 131ec727ea7Spatrick return false; 132ec727ea7Spatrick // Subclasses may further refine the validation. 133ec727ea7Spatrick return checkSpecificValidity(FD); 134ec727ea7Spatrick } 135ec727ea7Spatrick ArgNo getArgNo() const { return ArgN; } 136ec727ea7Spatrick 137*a9ac8606Spatrick // Return those arguments that should be tracked when we report a bug. By 138*a9ac8606Spatrick // default it is the argument that is constrained, however, in some special 139*a9ac8606Spatrick // cases we need to track other arguments as well. E.g. a buffer size might 140*a9ac8606Spatrick // be encoded in another argument. 141*a9ac8606Spatrick virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; } 142*a9ac8606Spatrick 143*a9ac8606Spatrick virtual StringRef getName() const = 0; 144*a9ac8606Spatrick 145*a9ac8606Spatrick // Give a description that explains the constraint to the user. Used when 146*a9ac8606Spatrick // the bug is reported. 147*a9ac8606Spatrick virtual std::string describe(ProgramStateRef State, 148*a9ac8606Spatrick const Summary &Summary) const { 149*a9ac8606Spatrick // There are some descendant classes that are not used as argument 150*a9ac8606Spatrick // constraints, e.g. ComparisonConstraint. In that case we can safely 151*a9ac8606Spatrick // ignore the implementation of this function. 152*a9ac8606Spatrick llvm_unreachable("Not implemented"); 153*a9ac8606Spatrick } 154*a9ac8606Spatrick 155ec727ea7Spatrick protected: 156ec727ea7Spatrick ArgNo ArgN; // Argument to which we apply the constraint. 157ec727ea7Spatrick 158ec727ea7Spatrick /// Do polymorphic sanity check on the constraint. 159ec727ea7Spatrick virtual bool checkSpecificValidity(const FunctionDecl *FD) const { 160ec727ea7Spatrick return true; 161ec727ea7Spatrick } 162ec727ea7Spatrick }; 163ec727ea7Spatrick 164ec727ea7Spatrick /// Given a range, should the argument stay inside or outside this range? 165ec727ea7Spatrick enum RangeKind { OutOfRange, WithinRange }; 166ec727ea7Spatrick 167*a9ac8606Spatrick /// Encapsulates a range on a single symbol. 168ec727ea7Spatrick class RangeConstraint : public ValueConstraint { 169*a9ac8606Spatrick RangeKind Kind; 170*a9ac8606Spatrick // A range is formed as a set of intervals (sub-ranges). 171*a9ac8606Spatrick // E.g. {['A', 'Z'], ['a', 'z']} 172*a9ac8606Spatrick // 173*a9ac8606Spatrick // The default constructed RangeConstraint has an empty range set, applying 174*a9ac8606Spatrick // such constraint does not involve any assumptions, thus the State remains 175*a9ac8606Spatrick // unchanged. This is meaningful, if the range is dependent on a looked up 176*a9ac8606Spatrick // type (e.g. [0, Socklen_tMax]). If the type is not found, then the range 177*a9ac8606Spatrick // is default initialized to be empty. 178*a9ac8606Spatrick IntRangeVector Ranges; 179e5dd7070Spatrick 180e5dd7070Spatrick public: 181*a9ac8606Spatrick StringRef getName() const override { return "Range"; } 182*a9ac8606Spatrick RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges) 183*a9ac8606Spatrick : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {} 184e5dd7070Spatrick 185*a9ac8606Spatrick std::string describe(ProgramStateRef State, 186*a9ac8606Spatrick const Summary &Summary) const override; 187*a9ac8606Spatrick 188*a9ac8606Spatrick const IntRangeVector &getRanges() const { return Ranges; } 189e5dd7070Spatrick 190e5dd7070Spatrick private: 191ec727ea7Spatrick ProgramStateRef applyAsOutOfRange(ProgramStateRef State, 192ec727ea7Spatrick const CallEvent &Call, 193ec727ea7Spatrick const Summary &Summary) const; 194ec727ea7Spatrick ProgramStateRef applyAsWithinRange(ProgramStateRef State, 195ec727ea7Spatrick const CallEvent &Call, 196ec727ea7Spatrick const Summary &Summary) const; 197*a9ac8606Spatrick 198e5dd7070Spatrick public: 199e5dd7070Spatrick ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 200ec727ea7Spatrick const Summary &Summary, 201ec727ea7Spatrick CheckerContext &C) const override { 202e5dd7070Spatrick switch (Kind) { 203e5dd7070Spatrick case OutOfRange: 204e5dd7070Spatrick return applyAsOutOfRange(State, Call, Summary); 205e5dd7070Spatrick case WithinRange: 206e5dd7070Spatrick return applyAsWithinRange(State, Call, Summary); 207e5dd7070Spatrick } 208ec727ea7Spatrick llvm_unreachable("Unknown range kind!"); 209ec727ea7Spatrick } 210ec727ea7Spatrick 211ec727ea7Spatrick ValueConstraintPtr negate() const override { 212ec727ea7Spatrick RangeConstraint Tmp(*this); 213ec727ea7Spatrick switch (Kind) { 214ec727ea7Spatrick case OutOfRange: 215ec727ea7Spatrick Tmp.Kind = WithinRange; 216ec727ea7Spatrick break; 217ec727ea7Spatrick case WithinRange: 218ec727ea7Spatrick Tmp.Kind = OutOfRange; 219ec727ea7Spatrick break; 220ec727ea7Spatrick } 221ec727ea7Spatrick return std::make_shared<RangeConstraint>(Tmp); 222ec727ea7Spatrick } 223ec727ea7Spatrick 224ec727ea7Spatrick bool checkSpecificValidity(const FunctionDecl *FD) const override { 225ec727ea7Spatrick const bool ValidArg = 226ec727ea7Spatrick getArgType(FD, ArgN)->isIntegralType(FD->getASTContext()); 227ec727ea7Spatrick assert(ValidArg && 228ec727ea7Spatrick "This constraint should be applied on an integral type"); 229ec727ea7Spatrick return ValidArg; 230e5dd7070Spatrick } 231e5dd7070Spatrick }; 232e5dd7070Spatrick 233ec727ea7Spatrick class ComparisonConstraint : public ValueConstraint { 234ec727ea7Spatrick BinaryOperator::Opcode Opcode; 235ec727ea7Spatrick ArgNo OtherArgN; 236e5dd7070Spatrick 237e5dd7070Spatrick public: 238*a9ac8606Spatrick virtual StringRef getName() const override { return "Comparison"; }; 239ec727ea7Spatrick ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode, 240ec727ea7Spatrick ArgNo OtherArgN) 241ec727ea7Spatrick : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {} 242ec727ea7Spatrick ArgNo getOtherArgNo() const { return OtherArgN; } 243ec727ea7Spatrick BinaryOperator::Opcode getOpcode() const { return Opcode; } 244ec727ea7Spatrick ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 245ec727ea7Spatrick const Summary &Summary, 246ec727ea7Spatrick CheckerContext &C) const override; 247ec727ea7Spatrick }; 248ec727ea7Spatrick 249ec727ea7Spatrick class NotNullConstraint : public ValueConstraint { 250ec727ea7Spatrick using ValueConstraint::ValueConstraint; 251ec727ea7Spatrick // This variable has a role when we negate the constraint. 252ec727ea7Spatrick bool CannotBeNull = true; 253ec727ea7Spatrick 254ec727ea7Spatrick public: 255*a9ac8606Spatrick std::string describe(ProgramStateRef State, 256*a9ac8606Spatrick const Summary &Summary) const override; 257*a9ac8606Spatrick StringRef getName() const override { return "NonNull"; } 258ec727ea7Spatrick ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 259ec727ea7Spatrick const Summary &Summary, 260ec727ea7Spatrick CheckerContext &C) const override { 261ec727ea7Spatrick SVal V = getArgSVal(Call, getArgNo()); 262ec727ea7Spatrick if (V.isUndef()) 263ec727ea7Spatrick return State; 264ec727ea7Spatrick 265ec727ea7Spatrick DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>(); 266ec727ea7Spatrick if (!L.getAs<Loc>()) 267ec727ea7Spatrick return State; 268ec727ea7Spatrick 269ec727ea7Spatrick return State->assume(L, CannotBeNull); 270ec727ea7Spatrick } 271ec727ea7Spatrick 272ec727ea7Spatrick ValueConstraintPtr negate() const override { 273ec727ea7Spatrick NotNullConstraint Tmp(*this); 274ec727ea7Spatrick Tmp.CannotBeNull = !this->CannotBeNull; 275ec727ea7Spatrick return std::make_shared<NotNullConstraint>(Tmp); 276ec727ea7Spatrick } 277ec727ea7Spatrick 278ec727ea7Spatrick bool checkSpecificValidity(const FunctionDecl *FD) const override { 279ec727ea7Spatrick const bool ValidArg = getArgType(FD, ArgN)->isPointerType(); 280ec727ea7Spatrick assert(ValidArg && 281ec727ea7Spatrick "This constraint should be applied only on a pointer type"); 282ec727ea7Spatrick return ValidArg; 283ec727ea7Spatrick } 284ec727ea7Spatrick }; 285ec727ea7Spatrick 286*a9ac8606Spatrick // Represents a buffer argument with an additional size constraint. The 287*a9ac8606Spatrick // constraint may be a concrete value, or a symbolic value in an argument. 288*a9ac8606Spatrick // Example 1. Concrete value as the minimum buffer size. 289*a9ac8606Spatrick // char *asctime_r(const struct tm *restrict tm, char *restrict buf); 290*a9ac8606Spatrick // // `buf` size must be at least 26 bytes according the POSIX standard. 291*a9ac8606Spatrick // Example 2. Argument as a buffer size. 292ec727ea7Spatrick // ctime_s(char *buffer, rsize_t bufsz, const time_t *time); 293*a9ac8606Spatrick // Example 3. The size is computed as a multiplication of other args. 294ec727ea7Spatrick // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 295ec727ea7Spatrick // // Here, ptr is the buffer, and its minimum size is `size * nmemb`. 296ec727ea7Spatrick class BufferSizeConstraint : public ValueConstraint { 297*a9ac8606Spatrick // The concrete value which is the minimum size for the buffer. 298*a9ac8606Spatrick llvm::Optional<llvm::APSInt> ConcreteSize; 299ec727ea7Spatrick // The argument which holds the size of the buffer. 300*a9ac8606Spatrick llvm::Optional<ArgNo> SizeArgN; 301ec727ea7Spatrick // The argument which is a multiplier to size. This is set in case of 302ec727ea7Spatrick // `fread` like functions where the size is computed as a multiplication of 303ec727ea7Spatrick // two arguments. 304ec727ea7Spatrick llvm::Optional<ArgNo> SizeMultiplierArgN; 305ec727ea7Spatrick // The operator we use in apply. This is negated in negate(). 306ec727ea7Spatrick BinaryOperator::Opcode Op = BO_LE; 307ec727ea7Spatrick 308ec727ea7Spatrick public: 309*a9ac8606Spatrick StringRef getName() const override { return "BufferSize"; } 310*a9ac8606Spatrick BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize) 311*a9ac8606Spatrick : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {} 312ec727ea7Spatrick BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize) 313ec727ea7Spatrick : ValueConstraint(Buffer), SizeArgN(BufSize) {} 314ec727ea7Spatrick BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier) 315ec727ea7Spatrick : ValueConstraint(Buffer), SizeArgN(BufSize), 316ec727ea7Spatrick SizeMultiplierArgN(BufSizeMultiplier) {} 317ec727ea7Spatrick 318*a9ac8606Spatrick std::vector<ArgNo> getArgsToTrack() const override { 319*a9ac8606Spatrick std::vector<ArgNo> Result{ArgN}; 320*a9ac8606Spatrick if (SizeArgN) 321*a9ac8606Spatrick Result.push_back(*SizeArgN); 322*a9ac8606Spatrick if (SizeMultiplierArgN) 323*a9ac8606Spatrick Result.push_back(*SizeMultiplierArgN); 324*a9ac8606Spatrick return Result; 325*a9ac8606Spatrick } 326*a9ac8606Spatrick 327*a9ac8606Spatrick std::string describe(ProgramStateRef State, 328*a9ac8606Spatrick const Summary &Summary) const override; 329*a9ac8606Spatrick 330ec727ea7Spatrick ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 331ec727ea7Spatrick const Summary &Summary, 332ec727ea7Spatrick CheckerContext &C) const override { 333ec727ea7Spatrick SValBuilder &SvalBuilder = C.getSValBuilder(); 334ec727ea7Spatrick // The buffer argument. 335ec727ea7Spatrick SVal BufV = getArgSVal(Call, getArgNo()); 336*a9ac8606Spatrick 337*a9ac8606Spatrick // Get the size constraint. 338*a9ac8606Spatrick const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() { 339*a9ac8606Spatrick if (ConcreteSize) { 340*a9ac8606Spatrick return SVal(SvalBuilder.makeIntVal(*ConcreteSize)); 341*a9ac8606Spatrick } 342*a9ac8606Spatrick assert(SizeArgN && "The constraint must be either a concrete value or " 343*a9ac8606Spatrick "encoded in an argument."); 344ec727ea7Spatrick // The size argument. 345*a9ac8606Spatrick SVal SizeV = getArgSVal(Call, *SizeArgN); 346ec727ea7Spatrick // Multiply with another argument if given. 347ec727ea7Spatrick if (SizeMultiplierArgN) { 348ec727ea7Spatrick SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN); 349ec727ea7Spatrick SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV, 350*a9ac8606Spatrick Summary.getArgType(*SizeArgN)); 351ec727ea7Spatrick } 352*a9ac8606Spatrick return SizeV; 353*a9ac8606Spatrick }(); 354*a9ac8606Spatrick 355ec727ea7Spatrick // The dynamic size of the buffer argument, got from the analyzer engine. 356*a9ac8606Spatrick SVal BufDynSize = getDynamicExtentWithOffset(State, BufV); 357ec727ea7Spatrick 358ec727ea7Spatrick SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize, 359ec727ea7Spatrick SvalBuilder.getContext().BoolTy); 360ec727ea7Spatrick if (auto F = Feasible.getAs<DefinedOrUnknownSVal>()) 361ec727ea7Spatrick return State->assume(*F, true); 362ec727ea7Spatrick 363ec727ea7Spatrick // We can get here only if the size argument or the dynamic size is 364ec727ea7Spatrick // undefined. But the dynamic size should never be undefined, only 365ec727ea7Spatrick // unknown. So, here, the size of the argument is undefined, i.e. we 366ec727ea7Spatrick // cannot apply the constraint. Actually, other checkers like 367ec727ea7Spatrick // CallAndMessage should catch this situation earlier, because we call a 368ec727ea7Spatrick // function with an uninitialized argument. 369ec727ea7Spatrick llvm_unreachable("Size argument or the dynamic size is Undefined"); 370ec727ea7Spatrick } 371ec727ea7Spatrick 372ec727ea7Spatrick ValueConstraintPtr negate() const override { 373ec727ea7Spatrick BufferSizeConstraint Tmp(*this); 374ec727ea7Spatrick Tmp.Op = BinaryOperator::negateComparisonOp(Op); 375ec727ea7Spatrick return std::make_shared<BufferSizeConstraint>(Tmp); 376ec727ea7Spatrick } 377*a9ac8606Spatrick 378*a9ac8606Spatrick bool checkSpecificValidity(const FunctionDecl *FD) const override { 379*a9ac8606Spatrick const bool ValidArg = getArgType(FD, ArgN)->isPointerType(); 380*a9ac8606Spatrick assert(ValidArg && 381*a9ac8606Spatrick "This constraint should be applied only on a pointer type"); 382*a9ac8606Spatrick return ValidArg; 383*a9ac8606Spatrick } 384ec727ea7Spatrick }; 385ec727ea7Spatrick 386ec727ea7Spatrick /// The complete list of constraints that defines a single branch. 387ec727ea7Spatrick typedef std::vector<ValueConstraintPtr> ConstraintSet; 388ec727ea7Spatrick 389*a9ac8606Spatrick using ArgTypes = std::vector<Optional<QualType>>; 390*a9ac8606Spatrick using RetType = Optional<QualType>; 391ec727ea7Spatrick 392ec727ea7Spatrick // A placeholder type, we use it whenever we do not care about the concrete 393ec727ea7Spatrick // type in a Signature. 394ec727ea7Spatrick const QualType Irrelevant{}; 395ec727ea7Spatrick bool static isIrrelevant(QualType T) { return T.isNull(); } 396ec727ea7Spatrick 397ec727ea7Spatrick // The signature of a function we want to describe with a summary. This is a 398ec727ea7Spatrick // concessive signature, meaning there may be irrelevant types in the 399ec727ea7Spatrick // signature which we do not check against a function with concrete types. 400*a9ac8606Spatrick // All types in the spec need to be canonical. 401*a9ac8606Spatrick class Signature { 402*a9ac8606Spatrick using ArgQualTypes = std::vector<QualType>; 403*a9ac8606Spatrick ArgQualTypes ArgTys; 404*a9ac8606Spatrick QualType RetTy; 405*a9ac8606Spatrick // True if any component type is not found by lookup. 406*a9ac8606Spatrick bool Invalid = false; 407*a9ac8606Spatrick 408*a9ac8606Spatrick public: 409*a9ac8606Spatrick // Construct a signature from optional types. If any of the optional types 410*a9ac8606Spatrick // are not set then the signature will be invalid. 411*a9ac8606Spatrick Signature(ArgTypes ArgTys, RetType RetTy) { 412*a9ac8606Spatrick for (Optional<QualType> Arg : ArgTys) { 413*a9ac8606Spatrick if (!Arg) { 414*a9ac8606Spatrick Invalid = true; 415*a9ac8606Spatrick return; 416*a9ac8606Spatrick } else { 417*a9ac8606Spatrick assertArgTypeSuitableForSignature(*Arg); 418*a9ac8606Spatrick this->ArgTys.push_back(*Arg); 419ec727ea7Spatrick } 420ec727ea7Spatrick } 421*a9ac8606Spatrick if (!RetTy) { 422*a9ac8606Spatrick Invalid = true; 423*a9ac8606Spatrick return; 424*a9ac8606Spatrick } else { 425*a9ac8606Spatrick assertRetTypeSuitableForSignature(*RetTy); 426*a9ac8606Spatrick this->RetTy = *RetTy; 427*a9ac8606Spatrick } 428*a9ac8606Spatrick } 429*a9ac8606Spatrick 430*a9ac8606Spatrick bool isInvalid() const { return Invalid; } 431ec727ea7Spatrick bool matches(const FunctionDecl *FD) const; 432ec727ea7Spatrick 433ec727ea7Spatrick private: 434ec727ea7Spatrick static void assertArgTypeSuitableForSignature(QualType T) { 435ec727ea7Spatrick assert((T.isNull() || !T->isVoidType()) && 436ec727ea7Spatrick "We should have no void types in the spec"); 437ec727ea7Spatrick assert((T.isNull() || T.isCanonical()) && 438ec727ea7Spatrick "We should only have canonical types in the spec"); 439ec727ea7Spatrick } 440ec727ea7Spatrick static void assertRetTypeSuitableForSignature(QualType T) { 441ec727ea7Spatrick assert((T.isNull() || T.isCanonical()) && 442ec727ea7Spatrick "We should only have canonical types in the spec"); 443ec727ea7Spatrick } 444ec727ea7Spatrick }; 445ec727ea7Spatrick 446ec727ea7Spatrick static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) { 447ec727ea7Spatrick assert(FD && "Function must be set"); 448ec727ea7Spatrick QualType T = (ArgN == Ret) 449ec727ea7Spatrick ? FD->getReturnType().getCanonicalType() 450ec727ea7Spatrick : FD->getParamDecl(ArgN)->getType().getCanonicalType(); 451e5dd7070Spatrick return T; 452e5dd7070Spatrick } 453e5dd7070Spatrick 454ec727ea7Spatrick using Cases = std::vector<ConstraintSet>; 455e5dd7070Spatrick 456ec727ea7Spatrick /// A summary includes information about 457ec727ea7Spatrick /// * function prototype (signature) 458ec727ea7Spatrick /// * approach to invalidation, 459ec727ea7Spatrick /// * a list of branches - a list of list of ranges - 460ec727ea7Spatrick /// A branch represents a path in the exploded graph of a function (which 461ec727ea7Spatrick /// is a tree). So, a branch is a series of assumptions. In other words, 462ec727ea7Spatrick /// branches represent split states and additional assumptions on top of 463ec727ea7Spatrick /// the splitting assumption. 464ec727ea7Spatrick /// For example, consider the branches in `isalpha(x)` 465ec727ea7Spatrick /// Branch 1) 466ec727ea7Spatrick /// x is in range ['A', 'Z'] or in ['a', 'z'] 467ec727ea7Spatrick /// then the return value is not 0. (I.e. out-of-range [0, 0]) 468ec727ea7Spatrick /// Branch 2) 469ec727ea7Spatrick /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z'] 470ec727ea7Spatrick /// then the return value is 0. 471ec727ea7Spatrick /// * a list of argument constraints, that must be true on every branch. 472ec727ea7Spatrick /// If these constraints are not satisfied that means a fatal error 473ec727ea7Spatrick /// usually resulting in undefined behaviour. 474ec727ea7Spatrick /// 475ec727ea7Spatrick /// Application of a summary: 476ec727ea7Spatrick /// The signature and argument constraints together contain information 477ec727ea7Spatrick /// about which functions are handled by the summary. The signature can use 478ec727ea7Spatrick /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in 479ec727ea7Spatrick /// a signature means that type is not compared to the type of the parameter 480ec727ea7Spatrick /// in the found FunctionDecl. Argument constraints may specify additional 481ec727ea7Spatrick /// rules for the given parameter's type, those rules are checked once the 482ec727ea7Spatrick /// signature is matched. 483ec727ea7Spatrick class Summary { 484ec727ea7Spatrick const InvalidationKind InvalidationKd; 485ec727ea7Spatrick Cases CaseConstraints; 486ec727ea7Spatrick ConstraintSet ArgConstraints; 487ec727ea7Spatrick 488ec727ea7Spatrick // The function to which the summary applies. This is set after lookup and 489ec727ea7Spatrick // match to the signature. 490ec727ea7Spatrick const FunctionDecl *FD = nullptr; 491ec727ea7Spatrick 492ec727ea7Spatrick public: 493*a9ac8606Spatrick Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {} 494ec727ea7Spatrick 495ec727ea7Spatrick Summary &Case(ConstraintSet &&CS) { 496ec727ea7Spatrick CaseConstraints.push_back(std::move(CS)); 497ec727ea7Spatrick return *this; 498ec727ea7Spatrick } 499*a9ac8606Spatrick Summary &Case(const ConstraintSet &CS) { 500*a9ac8606Spatrick CaseConstraints.push_back(CS); 501*a9ac8606Spatrick return *this; 502*a9ac8606Spatrick } 503ec727ea7Spatrick Summary &ArgConstraint(ValueConstraintPtr VC) { 504*a9ac8606Spatrick assert(VC->getArgNo() != Ret && 505*a9ac8606Spatrick "Arg constraint should not refer to the return value"); 506ec727ea7Spatrick ArgConstraints.push_back(VC); 507ec727ea7Spatrick return *this; 508ec727ea7Spatrick } 509ec727ea7Spatrick 510ec727ea7Spatrick InvalidationKind getInvalidationKd() const { return InvalidationKd; } 511ec727ea7Spatrick const Cases &getCaseConstraints() const { return CaseConstraints; } 512ec727ea7Spatrick const ConstraintSet &getArgConstraints() const { return ArgConstraints; } 513ec727ea7Spatrick 514ec727ea7Spatrick QualType getArgType(ArgNo ArgN) const { 515ec727ea7Spatrick return StdLibraryFunctionsChecker::getArgType(FD, ArgN); 516ec727ea7Spatrick } 517ec727ea7Spatrick 518ec727ea7Spatrick // Returns true if the summary should be applied to the given function. 519ec727ea7Spatrick // And if yes then store the function declaration. 520*a9ac8606Spatrick bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) { 521ec727ea7Spatrick bool Result = Sign.matches(FD) && validateByConstraints(FD); 522ec727ea7Spatrick if (Result) { 523ec727ea7Spatrick assert(!this->FD && "FD must not be set more than once"); 524ec727ea7Spatrick this->FD = FD; 525ec727ea7Spatrick } 526ec727ea7Spatrick return Result; 527ec727ea7Spatrick } 528ec727ea7Spatrick 529ec727ea7Spatrick private: 530ec727ea7Spatrick // Once we know the exact type of the function then do sanity check on all 531ec727ea7Spatrick // the given constraints. 532ec727ea7Spatrick bool validateByConstraints(const FunctionDecl *FD) const { 533ec727ea7Spatrick for (const ConstraintSet &Case : CaseConstraints) 534ec727ea7Spatrick for (const ValueConstraintPtr &Constraint : Case) 535ec727ea7Spatrick if (!Constraint->checkValidity(FD)) 536ec727ea7Spatrick return false; 537ec727ea7Spatrick for (const ValueConstraintPtr &Constraint : ArgConstraints) 538ec727ea7Spatrick if (!Constraint->checkValidity(FD)) 539ec727ea7Spatrick return false; 540ec727ea7Spatrick return true; 541ec727ea7Spatrick } 542ec727ea7Spatrick }; 543e5dd7070Spatrick 544e5dd7070Spatrick // The map of all functions supported by the checker. It is initialized 545e5dd7070Spatrick // lazily, and it doesn't change after initialization. 546ec727ea7Spatrick using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>; 547ec727ea7Spatrick mutable FunctionSummaryMapType FunctionSummaryMap; 548e5dd7070Spatrick 549ec727ea7Spatrick mutable std::unique_ptr<BugType> BT_InvalidArg; 550*a9ac8606Spatrick mutable bool SummariesInitialized = false; 551ec727ea7Spatrick 552ec727ea7Spatrick static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) { 553ec727ea7Spatrick return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN); 554e5dd7070Spatrick } 555e5dd7070Spatrick 556e5dd7070Spatrick public: 557ec727ea7Spatrick void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 558e5dd7070Spatrick void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 559e5dd7070Spatrick bool evalCall(const CallEvent &Call, CheckerContext &C) const; 560e5dd7070Spatrick 561ec727ea7Spatrick enum CheckKind { 562ec727ea7Spatrick CK_StdCLibraryFunctionArgsChecker, 563ec727ea7Spatrick CK_StdCLibraryFunctionsTesterChecker, 564ec727ea7Spatrick CK_NumCheckKinds 565ec727ea7Spatrick }; 566ec727ea7Spatrick DefaultBool ChecksEnabled[CK_NumCheckKinds]; 567ec727ea7Spatrick CheckerNameRef CheckNames[CK_NumCheckKinds]; 568ec727ea7Spatrick 569ec727ea7Spatrick bool DisplayLoadedSummaries = false; 570ec727ea7Spatrick bool ModelPOSIX = false; 571ec727ea7Spatrick 572e5dd7070Spatrick private: 573ec727ea7Spatrick Optional<Summary> findFunctionSummary(const FunctionDecl *FD, 574ec727ea7Spatrick CheckerContext &C) const; 575ec727ea7Spatrick Optional<Summary> findFunctionSummary(const CallEvent &Call, 576e5dd7070Spatrick CheckerContext &C) const; 577e5dd7070Spatrick 578ec727ea7Spatrick void initFunctionSummaries(CheckerContext &C) const; 579ec727ea7Spatrick 580ec727ea7Spatrick void reportBug(const CallEvent &Call, ExplodedNode *N, 581*a9ac8606Spatrick const ValueConstraint *VC, const Summary &Summary, 582ec727ea7Spatrick CheckerContext &C) const { 583ec727ea7Spatrick if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker]) 584ec727ea7Spatrick return; 585*a9ac8606Spatrick std::string Msg = 586*a9ac8606Spatrick (Twine("Function argument constraint is not satisfied, constraint: ") + 587*a9ac8606Spatrick VC->getName().data()) 588*a9ac8606Spatrick .str(); 589ec727ea7Spatrick if (!BT_InvalidArg) 590ec727ea7Spatrick BT_InvalidArg = std::make_unique<BugType>( 591ec727ea7Spatrick CheckNames[CK_StdCLibraryFunctionArgsChecker], 592ec727ea7Spatrick "Unsatisfied argument constraints", categories::LogicError); 593ec727ea7Spatrick auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N); 594*a9ac8606Spatrick 595*a9ac8606Spatrick for (ArgNo ArgN : VC->getArgsToTrack()) 596*a9ac8606Spatrick bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R); 597*a9ac8606Spatrick 598*a9ac8606Spatrick // Highlight the range of the argument that was violated. 599*a9ac8606Spatrick R->addRange(Call.getArgSourceRange(VC->getArgNo())); 600*a9ac8606Spatrick 601*a9ac8606Spatrick // Describe the argument constraint in a note. 602*a9ac8606Spatrick R->addNote(VC->describe(C.getState(), Summary), R->getLocation(), 603*a9ac8606Spatrick Call.getArgSourceRange(VC->getArgNo())); 604*a9ac8606Spatrick 605ec727ea7Spatrick C.emitReport(std::move(R)); 606ec727ea7Spatrick } 607e5dd7070Spatrick }; 608ec727ea7Spatrick 609ec727ea7Spatrick const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret = 610ec727ea7Spatrick std::numeric_limits<ArgNo>::max(); 611ec727ea7Spatrick 612e5dd7070Spatrick } // end of anonymous namespace 613e5dd7070Spatrick 614*a9ac8606Spatrick static BasicValueFactory &getBVF(ProgramStateRef State) { 615*a9ac8606Spatrick ProgramStateManager &Mgr = State->getStateManager(); 616*a9ac8606Spatrick SValBuilder &SVB = Mgr.getSValBuilder(); 617*a9ac8606Spatrick return SVB.getBasicValueFactory(); 618*a9ac8606Spatrick } 619*a9ac8606Spatrick 620*a9ac8606Spatrick std::string StdLibraryFunctionsChecker::NotNullConstraint::describe( 621*a9ac8606Spatrick ProgramStateRef State, const Summary &Summary) const { 622*a9ac8606Spatrick SmallString<48> Result; 623*a9ac8606Spatrick Result += "The "; 624*a9ac8606Spatrick Result += getArgDesc(ArgN); 625*a9ac8606Spatrick Result += " should not be NULL"; 626*a9ac8606Spatrick return Result.c_str(); 627*a9ac8606Spatrick } 628*a9ac8606Spatrick 629*a9ac8606Spatrick std::string StdLibraryFunctionsChecker::RangeConstraint::describe( 630*a9ac8606Spatrick ProgramStateRef State, const Summary &Summary) const { 631*a9ac8606Spatrick 632*a9ac8606Spatrick BasicValueFactory &BVF = getBVF(State); 633*a9ac8606Spatrick 634*a9ac8606Spatrick QualType T = Summary.getArgType(getArgNo()); 635*a9ac8606Spatrick SmallString<48> Result; 636*a9ac8606Spatrick Result += "The "; 637*a9ac8606Spatrick Result += getArgDesc(ArgN); 638*a9ac8606Spatrick Result += " should be "; 639*a9ac8606Spatrick 640*a9ac8606Spatrick // Range kind as a string. 641*a9ac8606Spatrick Kind == OutOfRange ? Result += "out of" : Result += "within"; 642*a9ac8606Spatrick 643*a9ac8606Spatrick // Get the range values as a string. 644*a9ac8606Spatrick Result += " the range "; 645*a9ac8606Spatrick if (Ranges.size() > 1) 646*a9ac8606Spatrick Result += "["; 647*a9ac8606Spatrick unsigned I = Ranges.size(); 648*a9ac8606Spatrick for (const std::pair<RangeInt, RangeInt> &R : Ranges) { 649*a9ac8606Spatrick Result += "["; 650*a9ac8606Spatrick const llvm::APSInt &Min = BVF.getValue(R.first, T); 651*a9ac8606Spatrick const llvm::APSInt &Max = BVF.getValue(R.second, T); 652*a9ac8606Spatrick Min.toString(Result); 653*a9ac8606Spatrick Result += ", "; 654*a9ac8606Spatrick Max.toString(Result); 655*a9ac8606Spatrick Result += "]"; 656*a9ac8606Spatrick if (--I > 0) 657*a9ac8606Spatrick Result += ", "; 658*a9ac8606Spatrick } 659*a9ac8606Spatrick if (Ranges.size() > 1) 660*a9ac8606Spatrick Result += "]"; 661*a9ac8606Spatrick 662*a9ac8606Spatrick return Result.c_str(); 663*a9ac8606Spatrick } 664*a9ac8606Spatrick 665*a9ac8606Spatrick SmallString<8> 666*a9ac8606Spatrick StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) { 667*a9ac8606Spatrick SmallString<8> Result; 668*a9ac8606Spatrick Result += std::to_string(ArgN + 1); 669*a9ac8606Spatrick Result += llvm::getOrdinalSuffix(ArgN + 1); 670*a9ac8606Spatrick Result += " arg"; 671*a9ac8606Spatrick return Result; 672*a9ac8606Spatrick } 673*a9ac8606Spatrick 674*a9ac8606Spatrick std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe( 675*a9ac8606Spatrick ProgramStateRef State, const Summary &Summary) const { 676*a9ac8606Spatrick SmallString<96> Result; 677*a9ac8606Spatrick Result += "The size of the "; 678*a9ac8606Spatrick Result += getArgDesc(ArgN); 679*a9ac8606Spatrick Result += " should be equal to or less than the value of "; 680*a9ac8606Spatrick if (ConcreteSize) { 681*a9ac8606Spatrick ConcreteSize->toString(Result); 682*a9ac8606Spatrick } else if (SizeArgN) { 683*a9ac8606Spatrick Result += "the "; 684*a9ac8606Spatrick Result += getArgDesc(*SizeArgN); 685*a9ac8606Spatrick if (SizeMultiplierArgN) { 686*a9ac8606Spatrick Result += " times the "; 687*a9ac8606Spatrick Result += getArgDesc(*SizeMultiplierArgN); 688*a9ac8606Spatrick } 689*a9ac8606Spatrick } 690*a9ac8606Spatrick return Result.c_str(); 691*a9ac8606Spatrick } 692*a9ac8606Spatrick 693ec727ea7Spatrick ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange( 694e5dd7070Spatrick ProgramStateRef State, const CallEvent &Call, 695ec727ea7Spatrick const Summary &Summary) const { 696*a9ac8606Spatrick if (Ranges.empty()) 697*a9ac8606Spatrick return State; 698e5dd7070Spatrick 699e5dd7070Spatrick ProgramStateManager &Mgr = State->getStateManager(); 700e5dd7070Spatrick SValBuilder &SVB = Mgr.getSValBuilder(); 701e5dd7070Spatrick BasicValueFactory &BVF = SVB.getBasicValueFactory(); 702e5dd7070Spatrick ConstraintManager &CM = Mgr.getConstraintManager(); 703ec727ea7Spatrick QualType T = Summary.getArgType(getArgNo()); 704e5dd7070Spatrick SVal V = getArgSVal(Call, getArgNo()); 705e5dd7070Spatrick 706e5dd7070Spatrick if (auto N = V.getAs<NonLoc>()) { 707ec727ea7Spatrick const IntRangeVector &R = getRanges(); 708e5dd7070Spatrick size_t E = R.size(); 709e5dd7070Spatrick for (size_t I = 0; I != E; ++I) { 710e5dd7070Spatrick const llvm::APSInt &Min = BVF.getValue(R[I].first, T); 711e5dd7070Spatrick const llvm::APSInt &Max = BVF.getValue(R[I].second, T); 712e5dd7070Spatrick assert(Min <= Max); 713e5dd7070Spatrick State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 714e5dd7070Spatrick if (!State) 715e5dd7070Spatrick break; 716e5dd7070Spatrick } 717e5dd7070Spatrick } 718e5dd7070Spatrick 719e5dd7070Spatrick return State; 720e5dd7070Spatrick } 721e5dd7070Spatrick 722ec727ea7Spatrick ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange( 723e5dd7070Spatrick ProgramStateRef State, const CallEvent &Call, 724ec727ea7Spatrick const Summary &Summary) const { 725*a9ac8606Spatrick if (Ranges.empty()) 726*a9ac8606Spatrick return State; 727e5dd7070Spatrick 728e5dd7070Spatrick ProgramStateManager &Mgr = State->getStateManager(); 729e5dd7070Spatrick SValBuilder &SVB = Mgr.getSValBuilder(); 730e5dd7070Spatrick BasicValueFactory &BVF = SVB.getBasicValueFactory(); 731e5dd7070Spatrick ConstraintManager &CM = Mgr.getConstraintManager(); 732ec727ea7Spatrick QualType T = Summary.getArgType(getArgNo()); 733e5dd7070Spatrick SVal V = getArgSVal(Call, getArgNo()); 734e5dd7070Spatrick 735e5dd7070Spatrick // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R". 736e5dd7070Spatrick // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary, 737e5dd7070Spatrick // and then cut away all holes in R one by one. 738ec727ea7Spatrick // 739ec727ea7Spatrick // E.g. consider a range list R as [A, B] and [C, D] 740ec727ea7Spatrick // -------+--------+------------------+------------+-----------> 741ec727ea7Spatrick // A B C D 742ec727ea7Spatrick // Then we assume that the value is not in [-inf, A - 1], 743ec727ea7Spatrick // then not in [D + 1, +inf], then not in [B + 1, C - 1] 744e5dd7070Spatrick if (auto N = V.getAs<NonLoc>()) { 745ec727ea7Spatrick const IntRangeVector &R = getRanges(); 746e5dd7070Spatrick size_t E = R.size(); 747e5dd7070Spatrick 748e5dd7070Spatrick const llvm::APSInt &MinusInf = BVF.getMinValue(T); 749e5dd7070Spatrick const llvm::APSInt &PlusInf = BVF.getMaxValue(T); 750e5dd7070Spatrick 751e5dd7070Spatrick const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T); 752e5dd7070Spatrick if (Left != PlusInf) { 753e5dd7070Spatrick assert(MinusInf <= Left); 754e5dd7070Spatrick State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false); 755e5dd7070Spatrick if (!State) 756e5dd7070Spatrick return nullptr; 757e5dd7070Spatrick } 758e5dd7070Spatrick 759e5dd7070Spatrick const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T); 760e5dd7070Spatrick if (Right != MinusInf) { 761e5dd7070Spatrick assert(Right <= PlusInf); 762e5dd7070Spatrick State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false); 763e5dd7070Spatrick if (!State) 764e5dd7070Spatrick return nullptr; 765e5dd7070Spatrick } 766e5dd7070Spatrick 767e5dd7070Spatrick for (size_t I = 1; I != E; ++I) { 768e5dd7070Spatrick const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T); 769e5dd7070Spatrick const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T); 770ec727ea7Spatrick if (Min <= Max) { 771e5dd7070Spatrick State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 772e5dd7070Spatrick if (!State) 773e5dd7070Spatrick return nullptr; 774e5dd7070Spatrick } 775e5dd7070Spatrick } 776ec727ea7Spatrick } 777e5dd7070Spatrick 778e5dd7070Spatrick return State; 779e5dd7070Spatrick } 780e5dd7070Spatrick 781ec727ea7Spatrick ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply( 782ec727ea7Spatrick ProgramStateRef State, const CallEvent &Call, const Summary &Summary, 783ec727ea7Spatrick CheckerContext &C) const { 784e5dd7070Spatrick 785e5dd7070Spatrick ProgramStateManager &Mgr = State->getStateManager(); 786e5dd7070Spatrick SValBuilder &SVB = Mgr.getSValBuilder(); 787e5dd7070Spatrick QualType CondT = SVB.getConditionType(); 788ec727ea7Spatrick QualType T = Summary.getArgType(getArgNo()); 789e5dd7070Spatrick SVal V = getArgSVal(Call, getArgNo()); 790e5dd7070Spatrick 791e5dd7070Spatrick BinaryOperator::Opcode Op = getOpcode(); 792ec727ea7Spatrick ArgNo OtherArg = getOtherArgNo(); 793e5dd7070Spatrick SVal OtherV = getArgSVal(Call, OtherArg); 794ec727ea7Spatrick QualType OtherT = Summary.getArgType(OtherArg); 795e5dd7070Spatrick // Note: we avoid integral promotion for comparison. 796e5dd7070Spatrick OtherV = SVB.evalCast(OtherV, T, OtherT); 797e5dd7070Spatrick if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT) 798e5dd7070Spatrick .getAs<DefinedOrUnknownSVal>()) 799e5dd7070Spatrick State = State->assume(*CompV, true); 800e5dd7070Spatrick return State; 801e5dd7070Spatrick } 802e5dd7070Spatrick 803ec727ea7Spatrick void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call, 804e5dd7070Spatrick CheckerContext &C) const { 805ec727ea7Spatrick Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 806e5dd7070Spatrick if (!FoundSummary) 807e5dd7070Spatrick return; 808e5dd7070Spatrick 809ec727ea7Spatrick const Summary &Summary = *FoundSummary; 810e5dd7070Spatrick ProgramStateRef State = C.getState(); 811e5dd7070Spatrick 812e5dd7070Spatrick ProgramStateRef NewState = State; 813ec727ea7Spatrick for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) { 814ec727ea7Spatrick ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C); 815ec727ea7Spatrick ProgramStateRef FailureSt = 816ec727ea7Spatrick Constraint->negate()->apply(NewState, Call, Summary, C); 817ec727ea7Spatrick // The argument constraint is not satisfied. 818ec727ea7Spatrick if (FailureSt && !SuccessSt) { 819ec727ea7Spatrick if (ExplodedNode *N = C.generateErrorNode(NewState)) 820*a9ac8606Spatrick reportBug(Call, N, Constraint.get(), Summary, C); 821ec727ea7Spatrick break; 822ec727ea7Spatrick } else { 823ec727ea7Spatrick // We will apply the constraint even if we cannot reason about the 824ec727ea7Spatrick // argument. This means both SuccessSt and FailureSt can be true. If we 825ec727ea7Spatrick // weren't applying the constraint that would mean that symbolic 826ec727ea7Spatrick // execution continues on a code whose behaviour is undefined. 827ec727ea7Spatrick assert(SuccessSt); 828ec727ea7Spatrick NewState = SuccessSt; 829ec727ea7Spatrick } 830ec727ea7Spatrick } 831ec727ea7Spatrick if (NewState && NewState != State) 832ec727ea7Spatrick C.addTransition(NewState); 833ec727ea7Spatrick } 834ec727ea7Spatrick 835ec727ea7Spatrick void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, 836ec727ea7Spatrick CheckerContext &C) const { 837ec727ea7Spatrick Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 838ec727ea7Spatrick if (!FoundSummary) 839ec727ea7Spatrick return; 840ec727ea7Spatrick 841ec727ea7Spatrick // Now apply the constraints. 842ec727ea7Spatrick const Summary &Summary = *FoundSummary; 843ec727ea7Spatrick ProgramStateRef State = C.getState(); 844ec727ea7Spatrick 845ec727ea7Spatrick // Apply case/branch specifications. 846ec727ea7Spatrick for (const ConstraintSet &Case : Summary.getCaseConstraints()) { 847ec727ea7Spatrick ProgramStateRef NewState = State; 848ec727ea7Spatrick for (const ValueConstraintPtr &Constraint : Case) { 849ec727ea7Spatrick NewState = Constraint->apply(NewState, Call, Summary, C); 850e5dd7070Spatrick if (!NewState) 851e5dd7070Spatrick break; 852e5dd7070Spatrick } 853e5dd7070Spatrick 854e5dd7070Spatrick if (NewState && NewState != State) 855e5dd7070Spatrick C.addTransition(NewState); 856e5dd7070Spatrick } 857e5dd7070Spatrick } 858e5dd7070Spatrick 859e5dd7070Spatrick bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, 860e5dd7070Spatrick CheckerContext &C) const { 861ec727ea7Spatrick Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 862e5dd7070Spatrick if (!FoundSummary) 863e5dd7070Spatrick return false; 864e5dd7070Spatrick 865ec727ea7Spatrick const Summary &Summary = *FoundSummary; 866ec727ea7Spatrick switch (Summary.getInvalidationKd()) { 867e5dd7070Spatrick case EvalCallAsPure: { 868e5dd7070Spatrick ProgramStateRef State = C.getState(); 869e5dd7070Spatrick const LocationContext *LC = C.getLocationContext(); 870*a9ac8606Spatrick const auto *CE = cast<CallExpr>(Call.getOriginExpr()); 871e5dd7070Spatrick SVal V = C.getSValBuilder().conjureSymbolVal( 872e5dd7070Spatrick CE, LC, CE->getType().getCanonicalType(), C.blockCount()); 873e5dd7070Spatrick State = State->BindExpr(CE, LC, V); 874e5dd7070Spatrick C.addTransition(State); 875e5dd7070Spatrick return true; 876e5dd7070Spatrick } 877e5dd7070Spatrick case NoEvalCall: 878e5dd7070Spatrick // Summary tells us to avoid performing eval::Call. The function is possibly 879e5dd7070Spatrick // evaluated by another checker, or evaluated conservatively. 880e5dd7070Spatrick return false; 881e5dd7070Spatrick } 882e5dd7070Spatrick llvm_unreachable("Unknown invalidation kind!"); 883e5dd7070Spatrick } 884e5dd7070Spatrick 885ec727ea7Spatrick bool StdLibraryFunctionsChecker::Signature::matches( 886ec727ea7Spatrick const FunctionDecl *FD) const { 887*a9ac8606Spatrick assert(!isInvalid()); 888*a9ac8606Spatrick // Check the number of arguments. 889ec727ea7Spatrick if (FD->param_size() != ArgTys.size()) 890e5dd7070Spatrick return false; 891e5dd7070Spatrick 892*a9ac8606Spatrick // The "restrict" keyword is illegal in C++, however, many libc 893*a9ac8606Spatrick // implementations use the "__restrict" compiler intrinsic in functions 894*a9ac8606Spatrick // prototypes. The "__restrict" keyword qualifies a type as a restricted type 895*a9ac8606Spatrick // even in C++. 896*a9ac8606Spatrick // In case of any non-C99 languages, we don't want to match based on the 897*a9ac8606Spatrick // restrict qualifier because we cannot know if the given libc implementation 898*a9ac8606Spatrick // qualifies the paramter type or not. 899*a9ac8606Spatrick auto RemoveRestrict = [&FD](QualType T) { 900*a9ac8606Spatrick if (!FD->getASTContext().getLangOpts().C99) 901*a9ac8606Spatrick T.removeLocalRestrict(); 902*a9ac8606Spatrick return T; 903*a9ac8606Spatrick }; 904e5dd7070Spatrick 905*a9ac8606Spatrick // Check the return type. 906*a9ac8606Spatrick if (!isIrrelevant(RetTy)) { 907*a9ac8606Spatrick QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType()); 908*a9ac8606Spatrick if (RetTy != FDRetTy) 909*a9ac8606Spatrick return false; 910*a9ac8606Spatrick } 911*a9ac8606Spatrick 912*a9ac8606Spatrick // Check the argument types. 913ec727ea7Spatrick for (size_t I = 0, E = ArgTys.size(); I != E; ++I) { 914ec727ea7Spatrick QualType ArgTy = ArgTys[I]; 915ec727ea7Spatrick if (isIrrelevant(ArgTy)) 916e5dd7070Spatrick continue; 917*a9ac8606Spatrick QualType FDArgTy = 918*a9ac8606Spatrick RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType()); 919*a9ac8606Spatrick if (ArgTy != FDArgTy) 920e5dd7070Spatrick return false; 921e5dd7070Spatrick } 922e5dd7070Spatrick 923e5dd7070Spatrick return true; 924e5dd7070Spatrick } 925e5dd7070Spatrick 926ec727ea7Spatrick Optional<StdLibraryFunctionsChecker::Summary> 927e5dd7070Spatrick StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, 928e5dd7070Spatrick CheckerContext &C) const { 929e5dd7070Spatrick if (!FD) 930e5dd7070Spatrick return None; 931e5dd7070Spatrick 932ec727ea7Spatrick initFunctionSummaries(C); 933e5dd7070Spatrick 934ec727ea7Spatrick auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl()); 935e5dd7070Spatrick if (FSMI == FunctionSummaryMap.end()) 936e5dd7070Spatrick return None; 937ec727ea7Spatrick return FSMI->second; 938ec727ea7Spatrick } 939e5dd7070Spatrick 940ec727ea7Spatrick Optional<StdLibraryFunctionsChecker::Summary> 941ec727ea7Spatrick StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call, 942ec727ea7Spatrick CheckerContext &C) const { 943ec727ea7Spatrick const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 944ec727ea7Spatrick if (!FD) 945ec727ea7Spatrick return None; 946ec727ea7Spatrick return findFunctionSummary(FD, C); 947ec727ea7Spatrick } 948e5dd7070Spatrick 949*a9ac8606Spatrick void StdLibraryFunctionsChecker::initFunctionSummaries( 950*a9ac8606Spatrick CheckerContext &C) const { 951*a9ac8606Spatrick if (SummariesInitialized) 952*a9ac8606Spatrick return; 953*a9ac8606Spatrick 954*a9ac8606Spatrick SValBuilder &SVB = C.getSValBuilder(); 955*a9ac8606Spatrick BasicValueFactory &BVF = SVB.getBasicValueFactory(); 956*a9ac8606Spatrick const ASTContext &ACtx = BVF.getContext(); 957*a9ac8606Spatrick 958*a9ac8606Spatrick // Helper class to lookup a type by its name. 959*a9ac8606Spatrick class LookupType { 960*a9ac8606Spatrick const ASTContext &ACtx; 961*a9ac8606Spatrick 962*a9ac8606Spatrick public: 963*a9ac8606Spatrick LookupType(const ASTContext &ACtx) : ACtx(ACtx) {} 964*a9ac8606Spatrick 965*a9ac8606Spatrick // Find the type. If not found then the optional is not set. 966*a9ac8606Spatrick llvm::Optional<QualType> operator()(StringRef Name) { 967ec727ea7Spatrick IdentifierInfo &II = ACtx.Idents.get(Name); 968ec727ea7Spatrick auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 969*a9ac8606Spatrick if (LookupRes.empty()) 970ec727ea7Spatrick return None; 971ec727ea7Spatrick 972ec727ea7Spatrick // Prioritze typedef declarations. 973ec727ea7Spatrick // This is needed in case of C struct typedefs. E.g.: 974ec727ea7Spatrick // typedef struct FILE FILE; 975*a9ac8606Spatrick // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' 976*a9ac8606Spatrick // and we have a TypedefDecl with the name 'FILE'. 977ec727ea7Spatrick for (Decl *D : LookupRes) 978ec727ea7Spatrick if (auto *TD = dyn_cast<TypedefNameDecl>(D)) 979ec727ea7Spatrick return ACtx.getTypeDeclType(TD).getCanonicalType(); 980ec727ea7Spatrick 981ec727ea7Spatrick // Find the first TypeDecl. 982ec727ea7Spatrick // There maybe cases when a function has the same name as a struct. 983ec727ea7Spatrick // E.g. in POSIX: `struct stat` and the function `stat()`: 984ec727ea7Spatrick // int stat(const char *restrict path, struct stat *restrict buf); 985ec727ea7Spatrick for (Decl *D : LookupRes) 986ec727ea7Spatrick if (auto *TD = dyn_cast<TypeDecl>(D)) 987ec727ea7Spatrick return ACtx.getTypeDeclType(TD).getCanonicalType(); 988e5dd7070Spatrick return None; 989e5dd7070Spatrick } 990*a9ac8606Spatrick } lookupTy(ACtx); 991e5dd7070Spatrick 992*a9ac8606Spatrick // Below are auxiliary classes to handle optional types that we get as a 993*a9ac8606Spatrick // result of the lookup. 994*a9ac8606Spatrick class GetRestrictTy { 995*a9ac8606Spatrick const ASTContext &ACtx; 996e5dd7070Spatrick 997*a9ac8606Spatrick public: 998*a9ac8606Spatrick GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {} 999*a9ac8606Spatrick QualType operator()(QualType Ty) { 1000*a9ac8606Spatrick return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty; 1001*a9ac8606Spatrick } 1002*a9ac8606Spatrick Optional<QualType> operator()(Optional<QualType> Ty) { 1003*a9ac8606Spatrick if (Ty) 1004*a9ac8606Spatrick return operator()(*Ty); 1005*a9ac8606Spatrick return None; 1006*a9ac8606Spatrick } 1007*a9ac8606Spatrick } getRestrictTy(ACtx); 1008*a9ac8606Spatrick class GetPointerTy { 1009*a9ac8606Spatrick const ASTContext &ACtx; 1010*a9ac8606Spatrick 1011*a9ac8606Spatrick public: 1012*a9ac8606Spatrick GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {} 1013*a9ac8606Spatrick QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); } 1014*a9ac8606Spatrick Optional<QualType> operator()(Optional<QualType> Ty) { 1015*a9ac8606Spatrick if (Ty) 1016*a9ac8606Spatrick return operator()(*Ty); 1017*a9ac8606Spatrick return None; 1018*a9ac8606Spatrick } 1019*a9ac8606Spatrick } getPointerTy(ACtx); 1020*a9ac8606Spatrick class { 1021*a9ac8606Spatrick public: 1022*a9ac8606Spatrick Optional<QualType> operator()(Optional<QualType> Ty) { 1023*a9ac8606Spatrick return Ty ? Optional<QualType>(Ty->withConst()) : None; 1024*a9ac8606Spatrick } 1025*a9ac8606Spatrick QualType operator()(QualType Ty) { return Ty.withConst(); } 1026*a9ac8606Spatrick } getConstTy; 1027*a9ac8606Spatrick class GetMaxValue { 1028*a9ac8606Spatrick BasicValueFactory &BVF; 1029*a9ac8606Spatrick 1030*a9ac8606Spatrick public: 1031*a9ac8606Spatrick GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {} 1032*a9ac8606Spatrick Optional<RangeInt> operator()(QualType Ty) { 1033*a9ac8606Spatrick return BVF.getMaxValue(Ty).getLimitedValue(); 1034*a9ac8606Spatrick } 1035*a9ac8606Spatrick Optional<RangeInt> operator()(Optional<QualType> Ty) { 1036*a9ac8606Spatrick if (Ty) { 1037*a9ac8606Spatrick return operator()(*Ty); 1038*a9ac8606Spatrick } 1039*a9ac8606Spatrick return None; 1040*a9ac8606Spatrick } 1041*a9ac8606Spatrick } getMaxValue(BVF); 1042e5dd7070Spatrick 1043e5dd7070Spatrick // These types are useful for writing specifications quickly, 1044e5dd7070Spatrick // New specifications should probably introduce more types. 1045e5dd7070Spatrick // Some types are hard to obtain from the AST, eg. "ssize_t". 1046e5dd7070Spatrick // In such cases it should be possible to provide multiple variants 1047e5dd7070Spatrick // of function summary for common cases (eg. ssize_t could be int or long 1048e5dd7070Spatrick // or long long, so three summary variants would be enough). 1049e5dd7070Spatrick // Of course, function variants are also useful for C++ overloads. 1050ec727ea7Spatrick const QualType VoidTy = ACtx.VoidTy; 1051*a9ac8606Spatrick const QualType CharTy = ACtx.CharTy; 1052*a9ac8606Spatrick const QualType WCharTy = ACtx.WCharTy; 1053ec727ea7Spatrick const QualType IntTy = ACtx.IntTy; 1054ec727ea7Spatrick const QualType UnsignedIntTy = ACtx.UnsignedIntTy; 1055ec727ea7Spatrick const QualType LongTy = ACtx.LongTy; 1056ec727ea7Spatrick const QualType SizeTy = ACtx.getSizeType(); 1057e5dd7070Spatrick 1058*a9ac8606Spatrick const QualType VoidPtrTy = getPointerTy(VoidTy); // void * 1059*a9ac8606Spatrick const QualType IntPtrTy = getPointerTy(IntTy); // int * 1060ec727ea7Spatrick const QualType UnsignedIntPtrTy = 1061*a9ac8606Spatrick getPointerTy(UnsignedIntTy); // unsigned int * 1062*a9ac8606Spatrick const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy); 1063ec727ea7Spatrick const QualType ConstVoidPtrTy = 1064*a9ac8606Spatrick getPointerTy(getConstTy(VoidTy)); // const void * 1065*a9ac8606Spatrick const QualType CharPtrTy = getPointerTy(CharTy); // char * 1066*a9ac8606Spatrick const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy); 1067ec727ea7Spatrick const QualType ConstCharPtrTy = 1068*a9ac8606Spatrick getPointerTy(getConstTy(CharTy)); // const char * 1069*a9ac8606Spatrick const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy); 1070*a9ac8606Spatrick const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t * 1071ec727ea7Spatrick const QualType ConstWchar_tPtrTy = 1072*a9ac8606Spatrick getPointerTy(getConstTy(WCharTy)); // const wchar_t * 1073*a9ac8606Spatrick const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy); 1074*a9ac8606Spatrick const QualType SizePtrTy = getPointerTy(SizeTy); 1075*a9ac8606Spatrick const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy); 1076ec727ea7Spatrick 1077ec727ea7Spatrick const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 1078ec727ea7Spatrick const RangeInt UnsignedIntMax = 1079ec727ea7Spatrick BVF.getMaxValue(UnsignedIntTy).getLimitedValue(); 1080ec727ea7Spatrick const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 1081ec727ea7Spatrick const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue(); 1082ec727ea7Spatrick 1083ec727ea7Spatrick // Set UCharRangeMax to min of int or uchar maximum value. 1084ec727ea7Spatrick // The C standard states that the arguments of functions like isalpha must 1085ec727ea7Spatrick // be representable as an unsigned char. Their type is 'int', so the max 1086ec727ea7Spatrick // value of the argument should be min(UCharMax, IntMax). This just happen 1087ec727ea7Spatrick // to be true for commonly used and well tested instruction set 1088ec727ea7Spatrick // architectures, but not for others. 1089ec727ea7Spatrick const RangeInt UCharRangeMax = 1090ec727ea7Spatrick std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax); 1091ec727ea7Spatrick 1092ec727ea7Spatrick // The platform dependent value of EOF. 1093ec727ea7Spatrick // Try our best to parse this from the Preprocessor, otherwise fallback to -1. 1094ec727ea7Spatrick const auto EOFv = [&C]() -> RangeInt { 1095ec727ea7Spatrick if (const llvm::Optional<int> OptInt = 1096ec727ea7Spatrick tryExpandAsInteger("EOF", C.getPreprocessor())) 1097ec727ea7Spatrick return *OptInt; 1098ec727ea7Spatrick return -1; 1099ec727ea7Spatrick }(); 1100ec727ea7Spatrick 1101ec727ea7Spatrick // Auxiliary class to aid adding summaries to the summary map. 1102ec727ea7Spatrick struct AddToFunctionSummaryMap { 1103ec727ea7Spatrick const ASTContext &ACtx; 1104ec727ea7Spatrick FunctionSummaryMapType ⤅ 1105ec727ea7Spatrick bool DisplayLoadedSummaries; 1106ec727ea7Spatrick AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM, 1107ec727ea7Spatrick bool DisplayLoadedSummaries) 1108ec727ea7Spatrick : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) { 1109ec727ea7Spatrick } 1110ec727ea7Spatrick 1111ec727ea7Spatrick // Add a summary to a FunctionDecl found by lookup. The lookup is performed 1112ec727ea7Spatrick // by the given Name, and in the global scope. The summary will be attached 1113ec727ea7Spatrick // to the found FunctionDecl only if the signatures match. 1114*a9ac8606Spatrick // 1115*a9ac8606Spatrick // Returns true if the summary has been added, false otherwise. 1116*a9ac8606Spatrick bool operator()(StringRef Name, Signature Sign, Summary Sum) { 1117*a9ac8606Spatrick if (Sign.isInvalid()) 1118*a9ac8606Spatrick return false; 1119ec727ea7Spatrick IdentifierInfo &II = ACtx.Idents.get(Name); 1120ec727ea7Spatrick auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 1121*a9ac8606Spatrick if (LookupRes.empty()) 1122*a9ac8606Spatrick return false; 1123ec727ea7Spatrick for (Decl *D : LookupRes) { 1124ec727ea7Spatrick if (auto *FD = dyn_cast<FunctionDecl>(D)) { 1125*a9ac8606Spatrick if (Sum.matchesAndSet(Sign, FD)) { 1126*a9ac8606Spatrick auto Res = Map.insert({FD->getCanonicalDecl(), Sum}); 1127ec727ea7Spatrick assert(Res.second && "Function already has a summary set!"); 1128ec727ea7Spatrick (void)Res; 1129ec727ea7Spatrick if (DisplayLoadedSummaries) { 1130ec727ea7Spatrick llvm::errs() << "Loaded summary for: "; 1131ec727ea7Spatrick FD->print(llvm::errs()); 1132ec727ea7Spatrick llvm::errs() << "\n"; 1133ec727ea7Spatrick } 1134*a9ac8606Spatrick return true; 1135ec727ea7Spatrick } 1136ec727ea7Spatrick } 1137ec727ea7Spatrick } 1138*a9ac8606Spatrick return false; 1139ec727ea7Spatrick } 1140*a9ac8606Spatrick // Add the same summary for different names with the Signature explicitly 1141*a9ac8606Spatrick // given. 1142*a9ac8606Spatrick void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) { 1143*a9ac8606Spatrick for (StringRef Name : Names) 1144*a9ac8606Spatrick operator()(Name, Sign, Sum); 1145ec727ea7Spatrick } 1146ec727ea7Spatrick } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries); 1147e5dd7070Spatrick 1148ec727ea7Spatrick // Below are helpers functions to create the summaries. 1149ec727ea7Spatrick auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, 1150ec727ea7Spatrick IntRangeVector Ranges) { 1151ec727ea7Spatrick return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges); 1152ec727ea7Spatrick }; 1153ec727ea7Spatrick auto BufferSize = [](auto... Args) { 1154ec727ea7Spatrick return std::make_shared<BufferSizeConstraint>(Args...); 1155ec727ea7Spatrick }; 1156ec727ea7Spatrick struct { 1157ec727ea7Spatrick auto operator()(RangeKind Kind, IntRangeVector Ranges) { 1158ec727ea7Spatrick return std::make_shared<RangeConstraint>(Ret, Kind, Ranges); 1159ec727ea7Spatrick } 1160ec727ea7Spatrick auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) { 1161ec727ea7Spatrick return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN); 1162ec727ea7Spatrick } 1163ec727ea7Spatrick } ReturnValueCondition; 1164*a9ac8606Spatrick struct { 1165*a9ac8606Spatrick auto operator()(RangeInt b, RangeInt e) { 1166ec727ea7Spatrick return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}}; 1167*a9ac8606Spatrick } 1168*a9ac8606Spatrick auto operator()(RangeInt b, Optional<RangeInt> e) { 1169*a9ac8606Spatrick if (e) 1170*a9ac8606Spatrick return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}}; 1171*a9ac8606Spatrick return IntRangeVector{}; 1172*a9ac8606Spatrick } 1173*a9ac8606Spatrick auto operator()(std::pair<RangeInt, RangeInt> i0, 1174*a9ac8606Spatrick std::pair<RangeInt, Optional<RangeInt>> i1) { 1175*a9ac8606Spatrick if (i1.second) 1176*a9ac8606Spatrick return IntRangeVector{i0, {i1.first, *(i1.second)}}; 1177*a9ac8606Spatrick return IntRangeVector{i0}; 1178*a9ac8606Spatrick } 1179*a9ac8606Spatrick } Range; 1180ec727ea7Spatrick auto SingleValue = [](RangeInt v) { 1181ec727ea7Spatrick return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}}; 1182ec727ea7Spatrick }; 1183ec727ea7Spatrick auto LessThanOrEq = BO_LE; 1184ec727ea7Spatrick auto NotNull = [&](ArgNo ArgN) { 1185ec727ea7Spatrick return std::make_shared<NotNullConstraint>(ArgN); 1186ec727ea7Spatrick }; 1187e5dd7070Spatrick 1188*a9ac8606Spatrick Optional<QualType> FileTy = lookupTy("FILE"); 1189*a9ac8606Spatrick Optional<QualType> FilePtrTy = getPointerTy(FileTy); 1190*a9ac8606Spatrick Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy); 1191ec727ea7Spatrick 1192*a9ac8606Spatrick // We are finally ready to define specifications for all supported functions. 1193*a9ac8606Spatrick // 1194*a9ac8606Spatrick // Argument ranges should always cover all variants. If return value 1195*a9ac8606Spatrick // is completely unknown, omit it from the respective range set. 1196*a9ac8606Spatrick // 1197*a9ac8606Spatrick // Every item in the list of range sets represents a particular 1198*a9ac8606Spatrick // execution path the analyzer would need to explore once 1199*a9ac8606Spatrick // the call is modeled - a new program state is constructed 1200*a9ac8606Spatrick // for every range set, and each range line in the range set 1201*a9ac8606Spatrick // corresponds to a specific constraint within this state. 1202ec727ea7Spatrick 1203e5dd7070Spatrick // The isascii() family of functions. 1204ec727ea7Spatrick // The behavior is undefined if the value of the argument is not 1205ec727ea7Spatrick // representable as unsigned char or is not equal to EOF. See e.g. C99 1206ec727ea7Spatrick // 7.4.1.2 The isalpha function (p: 181-182). 1207ec727ea7Spatrick addToFunctionSummaryMap( 1208*a9ac8606Spatrick "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1209*a9ac8606Spatrick Summary(EvalCallAsPure) 1210ec727ea7Spatrick // Boils down to isupper() or islower() or isdigit(). 1211ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, 1212ec727ea7Spatrick {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}), 1213ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1214ec727ea7Spatrick // The locale-specific range. 1215e5dd7070Spatrick // No post-condition. We are completely unaware of 1216e5dd7070Spatrick // locale-specific return values. 1217ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1218ec727ea7Spatrick .Case( 1219ec727ea7Spatrick {ArgumentCondition( 1220ec727ea7Spatrick 0U, OutOfRange, 1221ec727ea7Spatrick {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1222ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))}) 1223ec727ea7Spatrick .ArgConstraint(ArgumentCondition( 1224ec727ea7Spatrick 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1225ec727ea7Spatrick addToFunctionSummaryMap( 1226*a9ac8606Spatrick "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1227*a9ac8606Spatrick Summary(EvalCallAsPure) 1228ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}), 1229ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1230ec727ea7Spatrick // The locale-specific range. 1231ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1232ec727ea7Spatrick .Case({ArgumentCondition( 1233ec727ea7Spatrick 0U, OutOfRange, 1234ec727ea7Spatrick {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1235ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1236ec727ea7Spatrick addToFunctionSummaryMap( 1237*a9ac8606Spatrick "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1238*a9ac8606Spatrick Summary(EvalCallAsPure) 1239ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1240ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1241ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)), 1242ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1243ec727ea7Spatrick addToFunctionSummaryMap( 1244*a9ac8606Spatrick "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1245*a9ac8606Spatrick Summary(EvalCallAsPure) 1246ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}), 1247ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1248ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}), 1249ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1250ec727ea7Spatrick addToFunctionSummaryMap( 1251*a9ac8606Spatrick "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1252*a9ac8606Spatrick Summary(EvalCallAsPure) 1253ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}), 1254ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1255ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}), 1256ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1257ec727ea7Spatrick addToFunctionSummaryMap( 1258*a9ac8606Spatrick "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1259*a9ac8606Spatrick Summary(EvalCallAsPure) 1260ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')), 1261ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1262ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')), 1263ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1264ec727ea7Spatrick addToFunctionSummaryMap( 1265*a9ac8606Spatrick "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1266*a9ac8606Spatrick Summary(EvalCallAsPure) 1267ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)), 1268ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1269ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)), 1270ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1271ec727ea7Spatrick addToFunctionSummaryMap( 1272*a9ac8606Spatrick "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1273*a9ac8606Spatrick Summary(EvalCallAsPure) 1274ec727ea7Spatrick // Is certainly lowercase. 1275ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')), 1276ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1277ec727ea7Spatrick // Is ascii but not lowercase. 1278ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1279ec727ea7Spatrick ArgumentCondition(0U, OutOfRange, Range('a', 'z')), 1280ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))}) 1281ec727ea7Spatrick // The locale-specific range. 1282ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1283ec727ea7Spatrick // Is not an unsigned char. 1284ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)), 1285ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1286ec727ea7Spatrick addToFunctionSummaryMap( 1287*a9ac8606Spatrick "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1288*a9ac8606Spatrick Summary(EvalCallAsPure) 1289ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)), 1290ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1291ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)), 1292ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1293ec727ea7Spatrick addToFunctionSummaryMap( 1294*a9ac8606Spatrick "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1295*a9ac8606Spatrick Summary(EvalCallAsPure) 1296ec727ea7Spatrick .Case({ArgumentCondition( 1297ec727ea7Spatrick 0U, WithinRange, 1298ec727ea7Spatrick {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1299ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1300ec727ea7Spatrick .Case({ArgumentCondition( 1301ec727ea7Spatrick 0U, OutOfRange, 1302ec727ea7Spatrick {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1303ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1304ec727ea7Spatrick addToFunctionSummaryMap( 1305*a9ac8606Spatrick "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1306*a9ac8606Spatrick Summary(EvalCallAsPure) 1307ec727ea7Spatrick // Space, '\f', '\n', '\r', '\t', '\v'. 1308ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}), 1309ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1310ec727ea7Spatrick // The locale-specific range. 1311ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1312ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, 1313ec727ea7Spatrick {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}), 1314ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1315ec727ea7Spatrick addToFunctionSummaryMap( 1316*a9ac8606Spatrick "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1317*a9ac8606Spatrick Summary(EvalCallAsPure) 1318ec727ea7Spatrick // Is certainly uppercase. 1319ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')), 1320ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1321ec727ea7Spatrick // The locale-specific range. 1322ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1323ec727ea7Spatrick // Other. 1324ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, 1325ec727ea7Spatrick {{'A', 'Z'}, {128, UCharRangeMax}}), 1326ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1327ec727ea7Spatrick addToFunctionSummaryMap( 1328*a9ac8606Spatrick "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1329*a9ac8606Spatrick Summary(EvalCallAsPure) 1330ec727ea7Spatrick .Case({ArgumentCondition(0U, WithinRange, 1331ec727ea7Spatrick {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1332ec727ea7Spatrick ReturnValueCondition(OutOfRange, SingleValue(0))}) 1333ec727ea7Spatrick .Case({ArgumentCondition(0U, OutOfRange, 1334ec727ea7Spatrick {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1335ec727ea7Spatrick ReturnValueCondition(WithinRange, SingleValue(0))})); 1336*a9ac8606Spatrick addToFunctionSummaryMap( 1337*a9ac8606Spatrick "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1338*a9ac8606Spatrick Summary(EvalCallAsPure) 1339*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1340*a9ac8606Spatrick 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1341*a9ac8606Spatrick addToFunctionSummaryMap( 1342*a9ac8606Spatrick "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1343*a9ac8606Spatrick Summary(EvalCallAsPure) 1344*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1345*a9ac8606Spatrick 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1346*a9ac8606Spatrick addToFunctionSummaryMap( 1347*a9ac8606Spatrick "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1348*a9ac8606Spatrick Summary(EvalCallAsPure) 1349*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1350*a9ac8606Spatrick 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1351e5dd7070Spatrick 1352e5dd7070Spatrick // The getc() family of functions that returns either a char or an EOF. 1353ec727ea7Spatrick addToFunctionSummaryMap( 1354*a9ac8606Spatrick {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1355*a9ac8606Spatrick Summary(NoEvalCall) 1356*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, 1357*a9ac8606Spatrick {{EOFv, EOFv}, {0, UCharRangeMax}})})); 1358*a9ac8606Spatrick addToFunctionSummaryMap( 1359*a9ac8606Spatrick "getchar", Signature(ArgTypes{}, RetType{IntTy}), 1360*a9ac8606Spatrick Summary(NoEvalCall) 1361*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, 1362*a9ac8606Spatrick {{EOFv, EOFv}, {0, UCharRangeMax}})})); 1363e5dd7070Spatrick 1364e5dd7070Spatrick // read()-like functions that never return more than buffer size. 1365*a9ac8606Spatrick auto FreadSummary = 1366*a9ac8606Spatrick Summary(NoEvalCall) 1367*a9ac8606Spatrick .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1368*a9ac8606Spatrick ReturnValueCondition(WithinRange, Range(0, SizeMax))}) 1369*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1370*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(3))) 1371*a9ac8606Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 1372*a9ac8606Spatrick /*BufSizeMultiplier=*/ArgNo(2))); 1373ec727ea7Spatrick 1374*a9ac8606Spatrick // size_t fread(void *restrict ptr, size_t size, size_t nitems, 1375*a9ac8606Spatrick // FILE *restrict stream); 1376*a9ac8606Spatrick addToFunctionSummaryMap( 1377*a9ac8606Spatrick "fread", 1378*a9ac8606Spatrick Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy}, 1379*a9ac8606Spatrick RetType{SizeTy}), 1380*a9ac8606Spatrick FreadSummary); 1381*a9ac8606Spatrick // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, 1382*a9ac8606Spatrick // FILE *restrict stream); 1383*a9ac8606Spatrick addToFunctionSummaryMap("fwrite", 1384*a9ac8606Spatrick Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, 1385*a9ac8606Spatrick SizeTy, FilePtrRestrictTy}, 1386*a9ac8606Spatrick RetType{SizeTy}), 1387*a9ac8606Spatrick FreadSummary); 1388*a9ac8606Spatrick 1389*a9ac8606Spatrick Optional<QualType> Ssize_tTy = lookupTy("ssize_t"); 1390*a9ac8606Spatrick Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy); 1391*a9ac8606Spatrick 1392*a9ac8606Spatrick auto ReadSummary = 1393*a9ac8606Spatrick Summary(NoEvalCall) 1394*a9ac8606Spatrick .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1395*a9ac8606Spatrick ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}); 1396*a9ac8606Spatrick 1397ec727ea7Spatrick // FIXME these are actually defined by POSIX and not by the C standard, we 1398ec727ea7Spatrick // should handle them together with the rest of the POSIX functions. 1399*a9ac8606Spatrick // ssize_t read(int fildes, void *buf, size_t nbyte); 1400*a9ac8606Spatrick addToFunctionSummaryMap( 1401*a9ac8606Spatrick "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}), 1402*a9ac8606Spatrick ReadSummary); 1403*a9ac8606Spatrick // ssize_t write(int fildes, const void *buf, size_t nbyte); 1404*a9ac8606Spatrick addToFunctionSummaryMap( 1405*a9ac8606Spatrick "write", 1406*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}), 1407*a9ac8606Spatrick ReadSummary); 1408*a9ac8606Spatrick 1409*a9ac8606Spatrick auto GetLineSummary = 1410*a9ac8606Spatrick Summary(NoEvalCall) 1411*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, 1412*a9ac8606Spatrick Range({-1, -1}, {1, Ssize_tMax}))}); 1413*a9ac8606Spatrick 1414*a9ac8606Spatrick QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy)); 1415e5dd7070Spatrick 1416e5dd7070Spatrick // getline()-like functions either fail or read at least the delimiter. 1417ec727ea7Spatrick // FIXME these are actually defined by POSIX and not by the C standard, we 1418ec727ea7Spatrick // should handle them together with the rest of the POSIX functions. 1419*a9ac8606Spatrick // ssize_t getline(char **restrict lineptr, size_t *restrict n, 1420*a9ac8606Spatrick // FILE *restrict stream); 1421*a9ac8606Spatrick addToFunctionSummaryMap( 1422*a9ac8606Spatrick "getline", 1423*a9ac8606Spatrick Signature( 1424*a9ac8606Spatrick ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy}, 1425*a9ac8606Spatrick RetType{Ssize_tTy}), 1426*a9ac8606Spatrick GetLineSummary); 1427*a9ac8606Spatrick // ssize_t getdelim(char **restrict lineptr, size_t *restrict n, 1428*a9ac8606Spatrick // int delimiter, FILE *restrict stream); 1429*a9ac8606Spatrick addToFunctionSummaryMap( 1430*a9ac8606Spatrick "getdelim", 1431*a9ac8606Spatrick Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy, 1432*a9ac8606Spatrick FilePtrRestrictTy}, 1433*a9ac8606Spatrick RetType{Ssize_tTy}), 1434*a9ac8606Spatrick GetLineSummary); 1435ec727ea7Spatrick 1436ec727ea7Spatrick if (ModelPOSIX) { 1437ec727ea7Spatrick 1438ec727ea7Spatrick // long a64l(const char *str64); 1439ec727ea7Spatrick addToFunctionSummaryMap( 1440*a9ac8606Spatrick "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}), 1441*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1442ec727ea7Spatrick 1443ec727ea7Spatrick // char *l64a(long value); 1444*a9ac8606Spatrick addToFunctionSummaryMap("l64a", 1445*a9ac8606Spatrick Signature(ArgTypes{LongTy}, RetType{CharPtrTy}), 1446*a9ac8606Spatrick Summary(NoEvalCall) 1447*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1448*a9ac8606Spatrick 0, WithinRange, Range(0, LongMax)))); 1449*a9ac8606Spatrick 1450*a9ac8606Spatrick const auto ReturnsZeroOrMinusOne = 1451*a9ac8606Spatrick ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))}; 1452*a9ac8606Spatrick const auto ReturnsFileDescriptor = 1453*a9ac8606Spatrick ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))}; 1454ec727ea7Spatrick 1455ec727ea7Spatrick // int access(const char *pathname, int amode); 1456*a9ac8606Spatrick addToFunctionSummaryMap( 1457*a9ac8606Spatrick "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}), 1458*a9ac8606Spatrick Summary(NoEvalCall) 1459*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1460ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1461ec727ea7Spatrick 1462ec727ea7Spatrick // int faccessat(int dirfd, const char *pathname, int mode, int flags); 1463ec727ea7Spatrick addToFunctionSummaryMap( 1464*a9ac8606Spatrick "faccessat", 1465*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy}, 1466*a9ac8606Spatrick RetType{IntTy}), 1467*a9ac8606Spatrick Summary(NoEvalCall) 1468*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1469ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1470ec727ea7Spatrick 1471ec727ea7Spatrick // int dup(int fildes); 1472*a9ac8606Spatrick addToFunctionSummaryMap("dup", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1473*a9ac8606Spatrick Summary(NoEvalCall) 1474*a9ac8606Spatrick .Case(ReturnsFileDescriptor) 1475*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1476*a9ac8606Spatrick 0, WithinRange, Range(0, IntMax)))); 1477ec727ea7Spatrick 1478ec727ea7Spatrick // int dup2(int fildes1, int filedes2); 1479ec727ea7Spatrick addToFunctionSummaryMap( 1480*a9ac8606Spatrick "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 1481*a9ac8606Spatrick Summary(NoEvalCall) 1482*a9ac8606Spatrick .Case(ReturnsFileDescriptor) 1483ec727ea7Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1484ec727ea7Spatrick .ArgConstraint( 1485ec727ea7Spatrick ArgumentCondition(1, WithinRange, Range(0, IntMax)))); 1486ec727ea7Spatrick 1487ec727ea7Spatrick // int fdatasync(int fildes); 1488*a9ac8606Spatrick addToFunctionSummaryMap("fdatasync", 1489*a9ac8606Spatrick Signature(ArgTypes{IntTy}, RetType{IntTy}), 1490*a9ac8606Spatrick Summary(NoEvalCall) 1491*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1492*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1493*a9ac8606Spatrick 0, WithinRange, Range(0, IntMax)))); 1494ec727ea7Spatrick 1495ec727ea7Spatrick // int fnmatch(const char *pattern, const char *string, int flags); 1496ec727ea7Spatrick addToFunctionSummaryMap( 1497*a9ac8606Spatrick "fnmatch", 1498*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy}, 1499*a9ac8606Spatrick RetType{IntTy}), 1500*a9ac8606Spatrick Summary(EvalCallAsPure) 1501ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1502ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1503ec727ea7Spatrick 1504ec727ea7Spatrick // int fsync(int fildes); 1505*a9ac8606Spatrick addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1506*a9ac8606Spatrick Summary(NoEvalCall) 1507*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1508*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1509*a9ac8606Spatrick 0, WithinRange, Range(0, IntMax)))); 1510ec727ea7Spatrick 1511*a9ac8606Spatrick Optional<QualType> Off_tTy = lookupTy("off_t"); 1512ec727ea7Spatrick 1513ec727ea7Spatrick // int truncate(const char *path, off_t length); 1514*a9ac8606Spatrick addToFunctionSummaryMap( 1515*a9ac8606Spatrick "truncate", 1516*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}), 1517*a9ac8606Spatrick Summary(NoEvalCall) 1518*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1519ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1520ec727ea7Spatrick 1521ec727ea7Spatrick // int symlink(const char *oldpath, const char *newpath); 1522*a9ac8606Spatrick addToFunctionSummaryMap( 1523*a9ac8606Spatrick "symlink", 1524*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}), 1525*a9ac8606Spatrick Summary(NoEvalCall) 1526*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1527ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1528ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1529ec727ea7Spatrick 1530ec727ea7Spatrick // int symlinkat(const char *oldpath, int newdirfd, const char *newpath); 1531ec727ea7Spatrick addToFunctionSummaryMap( 1532ec727ea7Spatrick "symlinkat", 1533*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, 1534*a9ac8606Spatrick RetType{IntTy}), 1535*a9ac8606Spatrick Summary(NoEvalCall) 1536*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1537ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1538ec727ea7Spatrick .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax))) 1539ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(2)))); 1540ec727ea7Spatrick 1541ec727ea7Spatrick // int lockf(int fd, int cmd, off_t len); 1542ec727ea7Spatrick addToFunctionSummaryMap( 1543*a9ac8606Spatrick "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}), 1544*a9ac8606Spatrick Summary(NoEvalCall) 1545*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1546ec727ea7Spatrick .ArgConstraint( 1547ec727ea7Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1548ec727ea7Spatrick 1549*a9ac8606Spatrick Optional<QualType> Mode_tTy = lookupTy("mode_t"); 1550ec727ea7Spatrick 1551ec727ea7Spatrick // int creat(const char *pathname, mode_t mode); 1552*a9ac8606Spatrick addToFunctionSummaryMap( 1553*a9ac8606Spatrick "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1554*a9ac8606Spatrick Summary(NoEvalCall) 1555*a9ac8606Spatrick .Case(ReturnsFileDescriptor) 1556ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1557ec727ea7Spatrick 1558ec727ea7Spatrick // unsigned int sleep(unsigned int seconds); 1559ec727ea7Spatrick addToFunctionSummaryMap( 1560*a9ac8606Spatrick "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}), 1561*a9ac8606Spatrick Summary(NoEvalCall) 1562ec727ea7Spatrick .ArgConstraint( 1563ec727ea7Spatrick ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1564ec727ea7Spatrick 1565*a9ac8606Spatrick Optional<QualType> DirTy = lookupTy("DIR"); 1566*a9ac8606Spatrick Optional<QualType> DirPtrTy = getPointerTy(DirTy); 1567ec727ea7Spatrick 1568ec727ea7Spatrick // int dirfd(DIR *dirp); 1569*a9ac8606Spatrick addToFunctionSummaryMap("dirfd", 1570*a9ac8606Spatrick Signature(ArgTypes{DirPtrTy}, RetType{IntTy}), 1571*a9ac8606Spatrick Summary(NoEvalCall) 1572*a9ac8606Spatrick .Case(ReturnsFileDescriptor) 1573ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1574ec727ea7Spatrick 1575ec727ea7Spatrick // unsigned int alarm(unsigned int seconds); 1576ec727ea7Spatrick addToFunctionSummaryMap( 1577*a9ac8606Spatrick "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}), 1578*a9ac8606Spatrick Summary(NoEvalCall) 1579ec727ea7Spatrick .ArgConstraint( 1580ec727ea7Spatrick ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1581ec727ea7Spatrick 1582ec727ea7Spatrick // int closedir(DIR *dir); 1583*a9ac8606Spatrick addToFunctionSummaryMap("closedir", 1584*a9ac8606Spatrick Signature(ArgTypes{DirPtrTy}, RetType{IntTy}), 1585*a9ac8606Spatrick Summary(NoEvalCall) 1586*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1587ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1588ec727ea7Spatrick 1589ec727ea7Spatrick // char *strdup(const char *s); 1590*a9ac8606Spatrick addToFunctionSummaryMap( 1591*a9ac8606Spatrick "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}), 1592*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1593ec727ea7Spatrick 1594ec727ea7Spatrick // char *strndup(const char *s, size_t n); 1595ec727ea7Spatrick addToFunctionSummaryMap( 1596*a9ac8606Spatrick "strndup", 1597*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}), 1598*a9ac8606Spatrick Summary(NoEvalCall) 1599ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1600*a9ac8606Spatrick .ArgConstraint( 1601*a9ac8606Spatrick ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 1602ec727ea7Spatrick 1603ec727ea7Spatrick // wchar_t *wcsdup(const wchar_t *s); 1604*a9ac8606Spatrick addToFunctionSummaryMap( 1605*a9ac8606Spatrick "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}), 1606*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1607ec727ea7Spatrick 1608ec727ea7Spatrick // int mkstemp(char *template); 1609*a9ac8606Spatrick addToFunctionSummaryMap("mkstemp", 1610*a9ac8606Spatrick Signature(ArgTypes{CharPtrTy}, RetType{IntTy}), 1611*a9ac8606Spatrick Summary(NoEvalCall) 1612*a9ac8606Spatrick .Case(ReturnsFileDescriptor) 1613ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1614ec727ea7Spatrick 1615ec727ea7Spatrick // char *mkdtemp(char *template); 1616ec727ea7Spatrick addToFunctionSummaryMap( 1617*a9ac8606Spatrick "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}), 1618*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1619ec727ea7Spatrick 1620ec727ea7Spatrick // char *getcwd(char *buf, size_t size); 1621ec727ea7Spatrick addToFunctionSummaryMap( 1622*a9ac8606Spatrick "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}), 1623*a9ac8606Spatrick Summary(NoEvalCall) 1624ec727ea7Spatrick .ArgConstraint( 1625ec727ea7Spatrick ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 1626ec727ea7Spatrick 1627ec727ea7Spatrick // int mkdir(const char *pathname, mode_t mode); 1628*a9ac8606Spatrick addToFunctionSummaryMap( 1629*a9ac8606Spatrick "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1630*a9ac8606Spatrick Summary(NoEvalCall) 1631*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1632ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1633ec727ea7Spatrick 1634ec727ea7Spatrick // int mkdirat(int dirfd, const char *pathname, mode_t mode); 1635ec727ea7Spatrick addToFunctionSummaryMap( 1636*a9ac8606Spatrick "mkdirat", 1637*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1638*a9ac8606Spatrick Summary(NoEvalCall) 1639*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1640ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1641ec727ea7Spatrick 1642*a9ac8606Spatrick Optional<QualType> Dev_tTy = lookupTy("dev_t"); 1643ec727ea7Spatrick 1644ec727ea7Spatrick // int mknod(const char *pathname, mode_t mode, dev_t dev); 1645ec727ea7Spatrick addToFunctionSummaryMap( 1646*a9ac8606Spatrick "mknod", 1647*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}), 1648*a9ac8606Spatrick Summary(NoEvalCall) 1649*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1650ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1651ec727ea7Spatrick 1652ec727ea7Spatrick // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); 1653*a9ac8606Spatrick addToFunctionSummaryMap( 1654*a9ac8606Spatrick "mknodat", 1655*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy}, 1656*a9ac8606Spatrick RetType{IntTy}), 1657*a9ac8606Spatrick Summary(NoEvalCall) 1658*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1659ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1660ec727ea7Spatrick 1661ec727ea7Spatrick // int chmod(const char *path, mode_t mode); 1662*a9ac8606Spatrick addToFunctionSummaryMap( 1663*a9ac8606Spatrick "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1664*a9ac8606Spatrick Summary(NoEvalCall) 1665*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1666ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1667ec727ea7Spatrick 1668ec727ea7Spatrick // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); 1669ec727ea7Spatrick addToFunctionSummaryMap( 1670*a9ac8606Spatrick "fchmodat", 1671*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy}, 1672*a9ac8606Spatrick RetType{IntTy}), 1673*a9ac8606Spatrick Summary(NoEvalCall) 1674*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1675*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1676ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1677ec727ea7Spatrick 1678ec727ea7Spatrick // int fchmod(int fildes, mode_t mode); 1679ec727ea7Spatrick addToFunctionSummaryMap( 1680*a9ac8606Spatrick "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}), 1681*a9ac8606Spatrick Summary(NoEvalCall) 1682*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1683ec727ea7Spatrick .ArgConstraint( 1684ec727ea7Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1685ec727ea7Spatrick 1686*a9ac8606Spatrick Optional<QualType> Uid_tTy = lookupTy("uid_t"); 1687*a9ac8606Spatrick Optional<QualType> Gid_tTy = lookupTy("gid_t"); 1688ec727ea7Spatrick 1689ec727ea7Spatrick // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, 1690ec727ea7Spatrick // int flags); 1691ec727ea7Spatrick addToFunctionSummaryMap( 1692ec727ea7Spatrick "fchownat", 1693*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy}, 1694*a9ac8606Spatrick RetType{IntTy}), 1695*a9ac8606Spatrick Summary(NoEvalCall) 1696*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1697*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1698ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1699ec727ea7Spatrick 1700ec727ea7Spatrick // int chown(const char *path, uid_t owner, gid_t group); 1701ec727ea7Spatrick addToFunctionSummaryMap( 1702*a9ac8606Spatrick "chown", 1703*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1704*a9ac8606Spatrick Summary(NoEvalCall) 1705*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1706ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1707ec727ea7Spatrick 1708ec727ea7Spatrick // int lchown(const char *path, uid_t owner, gid_t group); 1709ec727ea7Spatrick addToFunctionSummaryMap( 1710*a9ac8606Spatrick "lchown", 1711*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1712*a9ac8606Spatrick Summary(NoEvalCall) 1713*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1714ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1715ec727ea7Spatrick 1716ec727ea7Spatrick // int fchown(int fildes, uid_t owner, gid_t group); 1717ec727ea7Spatrick addToFunctionSummaryMap( 1718*a9ac8606Spatrick "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1719*a9ac8606Spatrick Summary(NoEvalCall) 1720*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1721*a9ac8606Spatrick .ArgConstraint( 1722*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1723ec727ea7Spatrick 1724ec727ea7Spatrick // int rmdir(const char *pathname); 1725*a9ac8606Spatrick addToFunctionSummaryMap("rmdir", 1726*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1727*a9ac8606Spatrick Summary(NoEvalCall) 1728*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1729ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1730ec727ea7Spatrick 1731ec727ea7Spatrick // int chdir(const char *path); 1732*a9ac8606Spatrick addToFunctionSummaryMap("chdir", 1733*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1734*a9ac8606Spatrick Summary(NoEvalCall) 1735*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1736ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1737ec727ea7Spatrick 1738ec727ea7Spatrick // int link(const char *oldpath, const char *newpath); 1739*a9ac8606Spatrick addToFunctionSummaryMap( 1740*a9ac8606Spatrick "link", 1741*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}), 1742*a9ac8606Spatrick Summary(NoEvalCall) 1743*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1744ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1745ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1746ec727ea7Spatrick 1747ec727ea7Spatrick // int linkat(int fd1, const char *path1, int fd2, const char *path2, 1748ec727ea7Spatrick // int flag); 1749ec727ea7Spatrick addToFunctionSummaryMap( 1750ec727ea7Spatrick "linkat", 1751*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy}, 1752*a9ac8606Spatrick RetType{IntTy}), 1753*a9ac8606Spatrick Summary(NoEvalCall) 1754*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1755ec727ea7Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1756ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1))) 1757ec727ea7Spatrick .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax))) 1758ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(3)))); 1759ec727ea7Spatrick 1760ec727ea7Spatrick // int unlink(const char *pathname); 1761*a9ac8606Spatrick addToFunctionSummaryMap("unlink", 1762*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1763*a9ac8606Spatrick Summary(NoEvalCall) 1764*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1765ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1766ec727ea7Spatrick 1767ec727ea7Spatrick // int unlinkat(int fd, const char *path, int flag); 1768ec727ea7Spatrick addToFunctionSummaryMap( 1769ec727ea7Spatrick "unlinkat", 1770*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}), 1771*a9ac8606Spatrick Summary(NoEvalCall) 1772*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1773ec727ea7Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1774ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1775ec727ea7Spatrick 1776*a9ac8606Spatrick Optional<QualType> StructStatTy = lookupTy("stat"); 1777*a9ac8606Spatrick Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy); 1778*a9ac8606Spatrick Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy); 1779ec727ea7Spatrick 1780ec727ea7Spatrick // int fstat(int fd, struct stat *statbuf); 1781ec727ea7Spatrick addToFunctionSummaryMap( 1782*a9ac8606Spatrick "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}), 1783*a9ac8606Spatrick Summary(NoEvalCall) 1784*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1785*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1786ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1787ec727ea7Spatrick 1788ec727ea7Spatrick // int stat(const char *restrict path, struct stat *restrict buf); 1789ec727ea7Spatrick addToFunctionSummaryMap( 1790ec727ea7Spatrick "stat", 1791*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy}, 1792*a9ac8606Spatrick RetType{IntTy}), 1793*a9ac8606Spatrick Summary(NoEvalCall) 1794*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1795ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1796ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1797ec727ea7Spatrick 1798ec727ea7Spatrick // int lstat(const char *restrict path, struct stat *restrict buf); 1799ec727ea7Spatrick addToFunctionSummaryMap( 1800ec727ea7Spatrick "lstat", 1801*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy}, 1802*a9ac8606Spatrick RetType{IntTy}), 1803*a9ac8606Spatrick Summary(NoEvalCall) 1804*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1805ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1806ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1807ec727ea7Spatrick 1808ec727ea7Spatrick // int fstatat(int fd, const char *restrict path, 1809ec727ea7Spatrick // struct stat *restrict buf, int flag); 1810ec727ea7Spatrick addToFunctionSummaryMap( 1811*a9ac8606Spatrick "fstatat", 1812*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy, 1813*a9ac8606Spatrick StructStatPtrRestrictTy, IntTy}, 1814*a9ac8606Spatrick RetType{IntTy}), 1815*a9ac8606Spatrick Summary(NoEvalCall) 1816*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1817*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1818ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1))) 1819ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(2)))); 1820ec727ea7Spatrick 1821ec727ea7Spatrick // DIR *opendir(const char *name); 1822*a9ac8606Spatrick addToFunctionSummaryMap( 1823*a9ac8606Spatrick "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}), 1824*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1825ec727ea7Spatrick 1826ec727ea7Spatrick // DIR *fdopendir(int fd); 1827*a9ac8606Spatrick addToFunctionSummaryMap("fdopendir", 1828*a9ac8606Spatrick Signature(ArgTypes{IntTy}, RetType{DirPtrTy}), 1829*a9ac8606Spatrick Summary(NoEvalCall) 1830*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1831*a9ac8606Spatrick 0, WithinRange, Range(0, IntMax)))); 1832ec727ea7Spatrick 1833ec727ea7Spatrick // int isatty(int fildes); 1834ec727ea7Spatrick addToFunctionSummaryMap( 1835*a9ac8606Spatrick "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1836*a9ac8606Spatrick Summary(NoEvalCall) 1837*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, Range(0, 1))}) 1838ec727ea7Spatrick .ArgConstraint( 1839ec727ea7Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1840ec727ea7Spatrick 1841ec727ea7Spatrick // FILE *popen(const char *command, const char *type); 1842*a9ac8606Spatrick addToFunctionSummaryMap( 1843*a9ac8606Spatrick "popen", 1844*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}), 1845*a9ac8606Spatrick Summary(NoEvalCall) 1846ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1847ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1848ec727ea7Spatrick 1849ec727ea7Spatrick // int pclose(FILE *stream); 1850ec727ea7Spatrick addToFunctionSummaryMap( 1851*a9ac8606Spatrick "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1852*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1853ec727ea7Spatrick 1854ec727ea7Spatrick // int close(int fildes); 1855*a9ac8606Spatrick addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1856*a9ac8606Spatrick Summary(NoEvalCall) 1857*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1858*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1859*a9ac8606Spatrick 0, WithinRange, Range(-1, IntMax)))); 1860ec727ea7Spatrick 1861ec727ea7Spatrick // long fpathconf(int fildes, int name); 1862*a9ac8606Spatrick addToFunctionSummaryMap("fpathconf", 1863*a9ac8606Spatrick Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}), 1864*a9ac8606Spatrick Summary(NoEvalCall) 1865*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 1866*a9ac8606Spatrick 0, WithinRange, Range(0, IntMax)))); 1867ec727ea7Spatrick 1868ec727ea7Spatrick // long pathconf(const char *path, int name); 1869*a9ac8606Spatrick addToFunctionSummaryMap( 1870*a9ac8606Spatrick "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}), 1871*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1872ec727ea7Spatrick 1873ec727ea7Spatrick // FILE *fdopen(int fd, const char *mode); 1874ec727ea7Spatrick addToFunctionSummaryMap( 1875*a9ac8606Spatrick "fdopen", 1876*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}), 1877*a9ac8606Spatrick Summary(NoEvalCall) 1878*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1879ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 1880ec727ea7Spatrick 1881ec727ea7Spatrick // void rewinddir(DIR *dir); 1882ec727ea7Spatrick addToFunctionSummaryMap( 1883*a9ac8606Spatrick "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}), 1884*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1885ec727ea7Spatrick 1886ec727ea7Spatrick // void seekdir(DIR *dirp, long loc); 1887*a9ac8606Spatrick addToFunctionSummaryMap( 1888*a9ac8606Spatrick "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}), 1889*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1890ec727ea7Spatrick 1891ec727ea7Spatrick // int rand_r(unsigned int *seedp); 1892ec727ea7Spatrick addToFunctionSummaryMap( 1893*a9ac8606Spatrick "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}), 1894*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1895ec727ea7Spatrick 1896ec727ea7Spatrick // int fileno(FILE *stream); 1897*a9ac8606Spatrick addToFunctionSummaryMap("fileno", 1898*a9ac8606Spatrick Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1899*a9ac8606Spatrick Summary(NoEvalCall) 1900*a9ac8606Spatrick .Case(ReturnsFileDescriptor) 1901ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1902ec727ea7Spatrick 1903ec727ea7Spatrick // int fseeko(FILE *stream, off_t offset, int whence); 1904*a9ac8606Spatrick addToFunctionSummaryMap( 1905*a9ac8606Spatrick "fseeko", 1906*a9ac8606Spatrick Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}), 1907*a9ac8606Spatrick Summary(NoEvalCall) 1908*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1909ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1910ec727ea7Spatrick 1911ec727ea7Spatrick // off_t ftello(FILE *stream); 1912ec727ea7Spatrick addToFunctionSummaryMap( 1913*a9ac8606Spatrick "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}), 1914*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1915ec727ea7Spatrick 1916ec727ea7Spatrick // void *mmap(void *addr, size_t length, int prot, int flags, int fd, 1917ec727ea7Spatrick // off_t offset); 1918ec727ea7Spatrick addToFunctionSummaryMap( 1919ec727ea7Spatrick "mmap", 1920*a9ac8606Spatrick Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy}, 1921*a9ac8606Spatrick RetType{VoidPtrTy}), 1922*a9ac8606Spatrick Summary(NoEvalCall) 1923*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1924ec727ea7Spatrick .ArgConstraint( 1925*a9ac8606Spatrick ArgumentCondition(4, WithinRange, Range(-1, IntMax)))); 1926ec727ea7Spatrick 1927*a9ac8606Spatrick Optional<QualType> Off64_tTy = lookupTy("off64_t"); 1928ec727ea7Spatrick // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, 1929ec727ea7Spatrick // off64_t offset); 1930ec727ea7Spatrick addToFunctionSummaryMap( 1931ec727ea7Spatrick "mmap64", 1932*a9ac8606Spatrick Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy}, 1933*a9ac8606Spatrick RetType{VoidPtrTy}), 1934*a9ac8606Spatrick Summary(NoEvalCall) 1935*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1936ec727ea7Spatrick .ArgConstraint( 1937*a9ac8606Spatrick ArgumentCondition(4, WithinRange, Range(-1, IntMax)))); 1938ec727ea7Spatrick 1939ec727ea7Spatrick // int pipe(int fildes[2]); 1940*a9ac8606Spatrick addToFunctionSummaryMap("pipe", 1941*a9ac8606Spatrick Signature(ArgTypes{IntPtrTy}, RetType{IntTy}), 1942*a9ac8606Spatrick Summary(NoEvalCall) 1943*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1944ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 1945ec727ea7Spatrick 1946ec727ea7Spatrick // off_t lseek(int fildes, off_t offset, int whence); 1947ec727ea7Spatrick addToFunctionSummaryMap( 1948*a9ac8606Spatrick "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}), 1949*a9ac8606Spatrick Summary(NoEvalCall) 1950*a9ac8606Spatrick .ArgConstraint( 1951*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1952ec727ea7Spatrick 1953ec727ea7Spatrick // ssize_t readlink(const char *restrict path, char *restrict buf, 1954ec727ea7Spatrick // size_t bufsize); 1955ec727ea7Spatrick addToFunctionSummaryMap( 1956ec727ea7Spatrick "readlink", 1957*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1958*a9ac8606Spatrick RetType{Ssize_tTy}), 1959*a9ac8606Spatrick Summary(NoEvalCall) 1960*a9ac8606Spatrick .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1961*a9ac8606Spatrick ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 1962ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 1963ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1))) 1964ec727ea7Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1965ec727ea7Spatrick /*BufSize=*/ArgNo(2))) 1966ec727ea7Spatrick .ArgConstraint( 1967ec727ea7Spatrick ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); 1968ec727ea7Spatrick 1969ec727ea7Spatrick // ssize_t readlinkat(int fd, const char *restrict path, 1970ec727ea7Spatrick // char *restrict buf, size_t bufsize); 1971ec727ea7Spatrick addToFunctionSummaryMap( 1972*a9ac8606Spatrick "readlinkat", 1973*a9ac8606Spatrick Signature( 1974*a9ac8606Spatrick ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1975*a9ac8606Spatrick RetType{Ssize_tTy}), 1976*a9ac8606Spatrick Summary(NoEvalCall) 1977*a9ac8606Spatrick .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)), 1978*a9ac8606Spatrick ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 1979*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1980ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1))) 1981ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(2))) 1982ec727ea7Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), 1983ec727ea7Spatrick /*BufSize=*/ArgNo(3))) 1984*a9ac8606Spatrick .ArgConstraint( 1985*a9ac8606Spatrick ArgumentCondition(3, WithinRange, Range(0, SizeMax)))); 1986ec727ea7Spatrick 1987ec727ea7Spatrick // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char 1988ec727ea7Spatrick // *newpath); 1989*a9ac8606Spatrick addToFunctionSummaryMap( 1990*a9ac8606Spatrick "renameat", 1991*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy}, 1992*a9ac8606Spatrick RetType{IntTy}), 1993*a9ac8606Spatrick Summary(NoEvalCall) 1994*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 1995ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1))) 1996ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(3)))); 1997ec727ea7Spatrick 1998ec727ea7Spatrick // char *realpath(const char *restrict file_name, 1999ec727ea7Spatrick // char *restrict resolved_name); 2000ec727ea7Spatrick addToFunctionSummaryMap( 2001*a9ac8606Spatrick "realpath", 2002*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy}, 2003*a9ac8606Spatrick RetType{CharPtrTy}), 2004*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2005ec727ea7Spatrick 2006*a9ac8606Spatrick QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy)); 2007ec727ea7Spatrick 2008ec727ea7Spatrick // int execv(const char *path, char *const argv[]); 2009*a9ac8606Spatrick addToFunctionSummaryMap( 2010*a9ac8606Spatrick "execv", 2011*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 2012*a9ac8606Spatrick Summary(NoEvalCall) 2013*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, SingleValue(-1))}) 2014ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 2015ec727ea7Spatrick 2016ec727ea7Spatrick // int execvp(const char *file, char *const argv[]); 2017*a9ac8606Spatrick addToFunctionSummaryMap( 2018*a9ac8606Spatrick "execvp", 2019*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 2020*a9ac8606Spatrick Summary(NoEvalCall) 2021*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, SingleValue(-1))}) 2022ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 2023ec727ea7Spatrick 2024ec727ea7Spatrick // int getopt(int argc, char * const argv[], const char *optstring); 2025ec727ea7Spatrick addToFunctionSummaryMap( 2026ec727ea7Spatrick "getopt", 2027*a9ac8606Spatrick Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy}, 2028*a9ac8606Spatrick RetType{IntTy}), 2029*a9ac8606Spatrick Summary(NoEvalCall) 2030*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))}) 2031ec727ea7Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2032ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1))) 2033ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(2)))); 2034*a9ac8606Spatrick 2035*a9ac8606Spatrick Optional<QualType> StructSockaddrTy = lookupTy("sockaddr"); 2036*a9ac8606Spatrick Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy); 2037*a9ac8606Spatrick Optional<QualType> ConstStructSockaddrPtrTy = 2038*a9ac8606Spatrick getPointerTy(getConstTy(StructSockaddrTy)); 2039*a9ac8606Spatrick Optional<QualType> StructSockaddrPtrRestrictTy = 2040*a9ac8606Spatrick getRestrictTy(StructSockaddrPtrTy); 2041*a9ac8606Spatrick Optional<QualType> ConstStructSockaddrPtrRestrictTy = 2042*a9ac8606Spatrick getRestrictTy(ConstStructSockaddrPtrTy); 2043*a9ac8606Spatrick Optional<QualType> Socklen_tTy = lookupTy("socklen_t"); 2044*a9ac8606Spatrick Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy); 2045*a9ac8606Spatrick Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy); 2046*a9ac8606Spatrick Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy); 2047*a9ac8606Spatrick 2048*a9ac8606Spatrick // In 'socket.h' of some libc implementations with C99, sockaddr parameter 2049*a9ac8606Spatrick // is a transparent union of the underlying sockaddr_ family of pointers 2050*a9ac8606Spatrick // instead of being a pointer to struct sockaddr. In these cases, the 2051*a9ac8606Spatrick // standardized signature will not match, thus we try to match with another 2052*a9ac8606Spatrick // signature that has the joker Irrelevant type. We also remove those 2053*a9ac8606Spatrick // constraints which require pointer types for the sockaddr param. 2054*a9ac8606Spatrick auto Accept = 2055*a9ac8606Spatrick Summary(NoEvalCall) 2056*a9ac8606Spatrick .Case(ReturnsFileDescriptor) 2057*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))); 2058*a9ac8606Spatrick if (!addToFunctionSummaryMap( 2059*a9ac8606Spatrick "accept", 2060*a9ac8606Spatrick // int accept(int socket, struct sockaddr *restrict address, 2061*a9ac8606Spatrick // socklen_t *restrict address_len); 2062*a9ac8606Spatrick Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 2063*a9ac8606Spatrick Socklen_tPtrRestrictTy}, 2064*a9ac8606Spatrick RetType{IntTy}), 2065*a9ac8606Spatrick Accept)) 2066*a9ac8606Spatrick addToFunctionSummaryMap( 2067*a9ac8606Spatrick "accept", 2068*a9ac8606Spatrick Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 2069*a9ac8606Spatrick RetType{IntTy}), 2070*a9ac8606Spatrick Accept); 2071*a9ac8606Spatrick 2072*a9ac8606Spatrick // int bind(int socket, const struct sockaddr *address, socklen_t 2073*a9ac8606Spatrick // address_len); 2074*a9ac8606Spatrick if (!addToFunctionSummaryMap( 2075*a9ac8606Spatrick "bind", 2076*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 2077*a9ac8606Spatrick RetType{IntTy}), 2078*a9ac8606Spatrick Summary(NoEvalCall) 2079*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2080*a9ac8606Spatrick .ArgConstraint( 2081*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2082*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1))) 2083*a9ac8606Spatrick .ArgConstraint( 2084*a9ac8606Spatrick BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2))) 2085*a9ac8606Spatrick .ArgConstraint( 2086*a9ac8606Spatrick ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))))) 2087*a9ac8606Spatrick // Do not add constraints on sockaddr. 2088*a9ac8606Spatrick addToFunctionSummaryMap( 2089*a9ac8606Spatrick "bind", 2090*a9ac8606Spatrick Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 2091*a9ac8606Spatrick Summary(NoEvalCall) 2092*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2093*a9ac8606Spatrick .ArgConstraint( 2094*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2095*a9ac8606Spatrick .ArgConstraint( 2096*a9ac8606Spatrick ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))); 2097*a9ac8606Spatrick 2098*a9ac8606Spatrick // int getpeername(int socket, struct sockaddr *restrict address, 2099*a9ac8606Spatrick // socklen_t *restrict address_len); 2100*a9ac8606Spatrick if (!addToFunctionSummaryMap( 2101*a9ac8606Spatrick "getpeername", 2102*a9ac8606Spatrick Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 2103*a9ac8606Spatrick Socklen_tPtrRestrictTy}, 2104*a9ac8606Spatrick RetType{IntTy}), 2105*a9ac8606Spatrick Summary(NoEvalCall) 2106*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2107*a9ac8606Spatrick .ArgConstraint( 2108*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2109*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1))) 2110*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(2))))) 2111*a9ac8606Spatrick addToFunctionSummaryMap( 2112*a9ac8606Spatrick "getpeername", 2113*a9ac8606Spatrick Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 2114*a9ac8606Spatrick RetType{IntTy}), 2115*a9ac8606Spatrick Summary(NoEvalCall) 2116*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2117*a9ac8606Spatrick .ArgConstraint( 2118*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2119*a9ac8606Spatrick 2120*a9ac8606Spatrick // int getsockname(int socket, struct sockaddr *restrict address, 2121*a9ac8606Spatrick // socklen_t *restrict address_len); 2122*a9ac8606Spatrick if (!addToFunctionSummaryMap( 2123*a9ac8606Spatrick "getsockname", 2124*a9ac8606Spatrick Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 2125*a9ac8606Spatrick Socklen_tPtrRestrictTy}, 2126*a9ac8606Spatrick RetType{IntTy}), 2127*a9ac8606Spatrick Summary(NoEvalCall) 2128*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2129*a9ac8606Spatrick .ArgConstraint( 2130*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2131*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1))) 2132*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(2))))) 2133*a9ac8606Spatrick addToFunctionSummaryMap( 2134*a9ac8606Spatrick "getsockname", 2135*a9ac8606Spatrick Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 2136*a9ac8606Spatrick RetType{IntTy}), 2137*a9ac8606Spatrick Summary(NoEvalCall) 2138*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2139*a9ac8606Spatrick .ArgConstraint( 2140*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2141*a9ac8606Spatrick 2142*a9ac8606Spatrick // int connect(int socket, const struct sockaddr *address, socklen_t 2143*a9ac8606Spatrick // address_len); 2144*a9ac8606Spatrick if (!addToFunctionSummaryMap( 2145*a9ac8606Spatrick "connect", 2146*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 2147*a9ac8606Spatrick RetType{IntTy}), 2148*a9ac8606Spatrick Summary(NoEvalCall) 2149*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2150*a9ac8606Spatrick .ArgConstraint( 2151*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2152*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1))))) 2153*a9ac8606Spatrick addToFunctionSummaryMap( 2154*a9ac8606Spatrick "connect", 2155*a9ac8606Spatrick Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 2156*a9ac8606Spatrick Summary(NoEvalCall) 2157*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2158*a9ac8606Spatrick .ArgConstraint( 2159*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2160*a9ac8606Spatrick 2161*a9ac8606Spatrick auto Recvfrom = 2162*a9ac8606Spatrick Summary(NoEvalCall) 2163*a9ac8606Spatrick .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2164*a9ac8606Spatrick ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2165*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2166*a9ac8606Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2167*a9ac8606Spatrick /*BufSize=*/ArgNo(2))); 2168*a9ac8606Spatrick if (!addToFunctionSummaryMap( 2169*a9ac8606Spatrick "recvfrom", 2170*a9ac8606Spatrick // ssize_t recvfrom(int socket, void *restrict buffer, 2171*a9ac8606Spatrick // size_t length, 2172*a9ac8606Spatrick // int flags, struct sockaddr *restrict address, 2173*a9ac8606Spatrick // socklen_t *restrict address_len); 2174*a9ac8606Spatrick Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 2175*a9ac8606Spatrick StructSockaddrPtrRestrictTy, 2176*a9ac8606Spatrick Socklen_tPtrRestrictTy}, 2177*a9ac8606Spatrick RetType{Ssize_tTy}), 2178*a9ac8606Spatrick Recvfrom)) 2179*a9ac8606Spatrick addToFunctionSummaryMap( 2180*a9ac8606Spatrick "recvfrom", 2181*a9ac8606Spatrick Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 2182*a9ac8606Spatrick Irrelevant, Socklen_tPtrRestrictTy}, 2183*a9ac8606Spatrick RetType{Ssize_tTy}), 2184*a9ac8606Spatrick Recvfrom); 2185*a9ac8606Spatrick 2186*a9ac8606Spatrick auto Sendto = 2187*a9ac8606Spatrick Summary(NoEvalCall) 2188*a9ac8606Spatrick .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2189*a9ac8606Spatrick ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2190*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2191*a9ac8606Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2192*a9ac8606Spatrick /*BufSize=*/ArgNo(2))); 2193*a9ac8606Spatrick if (!addToFunctionSummaryMap( 2194*a9ac8606Spatrick "sendto", 2195*a9ac8606Spatrick // ssize_t sendto(int socket, const void *message, size_t length, 2196*a9ac8606Spatrick // int flags, const struct sockaddr *dest_addr, 2197*a9ac8606Spatrick // socklen_t dest_len); 2198*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, 2199*a9ac8606Spatrick ConstStructSockaddrPtrTy, Socklen_tTy}, 2200*a9ac8606Spatrick RetType{Ssize_tTy}), 2201*a9ac8606Spatrick Sendto)) 2202*a9ac8606Spatrick addToFunctionSummaryMap( 2203*a9ac8606Spatrick "sendto", 2204*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant, 2205*a9ac8606Spatrick Socklen_tTy}, 2206*a9ac8606Spatrick RetType{Ssize_tTy}), 2207*a9ac8606Spatrick Sendto); 2208*a9ac8606Spatrick 2209*a9ac8606Spatrick // int listen(int sockfd, int backlog); 2210*a9ac8606Spatrick addToFunctionSummaryMap("listen", 2211*a9ac8606Spatrick Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 2212*a9ac8606Spatrick Summary(NoEvalCall) 2213*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2214*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 2215*a9ac8606Spatrick 0, WithinRange, Range(0, IntMax)))); 2216*a9ac8606Spatrick 2217*a9ac8606Spatrick // ssize_t recv(int sockfd, void *buf, size_t len, int flags); 2218*a9ac8606Spatrick addToFunctionSummaryMap( 2219*a9ac8606Spatrick "recv", 2220*a9ac8606Spatrick Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, 2221*a9ac8606Spatrick RetType{Ssize_tTy}), 2222*a9ac8606Spatrick Summary(NoEvalCall) 2223*a9ac8606Spatrick .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2224*a9ac8606Spatrick ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2225*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2226*a9ac8606Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2227*a9ac8606Spatrick /*BufSize=*/ArgNo(2)))); 2228*a9ac8606Spatrick 2229*a9ac8606Spatrick Optional<QualType> StructMsghdrTy = lookupTy("msghdr"); 2230*a9ac8606Spatrick Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy); 2231*a9ac8606Spatrick Optional<QualType> ConstStructMsghdrPtrTy = 2232*a9ac8606Spatrick getPointerTy(getConstTy(StructMsghdrTy)); 2233*a9ac8606Spatrick 2234*a9ac8606Spatrick // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 2235*a9ac8606Spatrick addToFunctionSummaryMap( 2236*a9ac8606Spatrick "recvmsg", 2237*a9ac8606Spatrick Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy}, 2238*a9ac8606Spatrick RetType{Ssize_tTy}), 2239*a9ac8606Spatrick Summary(NoEvalCall) 2240*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2241*a9ac8606Spatrick .ArgConstraint( 2242*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2243*a9ac8606Spatrick 2244*a9ac8606Spatrick // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 2245*a9ac8606Spatrick addToFunctionSummaryMap( 2246*a9ac8606Spatrick "sendmsg", 2247*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy}, 2248*a9ac8606Spatrick RetType{Ssize_tTy}), 2249*a9ac8606Spatrick Summary(NoEvalCall) 2250*a9ac8606Spatrick .Case({ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2251*a9ac8606Spatrick .ArgConstraint( 2252*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2253*a9ac8606Spatrick 2254*a9ac8606Spatrick // int setsockopt(int socket, int level, int option_name, 2255*a9ac8606Spatrick // const void *option_value, socklen_t option_len); 2256*a9ac8606Spatrick addToFunctionSummaryMap( 2257*a9ac8606Spatrick "setsockopt", 2258*a9ac8606Spatrick Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy}, 2259*a9ac8606Spatrick RetType{IntTy}), 2260*a9ac8606Spatrick Summary(NoEvalCall) 2261*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2262*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(3))) 2263*a9ac8606Spatrick .ArgConstraint( 2264*a9ac8606Spatrick BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4))) 2265*a9ac8606Spatrick .ArgConstraint( 2266*a9ac8606Spatrick ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax)))); 2267*a9ac8606Spatrick 2268*a9ac8606Spatrick // int getsockopt(int socket, int level, int option_name, 2269*a9ac8606Spatrick // void *restrict option_value, 2270*a9ac8606Spatrick // socklen_t *restrict option_len); 2271*a9ac8606Spatrick addToFunctionSummaryMap( 2272*a9ac8606Spatrick "getsockopt", 2273*a9ac8606Spatrick Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy, 2274*a9ac8606Spatrick Socklen_tPtrRestrictTy}, 2275*a9ac8606Spatrick RetType{IntTy}), 2276*a9ac8606Spatrick Summary(NoEvalCall) 2277*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2278*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(3))) 2279*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(4)))); 2280*a9ac8606Spatrick 2281*a9ac8606Spatrick // ssize_t send(int sockfd, const void *buf, size_t len, int flags); 2282*a9ac8606Spatrick addToFunctionSummaryMap( 2283*a9ac8606Spatrick "send", 2284*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy}, 2285*a9ac8606Spatrick RetType{Ssize_tTy}), 2286*a9ac8606Spatrick Summary(NoEvalCall) 2287*a9ac8606Spatrick .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2288*a9ac8606Spatrick ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2289*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2290*a9ac8606Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2291*a9ac8606Spatrick /*BufSize=*/ArgNo(2)))); 2292*a9ac8606Spatrick 2293*a9ac8606Spatrick // int socketpair(int domain, int type, int protocol, int sv[2]); 2294*a9ac8606Spatrick addToFunctionSummaryMap( 2295*a9ac8606Spatrick "socketpair", 2296*a9ac8606Spatrick Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}), 2297*a9ac8606Spatrick Summary(NoEvalCall) 2298*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2299*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(3)))); 2300*a9ac8606Spatrick 2301*a9ac8606Spatrick // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, 2302*a9ac8606Spatrick // char *restrict node, socklen_t nodelen, 2303*a9ac8606Spatrick // char *restrict service, 2304*a9ac8606Spatrick // socklen_t servicelen, int flags); 2305*a9ac8606Spatrick // 2306*a9ac8606Spatrick // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr 2307*a9ac8606Spatrick // parameter is never handled as a transparent union in netdb.h 2308*a9ac8606Spatrick addToFunctionSummaryMap( 2309*a9ac8606Spatrick "getnameinfo", 2310*a9ac8606Spatrick Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy, 2311*a9ac8606Spatrick CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy, 2312*a9ac8606Spatrick Socklen_tTy, IntTy}, 2313*a9ac8606Spatrick RetType{IntTy}), 2314*a9ac8606Spatrick Summary(NoEvalCall) 2315*a9ac8606Spatrick .ArgConstraint( 2316*a9ac8606Spatrick BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))) 2317*a9ac8606Spatrick .ArgConstraint( 2318*a9ac8606Spatrick ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax))) 2319*a9ac8606Spatrick .ArgConstraint( 2320*a9ac8606Spatrick BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3))) 2321*a9ac8606Spatrick .ArgConstraint( 2322*a9ac8606Spatrick ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax))) 2323*a9ac8606Spatrick .ArgConstraint( 2324*a9ac8606Spatrick BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5))) 2325*a9ac8606Spatrick .ArgConstraint( 2326*a9ac8606Spatrick ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax)))); 2327*a9ac8606Spatrick 2328*a9ac8606Spatrick Optional<QualType> StructUtimbufTy = lookupTy("utimbuf"); 2329*a9ac8606Spatrick Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy); 2330*a9ac8606Spatrick 2331*a9ac8606Spatrick // int utime(const char *filename, struct utimbuf *buf); 2332*a9ac8606Spatrick addToFunctionSummaryMap( 2333*a9ac8606Spatrick "utime", 2334*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}), 2335*a9ac8606Spatrick Summary(NoEvalCall) 2336*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2337*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 2338*a9ac8606Spatrick 2339*a9ac8606Spatrick Optional<QualType> StructTimespecTy = lookupTy("timespec"); 2340*a9ac8606Spatrick Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy); 2341*a9ac8606Spatrick Optional<QualType> ConstStructTimespecPtrTy = 2342*a9ac8606Spatrick getPointerTy(getConstTy(StructTimespecTy)); 2343*a9ac8606Spatrick 2344*a9ac8606Spatrick // int futimens(int fd, const struct timespec times[2]); 2345*a9ac8606Spatrick addToFunctionSummaryMap( 2346*a9ac8606Spatrick "futimens", 2347*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}), 2348*a9ac8606Spatrick Summary(NoEvalCall) 2349*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2350*a9ac8606Spatrick .ArgConstraint( 2351*a9ac8606Spatrick ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2352*a9ac8606Spatrick 2353*a9ac8606Spatrick // int utimensat(int dirfd, const char *pathname, 2354*a9ac8606Spatrick // const struct timespec times[2], int flags); 2355*a9ac8606Spatrick addToFunctionSummaryMap("utimensat", 2356*a9ac8606Spatrick Signature(ArgTypes{IntTy, ConstCharPtrTy, 2357*a9ac8606Spatrick ConstStructTimespecPtrTy, IntTy}, 2358*a9ac8606Spatrick RetType{IntTy}), 2359*a9ac8606Spatrick Summary(NoEvalCall) 2360*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2361*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 2362*a9ac8606Spatrick 2363*a9ac8606Spatrick Optional<QualType> StructTimevalTy = lookupTy("timeval"); 2364*a9ac8606Spatrick Optional<QualType> ConstStructTimevalPtrTy = 2365*a9ac8606Spatrick getPointerTy(getConstTy(StructTimevalTy)); 2366*a9ac8606Spatrick 2367*a9ac8606Spatrick // int utimes(const char *filename, const struct timeval times[2]); 2368*a9ac8606Spatrick addToFunctionSummaryMap( 2369*a9ac8606Spatrick "utimes", 2370*a9ac8606Spatrick Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy}, 2371*a9ac8606Spatrick RetType{IntTy}), 2372*a9ac8606Spatrick Summary(NoEvalCall) 2373*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2374*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 2375*a9ac8606Spatrick 2376*a9ac8606Spatrick // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); 2377*a9ac8606Spatrick addToFunctionSummaryMap( 2378*a9ac8606Spatrick "nanosleep", 2379*a9ac8606Spatrick Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy}, 2380*a9ac8606Spatrick RetType{IntTy}), 2381*a9ac8606Spatrick Summary(NoEvalCall) 2382*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2383*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0)))); 2384*a9ac8606Spatrick 2385*a9ac8606Spatrick Optional<QualType> Time_tTy = lookupTy("time_t"); 2386*a9ac8606Spatrick Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy)); 2387*a9ac8606Spatrick Optional<QualType> ConstTime_tPtrRestrictTy = 2388*a9ac8606Spatrick getRestrictTy(ConstTime_tPtrTy); 2389*a9ac8606Spatrick 2390*a9ac8606Spatrick Optional<QualType> StructTmTy = lookupTy("tm"); 2391*a9ac8606Spatrick Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy); 2392*a9ac8606Spatrick Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy); 2393*a9ac8606Spatrick Optional<QualType> ConstStructTmPtrTy = 2394*a9ac8606Spatrick getPointerTy(getConstTy(StructTmTy)); 2395*a9ac8606Spatrick Optional<QualType> ConstStructTmPtrRestrictTy = 2396*a9ac8606Spatrick getRestrictTy(ConstStructTmPtrTy); 2397*a9ac8606Spatrick 2398*a9ac8606Spatrick // struct tm * localtime(const time_t *tp); 2399*a9ac8606Spatrick addToFunctionSummaryMap( 2400*a9ac8606Spatrick "localtime", 2401*a9ac8606Spatrick Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 2402*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2403*a9ac8606Spatrick 2404*a9ac8606Spatrick // struct tm *localtime_r(const time_t *restrict timer, 2405*a9ac8606Spatrick // struct tm *restrict result); 2406*a9ac8606Spatrick addToFunctionSummaryMap( 2407*a9ac8606Spatrick "localtime_r", 2408*a9ac8606Spatrick Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 2409*a9ac8606Spatrick RetType{StructTmPtrTy}), 2410*a9ac8606Spatrick Summary(NoEvalCall) 2411*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0))) 2412*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 2413*a9ac8606Spatrick 2414*a9ac8606Spatrick // char *asctime_r(const struct tm *restrict tm, char *restrict buf); 2415*a9ac8606Spatrick addToFunctionSummaryMap( 2416*a9ac8606Spatrick "asctime_r", 2417*a9ac8606Spatrick Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy}, 2418*a9ac8606Spatrick RetType{CharPtrTy}), 2419*a9ac8606Spatrick Summary(NoEvalCall) 2420*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0))) 2421*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1))) 2422*a9ac8606Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2423*a9ac8606Spatrick /*MinBufSize=*/BVF.getValue(26, IntTy)))); 2424*a9ac8606Spatrick 2425*a9ac8606Spatrick // char *ctime_r(const time_t *timep, char *buf); 2426*a9ac8606Spatrick addToFunctionSummaryMap( 2427*a9ac8606Spatrick "ctime_r", 2428*a9ac8606Spatrick Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}), 2429*a9ac8606Spatrick Summary(NoEvalCall) 2430*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0))) 2431*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1))) 2432*a9ac8606Spatrick .ArgConstraint(BufferSize( 2433*a9ac8606Spatrick /*Buffer=*/ArgNo(1), 2434*a9ac8606Spatrick /*MinBufSize=*/BVF.getValue(26, IntTy)))); 2435*a9ac8606Spatrick 2436*a9ac8606Spatrick // struct tm *gmtime_r(const time_t *restrict timer, 2437*a9ac8606Spatrick // struct tm *restrict result); 2438*a9ac8606Spatrick addToFunctionSummaryMap( 2439*a9ac8606Spatrick "gmtime_r", 2440*a9ac8606Spatrick Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 2441*a9ac8606Spatrick RetType{StructTmPtrTy}), 2442*a9ac8606Spatrick Summary(NoEvalCall) 2443*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0))) 2444*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 2445*a9ac8606Spatrick 2446*a9ac8606Spatrick // struct tm * gmtime(const time_t *tp); 2447*a9ac8606Spatrick addToFunctionSummaryMap( 2448*a9ac8606Spatrick "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 2449*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2450*a9ac8606Spatrick 2451*a9ac8606Spatrick Optional<QualType> Clockid_tTy = lookupTy("clockid_t"); 2452*a9ac8606Spatrick 2453*a9ac8606Spatrick // int clock_gettime(clockid_t clock_id, struct timespec *tp); 2454*a9ac8606Spatrick addToFunctionSummaryMap( 2455*a9ac8606Spatrick "clock_gettime", 2456*a9ac8606Spatrick Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}), 2457*a9ac8606Spatrick Summary(NoEvalCall) 2458*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2459*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 2460*a9ac8606Spatrick 2461*a9ac8606Spatrick Optional<QualType> StructItimervalTy = lookupTy("itimerval"); 2462*a9ac8606Spatrick Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy); 2463*a9ac8606Spatrick 2464*a9ac8606Spatrick // int getitimer(int which, struct itimerval *curr_value); 2465*a9ac8606Spatrick addToFunctionSummaryMap( 2466*a9ac8606Spatrick "getitimer", 2467*a9ac8606Spatrick Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}), 2468*a9ac8606Spatrick Summary(NoEvalCall) 2469*a9ac8606Spatrick .Case(ReturnsZeroOrMinusOne) 2470*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 2471*a9ac8606Spatrick 2472*a9ac8606Spatrick Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t"); 2473*a9ac8606Spatrick Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy); 2474*a9ac8606Spatrick Optional<QualType> Pthread_tTy = lookupTy("pthread_t"); 2475*a9ac8606Spatrick Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy); 2476*a9ac8606Spatrick Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy); 2477*a9ac8606Spatrick Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t"); 2478*a9ac8606Spatrick Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy); 2479*a9ac8606Spatrick Optional<QualType> Pthread_mutex_tPtrRestrictTy = 2480*a9ac8606Spatrick getRestrictTy(Pthread_mutex_tPtrTy); 2481*a9ac8606Spatrick Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t"); 2482*a9ac8606Spatrick Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy); 2483*a9ac8606Spatrick Optional<QualType> ConstPthread_attr_tPtrTy = 2484*a9ac8606Spatrick getPointerTy(getConstTy(Pthread_attr_tTy)); 2485*a9ac8606Spatrick Optional<QualType> ConstPthread_attr_tPtrRestrictTy = 2486*a9ac8606Spatrick getRestrictTy(ConstPthread_attr_tPtrTy); 2487*a9ac8606Spatrick Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t"); 2488*a9ac8606Spatrick Optional<QualType> ConstPthread_mutexattr_tPtrTy = 2489*a9ac8606Spatrick getPointerTy(getConstTy(Pthread_mutexattr_tTy)); 2490*a9ac8606Spatrick Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy = 2491*a9ac8606Spatrick getRestrictTy(ConstPthread_mutexattr_tPtrTy); 2492*a9ac8606Spatrick 2493*a9ac8606Spatrick QualType PthreadStartRoutineTy = getPointerTy( 2494*a9ac8606Spatrick ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy, 2495*a9ac8606Spatrick FunctionProtoType::ExtProtoInfo())); 2496*a9ac8606Spatrick 2497*a9ac8606Spatrick // int pthread_cond_signal(pthread_cond_t *cond); 2498*a9ac8606Spatrick // int pthread_cond_broadcast(pthread_cond_t *cond); 2499*a9ac8606Spatrick addToFunctionSummaryMap( 2500*a9ac8606Spatrick {"pthread_cond_signal", "pthread_cond_broadcast"}, 2501*a9ac8606Spatrick Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}), 2502*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2503*a9ac8606Spatrick 2504*a9ac8606Spatrick // int pthread_create(pthread_t *restrict thread, 2505*a9ac8606Spatrick // const pthread_attr_t *restrict attr, 2506*a9ac8606Spatrick // void *(*start_routine)(void*), void *restrict arg); 2507*a9ac8606Spatrick addToFunctionSummaryMap( 2508*a9ac8606Spatrick "pthread_create", 2509*a9ac8606Spatrick Signature(ArgTypes{Pthread_tPtrRestrictTy, 2510*a9ac8606Spatrick ConstPthread_attr_tPtrRestrictTy, 2511*a9ac8606Spatrick PthreadStartRoutineTy, VoidPtrRestrictTy}, 2512*a9ac8606Spatrick RetType{IntTy}), 2513*a9ac8606Spatrick Summary(NoEvalCall) 2514*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0))) 2515*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(2)))); 2516*a9ac8606Spatrick 2517*a9ac8606Spatrick // int pthread_attr_destroy(pthread_attr_t *attr); 2518*a9ac8606Spatrick // int pthread_attr_init(pthread_attr_t *attr); 2519*a9ac8606Spatrick addToFunctionSummaryMap( 2520*a9ac8606Spatrick {"pthread_attr_destroy", "pthread_attr_init"}, 2521*a9ac8606Spatrick Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}), 2522*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2523*a9ac8606Spatrick 2524*a9ac8606Spatrick // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, 2525*a9ac8606Spatrick // size_t *restrict stacksize); 2526*a9ac8606Spatrick // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, 2527*a9ac8606Spatrick // size_t *restrict guardsize); 2528*a9ac8606Spatrick addToFunctionSummaryMap( 2529*a9ac8606Spatrick {"pthread_attr_getstacksize", "pthread_attr_getguardsize"}, 2530*a9ac8606Spatrick Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy}, 2531*a9ac8606Spatrick RetType{IntTy}), 2532*a9ac8606Spatrick Summary(NoEvalCall) 2533*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0))) 2534*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 2535*a9ac8606Spatrick 2536*a9ac8606Spatrick // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); 2537*a9ac8606Spatrick // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); 2538*a9ac8606Spatrick addToFunctionSummaryMap( 2539*a9ac8606Spatrick {"pthread_attr_setstacksize", "pthread_attr_setguardsize"}, 2540*a9ac8606Spatrick Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}), 2541*a9ac8606Spatrick Summary(NoEvalCall) 2542*a9ac8606Spatrick .ArgConstraint(NotNull(ArgNo(0))) 2543*a9ac8606Spatrick .ArgConstraint( 2544*a9ac8606Spatrick ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 2545*a9ac8606Spatrick 2546*a9ac8606Spatrick // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const 2547*a9ac8606Spatrick // pthread_mutexattr_t *restrict attr); 2548*a9ac8606Spatrick addToFunctionSummaryMap( 2549*a9ac8606Spatrick "pthread_mutex_init", 2550*a9ac8606Spatrick Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy, 2551*a9ac8606Spatrick ConstPthread_mutexattr_tPtrRestrictTy}, 2552*a9ac8606Spatrick RetType{IntTy}), 2553*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2554*a9ac8606Spatrick 2555*a9ac8606Spatrick // int pthread_mutex_destroy(pthread_mutex_t *mutex); 2556*a9ac8606Spatrick // int pthread_mutex_lock(pthread_mutex_t *mutex); 2557*a9ac8606Spatrick // int pthread_mutex_trylock(pthread_mutex_t *mutex); 2558*a9ac8606Spatrick // int pthread_mutex_unlock(pthread_mutex_t *mutex); 2559*a9ac8606Spatrick addToFunctionSummaryMap( 2560*a9ac8606Spatrick {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock", 2561*a9ac8606Spatrick "pthread_mutex_unlock"}, 2562*a9ac8606Spatrick Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}), 2563*a9ac8606Spatrick Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2564ec727ea7Spatrick } 2565ec727ea7Spatrick 2566ec727ea7Spatrick // Functions for testing. 2567ec727ea7Spatrick if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) { 2568ec727ea7Spatrick addToFunctionSummaryMap( 2569*a9ac8606Spatrick "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}), 2570*a9ac8606Spatrick Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0)))); 2571*a9ac8606Spatrick 2572*a9ac8606Spatrick // Test range values. 2573*a9ac8606Spatrick addToFunctionSummaryMap( 2574*a9ac8606Spatrick "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2575*a9ac8606Spatrick Summary(EvalCallAsPure) 2576*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))); 2577*a9ac8606Spatrick addToFunctionSummaryMap( 2578*a9ac8606Spatrick "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2579*a9ac8606Spatrick Summary(EvalCallAsPure) 2580*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2)))); 2581*a9ac8606Spatrick addToFunctionSummaryMap("__range_1_2__4_5", 2582*a9ac8606Spatrick Signature(ArgTypes{IntTy}, RetType{IntTy}), 2583*a9ac8606Spatrick Summary(EvalCallAsPure) 2584*a9ac8606Spatrick .ArgConstraint(ArgumentCondition( 2585*a9ac8606Spatrick 0U, WithinRange, Range({1, 2}, {4, 5})))); 2586*a9ac8606Spatrick 2587*a9ac8606Spatrick // Test range kind. 2588*a9ac8606Spatrick addToFunctionSummaryMap( 2589*a9ac8606Spatrick "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2590*a9ac8606Spatrick Summary(EvalCallAsPure) 2591*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))); 2592*a9ac8606Spatrick addToFunctionSummaryMap( 2593*a9ac8606Spatrick "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2594*a9ac8606Spatrick Summary(EvalCallAsPure) 2595*a9ac8606Spatrick .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))); 2596*a9ac8606Spatrick 2597*a9ac8606Spatrick addToFunctionSummaryMap( 2598ec727ea7Spatrick "__two_constrained_args", 2599*a9ac8606Spatrick Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 2600*a9ac8606Spatrick Summary(EvalCallAsPure) 2601ec727ea7Spatrick .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))) 2602ec727ea7Spatrick .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1)))); 2603ec727ea7Spatrick addToFunctionSummaryMap( 2604*a9ac8606Spatrick "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2605*a9ac8606Spatrick Summary(EvalCallAsPure) 2606ec727ea7Spatrick .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))) 2607ec727ea7Spatrick .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2)))); 2608ec727ea7Spatrick addToFunctionSummaryMap( 2609ec727ea7Spatrick "__defaultparam", 2610*a9ac8606Spatrick Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}), 2611*a9ac8606Spatrick Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0)))); 2612*a9ac8606Spatrick addToFunctionSummaryMap( 2613*a9ac8606Spatrick "__variadic", 2614*a9ac8606Spatrick Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}), 2615*a9ac8606Spatrick Summary(EvalCallAsPure) 2616ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(0))) 2617ec727ea7Spatrick .ArgConstraint(NotNull(ArgNo(1)))); 2618ec727ea7Spatrick addToFunctionSummaryMap( 2619ec727ea7Spatrick "__buf_size_arg_constraint", 2620*a9ac8606Spatrick Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}), 2621*a9ac8606Spatrick Summary(EvalCallAsPure) 2622ec727ea7Spatrick .ArgConstraint( 2623ec727ea7Spatrick BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))); 2624ec727ea7Spatrick addToFunctionSummaryMap( 2625ec727ea7Spatrick "__buf_size_arg_constraint_mul", 2626*a9ac8606Spatrick Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}), 2627*a9ac8606Spatrick Summary(EvalCallAsPure) 2628ec727ea7Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 2629ec727ea7Spatrick /*BufSizeMultiplier=*/ArgNo(2)))); 2630*a9ac8606Spatrick addToFunctionSummaryMap( 2631*a9ac8606Spatrick "__buf_size_arg_constraint_concrete", 2632*a9ac8606Spatrick Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}), 2633*a9ac8606Spatrick Summary(EvalCallAsPure) 2634*a9ac8606Spatrick .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), 2635*a9ac8606Spatrick /*BufSize=*/BVF.getValue(10, IntTy)))); 2636*a9ac8606Spatrick addToFunctionSummaryMap( 2637*a9ac8606Spatrick {"__test_restrict_param_0", "__test_restrict_param_1", 2638*a9ac8606Spatrick "__test_restrict_param_2"}, 2639*a9ac8606Spatrick Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}), 2640*a9ac8606Spatrick Summary(EvalCallAsPure)); 2641ec727ea7Spatrick } 2642*a9ac8606Spatrick 2643*a9ac8606Spatrick SummariesInitialized = true; 2644e5dd7070Spatrick } 2645e5dd7070Spatrick 2646e5dd7070Spatrick void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 2647ec727ea7Spatrick auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>(); 2648ec727ea7Spatrick Checker->DisplayLoadedSummaries = 2649ec727ea7Spatrick mgr.getAnalyzerOptions().getCheckerBooleanOption( 2650ec727ea7Spatrick Checker, "DisplayLoadedSummaries"); 2651ec727ea7Spatrick Checker->ModelPOSIX = 2652ec727ea7Spatrick mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX"); 2653e5dd7070Spatrick } 2654e5dd7070Spatrick 2655*a9ac8606Spatrick bool ento::shouldRegisterStdCLibraryFunctionsChecker( 2656*a9ac8606Spatrick const CheckerManager &mgr) { 2657e5dd7070Spatrick return true; 2658e5dd7070Spatrick } 2659ec727ea7Spatrick 2660ec727ea7Spatrick #define REGISTER_CHECKER(name) \ 2661ec727ea7Spatrick void ento::register##name(CheckerManager &mgr) { \ 2662ec727ea7Spatrick StdLibraryFunctionsChecker *checker = \ 2663ec727ea7Spatrick mgr.getChecker<StdLibraryFunctionsChecker>(); \ 2664ec727ea7Spatrick checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \ 2665ec727ea7Spatrick checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \ 2666ec727ea7Spatrick mgr.getCurrentCheckerName(); \ 2667ec727ea7Spatrick } \ 2668ec727ea7Spatrick \ 2669ec727ea7Spatrick bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 2670ec727ea7Spatrick 2671ec727ea7Spatrick REGISTER_CHECKER(StdCLibraryFunctionArgsChecker) 2672ec727ea7Spatrick REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker) 2673