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