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 &ArgConstraint(ValueConstraintPtr VC) { 461 assert(VC->getArgNo() != Ret && 462 "Arg constraint should not refer to the return value"); 463 ArgConstraints.push_back(VC); 464 return *this; 465 } 466 467 InvalidationKind getInvalidationKd() const { return InvalidationKd; } 468 const Cases &getCaseConstraints() const { return CaseConstraints; } 469 const ConstraintSet &getArgConstraints() const { return ArgConstraints; } 470 471 QualType getArgType(ArgNo ArgN) const { 472 return StdLibraryFunctionsChecker::getArgType(FD, ArgN); 473 } 474 475 // Returns true if the summary should be applied to the given function. 476 // And if yes then store the function declaration. 477 bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) { 478 bool Result = Sign.matches(FD) && validateByConstraints(FD); 479 if (Result) { 480 assert(!this->FD && "FD must not be set more than once"); 481 this->FD = FD; 482 } 483 return Result; 484 } 485 486 private: 487 // Once we know the exact type of the function then do sanity check on all 488 // the given constraints. 489 bool validateByConstraints(const FunctionDecl *FD) const { 490 for (const ConstraintSet &Case : CaseConstraints) 491 for (const ValueConstraintPtr &Constraint : Case) 492 if (!Constraint->checkValidity(FD)) 493 return false; 494 for (const ValueConstraintPtr &Constraint : ArgConstraints) 495 if (!Constraint->checkValidity(FD)) 496 return false; 497 return true; 498 } 499 }; 500 501 // The map of all functions supported by the checker. It is initialized 502 // lazily, and it doesn't change after initialization. 503 using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>; 504 mutable FunctionSummaryMapType FunctionSummaryMap; 505 506 mutable std::unique_ptr<BugType> BT_InvalidArg; 507 508 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) { 509 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN); 510 } 511 512 public: 513 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 514 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 515 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 516 517 enum CheckKind { 518 CK_StdCLibraryFunctionArgsChecker, 519 CK_StdCLibraryFunctionsTesterChecker, 520 CK_NumCheckKinds 521 }; 522 DefaultBool ChecksEnabled[CK_NumCheckKinds]; 523 CheckerNameRef CheckNames[CK_NumCheckKinds]; 524 525 bool DisplayLoadedSummaries = false; 526 bool ModelPOSIX = false; 527 528 private: 529 Optional<Summary> findFunctionSummary(const FunctionDecl *FD, 530 CheckerContext &C) const; 531 Optional<Summary> findFunctionSummary(const CallEvent &Call, 532 CheckerContext &C) const; 533 534 void initFunctionSummaries(CheckerContext &C) const; 535 536 void reportBug(const CallEvent &Call, ExplodedNode *N, 537 const ValueConstraint *VC, CheckerContext &C) const { 538 if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker]) 539 return; 540 // TODO Add more detailed diagnostic. 541 std::string Msg = 542 (Twine("Function argument constraint is not satisfied, constraint: ") + 543 VC->getName().data() + ", ArgN: " + Twine(VC->getArgNo())) 544 .str(); 545 if (!BT_InvalidArg) 546 BT_InvalidArg = std::make_unique<BugType>( 547 CheckNames[CK_StdCLibraryFunctionArgsChecker], 548 "Unsatisfied argument constraints", categories::LogicError); 549 auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N); 550 bugreporter::trackExpressionValue(N, Call.getArgExpr(VC->getArgNo()), *R); 551 552 // Highlight the range of the argument that was violated. 553 R->addRange(Call.getArgSourceRange(VC->getArgNo())); 554 555 C.emitReport(std::move(R)); 556 } 557 }; 558 559 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret = 560 std::numeric_limits<ArgNo>::max(); 561 562 } // end of anonymous namespace 563 564 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange( 565 ProgramStateRef State, const CallEvent &Call, 566 const Summary &Summary) const { 567 if (Ranges.empty()) 568 return State; 569 570 ProgramStateManager &Mgr = State->getStateManager(); 571 SValBuilder &SVB = Mgr.getSValBuilder(); 572 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 573 ConstraintManager &CM = Mgr.getConstraintManager(); 574 QualType T = Summary.getArgType(getArgNo()); 575 SVal V = getArgSVal(Call, getArgNo()); 576 577 if (auto N = V.getAs<NonLoc>()) { 578 const IntRangeVector &R = getRanges(); 579 size_t E = R.size(); 580 for (size_t I = 0; I != E; ++I) { 581 const llvm::APSInt &Min = BVF.getValue(R[I].first, T); 582 const llvm::APSInt &Max = BVF.getValue(R[I].second, T); 583 assert(Min <= Max); 584 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 585 if (!State) 586 break; 587 } 588 } 589 590 return State; 591 } 592 593 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange( 594 ProgramStateRef State, const CallEvent &Call, 595 const Summary &Summary) const { 596 if (Ranges.empty()) 597 return State; 598 599 ProgramStateManager &Mgr = State->getStateManager(); 600 SValBuilder &SVB = Mgr.getSValBuilder(); 601 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 602 ConstraintManager &CM = Mgr.getConstraintManager(); 603 QualType T = Summary.getArgType(getArgNo()); 604 SVal V = getArgSVal(Call, getArgNo()); 605 606 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R". 607 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary, 608 // and then cut away all holes in R one by one. 609 // 610 // E.g. consider a range list R as [A, B] and [C, D] 611 // -------+--------+------------------+------------+-----------> 612 // A B C D 613 // Then we assume that the value is not in [-inf, A - 1], 614 // then not in [D + 1, +inf], then not in [B + 1, C - 1] 615 if (auto N = V.getAs<NonLoc>()) { 616 const IntRangeVector &R = getRanges(); 617 size_t E = R.size(); 618 619 const llvm::APSInt &MinusInf = BVF.getMinValue(T); 620 const llvm::APSInt &PlusInf = BVF.getMaxValue(T); 621 622 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T); 623 if (Left != PlusInf) { 624 assert(MinusInf <= Left); 625 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false); 626 if (!State) 627 return nullptr; 628 } 629 630 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T); 631 if (Right != MinusInf) { 632 assert(Right <= PlusInf); 633 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false); 634 if (!State) 635 return nullptr; 636 } 637 638 for (size_t I = 1; I != E; ++I) { 639 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T); 640 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T); 641 if (Min <= Max) { 642 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 643 if (!State) 644 return nullptr; 645 } 646 } 647 } 648 649 return State; 650 } 651 652 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply( 653 ProgramStateRef State, const CallEvent &Call, const Summary &Summary, 654 CheckerContext &C) const { 655 656 ProgramStateManager &Mgr = State->getStateManager(); 657 SValBuilder &SVB = Mgr.getSValBuilder(); 658 QualType CondT = SVB.getConditionType(); 659 QualType T = Summary.getArgType(getArgNo()); 660 SVal V = getArgSVal(Call, getArgNo()); 661 662 BinaryOperator::Opcode Op = getOpcode(); 663 ArgNo OtherArg = getOtherArgNo(); 664 SVal OtherV = getArgSVal(Call, OtherArg); 665 QualType OtherT = Summary.getArgType(OtherArg); 666 // Note: we avoid integral promotion for comparison. 667 OtherV = SVB.evalCast(OtherV, T, OtherT); 668 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT) 669 .getAs<DefinedOrUnknownSVal>()) 670 State = State->assume(*CompV, true); 671 return State; 672 } 673 674 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call, 675 CheckerContext &C) const { 676 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 677 if (!FoundSummary) 678 return; 679 680 const Summary &Summary = *FoundSummary; 681 ProgramStateRef State = C.getState(); 682 683 ProgramStateRef NewState = State; 684 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) { 685 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C); 686 ProgramStateRef FailureSt = 687 Constraint->negate()->apply(NewState, Call, Summary, C); 688 // The argument constraint is not satisfied. 689 if (FailureSt && !SuccessSt) { 690 if (ExplodedNode *N = C.generateErrorNode(NewState)) 691 reportBug(Call, N, Constraint.get(), C); 692 break; 693 } else { 694 // We will apply the constraint even if we cannot reason about the 695 // argument. This means both SuccessSt and FailureSt can be true. If we 696 // weren't applying the constraint that would mean that symbolic 697 // execution continues on a code whose behaviour is undefined. 698 assert(SuccessSt); 699 NewState = SuccessSt; 700 } 701 } 702 if (NewState && NewState != State) 703 C.addTransition(NewState); 704 } 705 706 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, 707 CheckerContext &C) const { 708 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 709 if (!FoundSummary) 710 return; 711 712 // Now apply the constraints. 713 const Summary &Summary = *FoundSummary; 714 ProgramStateRef State = C.getState(); 715 716 // Apply case/branch specifications. 717 for (const ConstraintSet &Case : Summary.getCaseConstraints()) { 718 ProgramStateRef NewState = State; 719 for (const ValueConstraintPtr &Constraint : Case) { 720 NewState = Constraint->apply(NewState, Call, Summary, C); 721 if (!NewState) 722 break; 723 } 724 725 if (NewState && NewState != State) 726 C.addTransition(NewState); 727 } 728 } 729 730 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, 731 CheckerContext &C) const { 732 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 733 if (!FoundSummary) 734 return false; 735 736 const Summary &Summary = *FoundSummary; 737 switch (Summary.getInvalidationKd()) { 738 case EvalCallAsPure: { 739 ProgramStateRef State = C.getState(); 740 const LocationContext *LC = C.getLocationContext(); 741 const auto *CE = cast_or_null<CallExpr>(Call.getOriginExpr()); 742 SVal V = C.getSValBuilder().conjureSymbolVal( 743 CE, LC, CE->getType().getCanonicalType(), C.blockCount()); 744 State = State->BindExpr(CE, LC, V); 745 C.addTransition(State); 746 return true; 747 } 748 case NoEvalCall: 749 // Summary tells us to avoid performing eval::Call. The function is possibly 750 // evaluated by another checker, or evaluated conservatively. 751 return false; 752 } 753 llvm_unreachable("Unknown invalidation kind!"); 754 } 755 756 bool StdLibraryFunctionsChecker::Signature::matches( 757 const FunctionDecl *FD) const { 758 assert(!isInvalid()); 759 // Check the number of arguments. 760 if (FD->param_size() != ArgTys.size()) 761 return false; 762 763 // The "restrict" keyword is illegal in C++, however, many libc 764 // implementations use the "__restrict" compiler intrinsic in functions 765 // prototypes. The "__restrict" keyword qualifies a type as a restricted type 766 // even in C++. 767 // In case of any non-C99 languages, we don't want to match based on the 768 // restrict qualifier because we cannot know if the given libc implementation 769 // qualifies the paramter type or not. 770 auto RemoveRestrict = [&FD](QualType T) { 771 if (!FD->getASTContext().getLangOpts().C99) 772 T.removeLocalRestrict(); 773 return T; 774 }; 775 776 // Check the return type. 777 if (!isIrrelevant(RetTy)) { 778 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType()); 779 if (RetTy != FDRetTy) 780 return false; 781 } 782 783 // Check the argument types. 784 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) { 785 QualType ArgTy = ArgTys[I]; 786 if (isIrrelevant(ArgTy)) 787 continue; 788 QualType FDArgTy = 789 RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType()); 790 if (ArgTy != FDArgTy) 791 return false; 792 } 793 794 return true; 795 } 796 797 Optional<StdLibraryFunctionsChecker::Summary> 798 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, 799 CheckerContext &C) const { 800 if (!FD) 801 return None; 802 803 initFunctionSummaries(C); 804 805 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl()); 806 if (FSMI == FunctionSummaryMap.end()) 807 return None; 808 return FSMI->second; 809 } 810 811 Optional<StdLibraryFunctionsChecker::Summary> 812 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call, 813 CheckerContext &C) const { 814 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 815 if (!FD) 816 return None; 817 return findFunctionSummary(FD, C); 818 } 819 820 void StdLibraryFunctionsChecker::initFunctionSummaries( 821 CheckerContext &C) const { 822 if (!FunctionSummaryMap.empty()) 823 return; 824 825 SValBuilder &SVB = C.getSValBuilder(); 826 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 827 const ASTContext &ACtx = BVF.getContext(); 828 829 // Helper class to lookup a type by its name. 830 class LookupType { 831 const ASTContext &ACtx; 832 833 public: 834 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {} 835 836 // Find the type. If not found then the optional is not set. 837 llvm::Optional<QualType> operator()(StringRef Name) { 838 IdentifierInfo &II = ACtx.Idents.get(Name); 839 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 840 if (LookupRes.size() == 0) 841 return None; 842 843 // Prioritze typedef declarations. 844 // This is needed in case of C struct typedefs. E.g.: 845 // typedef struct FILE FILE; 846 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' 847 // and we have a TypedefDecl with the name 'FILE'. 848 for (Decl *D : LookupRes) 849 if (auto *TD = dyn_cast<TypedefNameDecl>(D)) 850 return ACtx.getTypeDeclType(TD).getCanonicalType(); 851 852 // Find the first TypeDecl. 853 // There maybe cases when a function has the same name as a struct. 854 // E.g. in POSIX: `struct stat` and the function `stat()`: 855 // int stat(const char *restrict path, struct stat *restrict buf); 856 for (Decl *D : LookupRes) 857 if (auto *TD = dyn_cast<TypeDecl>(D)) 858 return ACtx.getTypeDeclType(TD).getCanonicalType(); 859 return None; 860 } 861 } lookupTy(ACtx); 862 863 // Below are auxiliary classes to handle optional types that we get as a 864 // result of the lookup. 865 class GetRestrictTy { 866 const ASTContext &ACtx; 867 868 public: 869 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {} 870 QualType operator()(QualType Ty) { 871 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty; 872 } 873 Optional<QualType> operator()(Optional<QualType> Ty) { 874 if (Ty) 875 return operator()(*Ty); 876 return None; 877 } 878 } getRestrictTy(ACtx); 879 class GetPointerTy { 880 const ASTContext &ACtx; 881 882 public: 883 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {} 884 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); } 885 Optional<QualType> operator()(Optional<QualType> Ty) { 886 if (Ty) 887 return operator()(*Ty); 888 return None; 889 } 890 } getPointerTy(ACtx); 891 class { 892 public: 893 Optional<QualType> operator()(Optional<QualType> Ty) { 894 return Ty ? Optional<QualType>(Ty->withConst()) : None; 895 } 896 QualType operator()(QualType Ty) { return Ty.withConst(); } 897 } getConstTy; 898 class GetMaxValue { 899 BasicValueFactory &BVF; 900 901 public: 902 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {} 903 Optional<RangeInt> operator()(QualType Ty) { 904 return BVF.getMaxValue(Ty).getLimitedValue(); 905 } 906 Optional<RangeInt> operator()(Optional<QualType> Ty) { 907 if (Ty) { 908 return operator()(*Ty); 909 } 910 return None; 911 } 912 } getMaxValue(BVF); 913 914 // These types are useful for writing specifications quickly, 915 // New specifications should probably introduce more types. 916 // Some types are hard to obtain from the AST, eg. "ssize_t". 917 // In such cases it should be possible to provide multiple variants 918 // of function summary for common cases (eg. ssize_t could be int or long 919 // or long long, so three summary variants would be enough). 920 // Of course, function variants are also useful for C++ overloads. 921 const QualType VoidTy = ACtx.VoidTy; 922 const QualType CharTy = ACtx.CharTy; 923 const QualType WCharTy = ACtx.WCharTy; 924 const QualType IntTy = ACtx.IntTy; 925 const QualType UnsignedIntTy = ACtx.UnsignedIntTy; 926 const QualType LongTy = ACtx.LongTy; 927 const QualType SizeTy = ACtx.getSizeType(); 928 929 const QualType VoidPtrTy = getPointerTy(VoidTy); // void * 930 const QualType IntPtrTy = getPointerTy(IntTy); // int * 931 const QualType UnsignedIntPtrTy = 932 getPointerTy(UnsignedIntTy); // unsigned int * 933 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy); 934 const QualType ConstVoidPtrTy = 935 getPointerTy(getConstTy(VoidTy)); // const void * 936 const QualType CharPtrTy = getPointerTy(CharTy); // char * 937 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy); 938 const QualType ConstCharPtrTy = 939 getPointerTy(getConstTy(CharTy)); // const char * 940 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy); 941 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t * 942 const QualType ConstWchar_tPtrTy = 943 getPointerTy(getConstTy(WCharTy)); // const wchar_t * 944 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy); 945 const QualType SizePtrTy = getPointerTy(SizeTy); 946 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy); 947 948 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 949 const RangeInt UnsignedIntMax = 950 BVF.getMaxValue(UnsignedIntTy).getLimitedValue(); 951 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 952 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue(); 953 954 // Set UCharRangeMax to min of int or uchar maximum value. 955 // The C standard states that the arguments of functions like isalpha must 956 // be representable as an unsigned char. Their type is 'int', so the max 957 // value of the argument should be min(UCharMax, IntMax). This just happen 958 // to be true for commonly used and well tested instruction set 959 // architectures, but not for others. 960 const RangeInt UCharRangeMax = 961 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax); 962 963 // The platform dependent value of EOF. 964 // Try our best to parse this from the Preprocessor, otherwise fallback to -1. 965 const auto EOFv = [&C]() -> RangeInt { 966 if (const llvm::Optional<int> OptInt = 967 tryExpandAsInteger("EOF", C.getPreprocessor())) 968 return *OptInt; 969 return -1; 970 }(); 971 972 // Auxiliary class to aid adding summaries to the summary map. 973 struct AddToFunctionSummaryMap { 974 const ASTContext &ACtx; 975 FunctionSummaryMapType ⤅ 976 bool DisplayLoadedSummaries; 977 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM, 978 bool DisplayLoadedSummaries) 979 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) { 980 } 981 982 // Add a summary to a FunctionDecl found by lookup. The lookup is performed 983 // by the given Name, and in the global scope. The summary will be attached 984 // to the found FunctionDecl only if the signatures match. 985 // 986 // Returns true if the summary has been added, false otherwise. 987 bool operator()(StringRef Name, Signature Sign, Summary Sum) { 988 if (Sign.isInvalid()) 989 return false; 990 IdentifierInfo &II = ACtx.Idents.get(Name); 991 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 992 if (LookupRes.size() == 0) 993 return false; 994 for (Decl *D : LookupRes) { 995 if (auto *FD = dyn_cast<FunctionDecl>(D)) { 996 if (Sum.matchesAndSet(Sign, FD)) { 997 auto Res = Map.insert({FD->getCanonicalDecl(), Sum}); 998 assert(Res.second && "Function already has a summary set!"); 999 (void)Res; 1000 if (DisplayLoadedSummaries) { 1001 llvm::errs() << "Loaded summary for: "; 1002 FD->print(llvm::errs()); 1003 llvm::errs() << "\n"; 1004 } 1005 return true; 1006 } 1007 } 1008 } 1009 return false; 1010 } 1011 // Add the same summary for different names with the Signature explicitly 1012 // given. 1013 void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) { 1014 for (StringRef Name : Names) 1015 operator()(Name, Sign, Sum); 1016 } 1017 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries); 1018 1019 // Below are helpers functions to create the summaries. 1020 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, 1021 IntRangeVector Ranges) { 1022 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges); 1023 }; 1024 auto BufferSize = [](auto... Args) { 1025 return std::make_shared<BufferSizeConstraint>(Args...); 1026 }; 1027 struct { 1028 auto operator()(RangeKind Kind, IntRangeVector Ranges) { 1029 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges); 1030 } 1031 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) { 1032 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN); 1033 } 1034 } ReturnValueCondition; 1035 struct { 1036 auto operator()(RangeInt b, RangeInt e) { 1037 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}}; 1038 } 1039 auto operator()(RangeInt b, Optional<RangeInt> e) { 1040 if (e) 1041 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}}; 1042 return IntRangeVector{}; 1043 } 1044 auto operator()(std::pair<RangeInt, RangeInt> i0, 1045 std::pair<RangeInt, Optional<RangeInt>> i1) { 1046 if (i1.second) 1047 return IntRangeVector{i0, {i1.first, *(i1.second)}}; 1048 return IntRangeVector{i0}; 1049 } 1050 } Range; 1051 auto SingleValue = [](RangeInt v) { 1052 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}}; 1053 }; 1054 auto LessThanOrEq = BO_LE; 1055 auto NotNull = [&](ArgNo ArgN) { 1056 return std::make_shared<NotNullConstraint>(ArgN); 1057 }; 1058 1059 Optional<QualType> FileTy = lookupTy("FILE"); 1060 Optional<QualType> FilePtrTy = getPointerTy(FileTy); 1061 Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy); 1062 1063 // We are finally ready to define specifications for all supported functions. 1064 // 1065 // Argument ranges should always cover all variants. If return value 1066 // is completely unknown, omit it from the respective range set. 1067 // 1068 // Every item in the list of range sets represents a particular 1069 // execution path the analyzer would need to explore once 1070 // the call is modeled - a new program state is constructed 1071 // for every range set, and each range line in the range set 1072 // corresponds to a specific constraint within this state. 1073 1074 // The isascii() family of functions. 1075 // The behavior is undefined if the value of the argument is not 1076 // representable as unsigned char or is not equal to EOF. See e.g. C99 1077 // 7.4.1.2 The isalpha function (p: 181-182). 1078 addToFunctionSummaryMap( 1079 "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1080 Summary(EvalCallAsPure) 1081 // Boils down to isupper() or islower() or isdigit(). 1082 .Case({ArgumentCondition(0U, WithinRange, 1083 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}), 1084 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1085 // The locale-specific range. 1086 // No post-condition. We are completely unaware of 1087 // locale-specific return values. 1088 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1089 .Case( 1090 {ArgumentCondition( 1091 0U, OutOfRange, 1092 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1093 ReturnValueCondition(WithinRange, SingleValue(0))}) 1094 .ArgConstraint(ArgumentCondition( 1095 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1096 addToFunctionSummaryMap( 1097 "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1098 Summary(EvalCallAsPure) 1099 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}), 1100 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1101 // The locale-specific range. 1102 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1103 .Case({ArgumentCondition( 1104 0U, OutOfRange, 1105 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1106 ReturnValueCondition(WithinRange, SingleValue(0))})); 1107 addToFunctionSummaryMap( 1108 "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1109 Summary(EvalCallAsPure) 1110 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1111 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1112 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)), 1113 ReturnValueCondition(WithinRange, SingleValue(0))})); 1114 addToFunctionSummaryMap( 1115 "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1116 Summary(EvalCallAsPure) 1117 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}), 1118 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1119 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}), 1120 ReturnValueCondition(WithinRange, SingleValue(0))})); 1121 addToFunctionSummaryMap( 1122 "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1123 Summary(EvalCallAsPure) 1124 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}), 1125 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1126 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}), 1127 ReturnValueCondition(WithinRange, SingleValue(0))})); 1128 addToFunctionSummaryMap( 1129 "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1130 Summary(EvalCallAsPure) 1131 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')), 1132 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1133 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')), 1134 ReturnValueCondition(WithinRange, SingleValue(0))})); 1135 addToFunctionSummaryMap( 1136 "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1137 Summary(EvalCallAsPure) 1138 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)), 1139 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1140 .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)), 1141 ReturnValueCondition(WithinRange, SingleValue(0))})); 1142 addToFunctionSummaryMap( 1143 "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1144 Summary(EvalCallAsPure) 1145 // Is certainly lowercase. 1146 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')), 1147 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1148 // Is ascii but not lowercase. 1149 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1150 ArgumentCondition(0U, OutOfRange, Range('a', 'z')), 1151 ReturnValueCondition(WithinRange, SingleValue(0))}) 1152 // The locale-specific range. 1153 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1154 // Is not an unsigned char. 1155 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)), 1156 ReturnValueCondition(WithinRange, SingleValue(0))})); 1157 addToFunctionSummaryMap( 1158 "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1159 Summary(EvalCallAsPure) 1160 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)), 1161 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1162 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)), 1163 ReturnValueCondition(WithinRange, SingleValue(0))})); 1164 addToFunctionSummaryMap( 1165 "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1166 Summary(EvalCallAsPure) 1167 .Case({ArgumentCondition( 1168 0U, WithinRange, 1169 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1170 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1171 .Case({ArgumentCondition( 1172 0U, OutOfRange, 1173 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1174 ReturnValueCondition(WithinRange, SingleValue(0))})); 1175 addToFunctionSummaryMap( 1176 "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1177 Summary(EvalCallAsPure) 1178 // Space, '\f', '\n', '\r', '\t', '\v'. 1179 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}), 1180 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1181 // The locale-specific range. 1182 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1183 .Case({ArgumentCondition(0U, OutOfRange, 1184 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}), 1185 ReturnValueCondition(WithinRange, SingleValue(0))})); 1186 addToFunctionSummaryMap( 1187 "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1188 Summary(EvalCallAsPure) 1189 // Is certainly uppercase. 1190 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')), 1191 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1192 // The locale-specific range. 1193 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1194 // Other. 1195 .Case({ArgumentCondition(0U, OutOfRange, 1196 {{'A', 'Z'}, {128, UCharRangeMax}}), 1197 ReturnValueCondition(WithinRange, SingleValue(0))})); 1198 addToFunctionSummaryMap( 1199 "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1200 Summary(EvalCallAsPure) 1201 .Case({ArgumentCondition(0U, WithinRange, 1202 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1203 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1204 .Case({ArgumentCondition(0U, OutOfRange, 1205 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1206 ReturnValueCondition(WithinRange, SingleValue(0))})); 1207 addToFunctionSummaryMap( 1208 "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1209 Summary(EvalCallAsPure) 1210 .ArgConstraint(ArgumentCondition( 1211 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1212 addToFunctionSummaryMap( 1213 "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1214 Summary(EvalCallAsPure) 1215 .ArgConstraint(ArgumentCondition( 1216 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1217 addToFunctionSummaryMap( 1218 "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1219 Summary(EvalCallAsPure) 1220 .ArgConstraint(ArgumentCondition( 1221 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1222 1223 // The getc() family of functions that returns either a char or an EOF. 1224 addToFunctionSummaryMap( 1225 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1226 Summary(NoEvalCall) 1227 .Case({ReturnValueCondition(WithinRange, 1228 {{EOFv, EOFv}, {0, UCharRangeMax}})})); 1229 addToFunctionSummaryMap( 1230 "getchar", Signature(ArgTypes{}, RetType{IntTy}), 1231 Summary(NoEvalCall) 1232 .Case({ReturnValueCondition(WithinRange, 1233 {{EOFv, EOFv}, {0, UCharRangeMax}})})); 1234 1235 // read()-like functions that never return more than buffer size. 1236 auto FreadSummary = 1237 Summary(NoEvalCall) 1238 .Case({ 1239 ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1240 }) 1241 .ArgConstraint(NotNull(ArgNo(0))) 1242 .ArgConstraint(NotNull(ArgNo(3))) 1243 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 1244 /*BufSizeMultiplier=*/ArgNo(2))); 1245 1246 // size_t fread(void *restrict ptr, size_t size, size_t nitems, 1247 // FILE *restrict stream); 1248 addToFunctionSummaryMap( 1249 "fread", 1250 Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy}, 1251 RetType{SizeTy}), 1252 FreadSummary); 1253 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, 1254 // FILE *restrict stream); 1255 addToFunctionSummaryMap("fwrite", 1256 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, 1257 SizeTy, FilePtrRestrictTy}, 1258 RetType{SizeTy}), 1259 FreadSummary); 1260 1261 Optional<QualType> Ssize_tTy = lookupTy("ssize_t"); 1262 Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy); 1263 1264 auto ReadSummary = 1265 Summary(NoEvalCall) 1266 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1267 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}); 1268 1269 // FIXME these are actually defined by POSIX and not by the C standard, we 1270 // should handle them together with the rest of the POSIX functions. 1271 // ssize_t read(int fildes, void *buf, size_t nbyte); 1272 addToFunctionSummaryMap( 1273 "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}), 1274 ReadSummary); 1275 // ssize_t write(int fildes, const void *buf, size_t nbyte); 1276 addToFunctionSummaryMap( 1277 "write", 1278 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}), 1279 ReadSummary); 1280 1281 auto GetLineSummary = 1282 Summary(NoEvalCall) 1283 .Case({ReturnValueCondition(WithinRange, 1284 Range({-1, -1}, {1, Ssize_tMax}))}); 1285 1286 QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy)); 1287 1288 // getline()-like functions either fail or read at least the delimiter. 1289 // FIXME these are actually defined by POSIX and not by the C standard, we 1290 // should handle them together with the rest of the POSIX functions. 1291 // ssize_t getline(char **restrict lineptr, size_t *restrict n, 1292 // FILE *restrict stream); 1293 addToFunctionSummaryMap( 1294 "getline", 1295 Signature( 1296 ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy}, 1297 RetType{Ssize_tTy}), 1298 GetLineSummary); 1299 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n, 1300 // int delimiter, FILE *restrict stream); 1301 addToFunctionSummaryMap( 1302 "getdelim", 1303 Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy, 1304 FilePtrRestrictTy}, 1305 RetType{Ssize_tTy}), 1306 GetLineSummary); 1307 1308 if (ModelPOSIX) { 1309 1310 // long a64l(const char *str64); 1311 addToFunctionSummaryMap( 1312 "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}), 1313 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1314 1315 // char *l64a(long value); 1316 addToFunctionSummaryMap("l64a", 1317 Signature(ArgTypes{LongTy}, RetType{CharPtrTy}), 1318 Summary(NoEvalCall) 1319 .ArgConstraint(ArgumentCondition( 1320 0, WithinRange, Range(0, LongMax)))); 1321 1322 // int access(const char *pathname, int amode); 1323 addToFunctionSummaryMap( 1324 "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}), 1325 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1326 1327 // int faccessat(int dirfd, const char *pathname, int mode, int flags); 1328 addToFunctionSummaryMap( 1329 "faccessat", 1330 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy}, 1331 RetType{IntTy}), 1332 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 1333 1334 // int dup(int fildes); 1335 addToFunctionSummaryMap("dup", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1336 Summary(NoEvalCall) 1337 .ArgConstraint(ArgumentCondition( 1338 0, WithinRange, Range(0, IntMax)))); 1339 1340 // int dup2(int fildes1, int filedes2); 1341 addToFunctionSummaryMap( 1342 "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 1343 Summary(NoEvalCall) 1344 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1345 .ArgConstraint( 1346 ArgumentCondition(1, WithinRange, Range(0, IntMax)))); 1347 1348 // int fdatasync(int fildes); 1349 addToFunctionSummaryMap("fdatasync", 1350 Signature(ArgTypes{IntTy}, RetType{IntTy}), 1351 Summary(NoEvalCall) 1352 .ArgConstraint(ArgumentCondition( 1353 0, WithinRange, Range(0, IntMax)))); 1354 1355 // int fnmatch(const char *pattern, const char *string, int flags); 1356 addToFunctionSummaryMap( 1357 "fnmatch", 1358 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy}, 1359 RetType{IntTy}), 1360 Summary(EvalCallAsPure) 1361 .ArgConstraint(NotNull(ArgNo(0))) 1362 .ArgConstraint(NotNull(ArgNo(1)))); 1363 1364 // int fsync(int fildes); 1365 addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1366 Summary(NoEvalCall) 1367 .ArgConstraint(ArgumentCondition( 1368 0, WithinRange, Range(0, IntMax)))); 1369 1370 Optional<QualType> Off_tTy = lookupTy("off_t"); 1371 1372 // int truncate(const char *path, off_t length); 1373 addToFunctionSummaryMap( 1374 "truncate", 1375 Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}), 1376 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1377 1378 // int symlink(const char *oldpath, const char *newpath); 1379 addToFunctionSummaryMap( 1380 "symlink", 1381 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}), 1382 Summary(NoEvalCall) 1383 .ArgConstraint(NotNull(ArgNo(0))) 1384 .ArgConstraint(NotNull(ArgNo(1)))); 1385 1386 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath); 1387 addToFunctionSummaryMap( 1388 "symlinkat", 1389 Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, 1390 RetType{IntTy}), 1391 Summary(NoEvalCall) 1392 .ArgConstraint(NotNull(ArgNo(0))) 1393 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax))) 1394 .ArgConstraint(NotNull(ArgNo(2)))); 1395 1396 // int lockf(int fd, int cmd, off_t len); 1397 addToFunctionSummaryMap( 1398 "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}), 1399 Summary(NoEvalCall) 1400 .ArgConstraint( 1401 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1402 1403 Optional<QualType> Mode_tTy = lookupTy("mode_t"); 1404 1405 // int creat(const char *pathname, mode_t mode); 1406 addToFunctionSummaryMap( 1407 "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1408 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1409 1410 // unsigned int sleep(unsigned int seconds); 1411 addToFunctionSummaryMap( 1412 "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}), 1413 Summary(NoEvalCall) 1414 .ArgConstraint( 1415 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1416 1417 Optional<QualType> DirTy = lookupTy("DIR"); 1418 Optional<QualType> DirPtrTy = getPointerTy(DirTy); 1419 1420 // int dirfd(DIR *dirp); 1421 addToFunctionSummaryMap( 1422 "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}), 1423 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1424 1425 // unsigned int alarm(unsigned int seconds); 1426 addToFunctionSummaryMap( 1427 "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}), 1428 Summary(NoEvalCall) 1429 .ArgConstraint( 1430 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1431 1432 // int closedir(DIR *dir); 1433 addToFunctionSummaryMap( 1434 "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}), 1435 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1436 1437 // char *strdup(const char *s); 1438 addToFunctionSummaryMap( 1439 "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}), 1440 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1441 1442 // char *strndup(const char *s, size_t n); 1443 addToFunctionSummaryMap( 1444 "strndup", 1445 Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}), 1446 Summary(NoEvalCall) 1447 .ArgConstraint(NotNull(ArgNo(0))) 1448 .ArgConstraint( 1449 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 1450 1451 // wchar_t *wcsdup(const wchar_t *s); 1452 addToFunctionSummaryMap( 1453 "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}), 1454 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1455 1456 // int mkstemp(char *template); 1457 addToFunctionSummaryMap( 1458 "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}), 1459 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1460 1461 // char *mkdtemp(char *template); 1462 addToFunctionSummaryMap( 1463 "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}), 1464 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1465 1466 // char *getcwd(char *buf, size_t size); 1467 addToFunctionSummaryMap( 1468 "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}), 1469 Summary(NoEvalCall) 1470 .ArgConstraint( 1471 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 1472 1473 // int mkdir(const char *pathname, mode_t mode); 1474 addToFunctionSummaryMap( 1475 "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1476 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1477 1478 // int mkdirat(int dirfd, const char *pathname, mode_t mode); 1479 addToFunctionSummaryMap( 1480 "mkdirat", 1481 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1482 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 1483 1484 Optional<QualType> Dev_tTy = lookupTy("dev_t"); 1485 1486 // int mknod(const char *pathname, mode_t mode, dev_t dev); 1487 addToFunctionSummaryMap( 1488 "mknod", 1489 Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}), 1490 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1491 1492 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); 1493 addToFunctionSummaryMap( 1494 "mknodat", 1495 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy}, 1496 RetType{IntTy}), 1497 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 1498 1499 // int chmod(const char *path, mode_t mode); 1500 addToFunctionSummaryMap( 1501 "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1502 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1503 1504 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); 1505 addToFunctionSummaryMap( 1506 "fchmodat", 1507 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy}, 1508 RetType{IntTy}), 1509 Summary(NoEvalCall) 1510 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1511 .ArgConstraint(NotNull(ArgNo(1)))); 1512 1513 // int fchmod(int fildes, mode_t mode); 1514 addToFunctionSummaryMap( 1515 "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}), 1516 Summary(NoEvalCall) 1517 .ArgConstraint( 1518 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1519 1520 Optional<QualType> Uid_tTy = lookupTy("uid_t"); 1521 Optional<QualType> Gid_tTy = lookupTy("gid_t"); 1522 1523 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, 1524 // int flags); 1525 addToFunctionSummaryMap( 1526 "fchownat", 1527 Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy}, 1528 RetType{IntTy}), 1529 Summary(NoEvalCall) 1530 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1531 .ArgConstraint(NotNull(ArgNo(1)))); 1532 1533 // int chown(const char *path, uid_t owner, gid_t group); 1534 addToFunctionSummaryMap( 1535 "chown", 1536 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1537 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1538 1539 // int lchown(const char *path, uid_t owner, gid_t group); 1540 addToFunctionSummaryMap( 1541 "lchown", 1542 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1543 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1544 1545 // int fchown(int fildes, uid_t owner, gid_t group); 1546 addToFunctionSummaryMap( 1547 "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1548 Summary(NoEvalCall) 1549 .ArgConstraint( 1550 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1551 1552 // int rmdir(const char *pathname); 1553 addToFunctionSummaryMap( 1554 "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1555 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1556 1557 // int chdir(const char *path); 1558 addToFunctionSummaryMap( 1559 "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1560 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1561 1562 // int link(const char *oldpath, const char *newpath); 1563 addToFunctionSummaryMap( 1564 "link", 1565 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}), 1566 Summary(NoEvalCall) 1567 .ArgConstraint(NotNull(ArgNo(0))) 1568 .ArgConstraint(NotNull(ArgNo(1)))); 1569 1570 // int linkat(int fd1, const char *path1, int fd2, const char *path2, 1571 // int flag); 1572 addToFunctionSummaryMap( 1573 "linkat", 1574 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy}, 1575 RetType{IntTy}), 1576 Summary(NoEvalCall) 1577 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1578 .ArgConstraint(NotNull(ArgNo(1))) 1579 .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax))) 1580 .ArgConstraint(NotNull(ArgNo(3)))); 1581 1582 // int unlink(const char *pathname); 1583 addToFunctionSummaryMap( 1584 "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1585 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1586 1587 // int unlinkat(int fd, const char *path, int flag); 1588 addToFunctionSummaryMap( 1589 "unlinkat", 1590 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}), 1591 Summary(NoEvalCall) 1592 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1593 .ArgConstraint(NotNull(ArgNo(1)))); 1594 1595 Optional<QualType> StructStatTy = lookupTy("stat"); 1596 Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy); 1597 Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy); 1598 1599 // int fstat(int fd, struct stat *statbuf); 1600 addToFunctionSummaryMap( 1601 "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}), 1602 Summary(NoEvalCall) 1603 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1604 .ArgConstraint(NotNull(ArgNo(1)))); 1605 1606 // int stat(const char *restrict path, struct stat *restrict buf); 1607 addToFunctionSummaryMap( 1608 "stat", 1609 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy}, 1610 RetType{IntTy}), 1611 Summary(NoEvalCall) 1612 .ArgConstraint(NotNull(ArgNo(0))) 1613 .ArgConstraint(NotNull(ArgNo(1)))); 1614 1615 // int lstat(const char *restrict path, struct stat *restrict buf); 1616 addToFunctionSummaryMap( 1617 "lstat", 1618 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy}, 1619 RetType{IntTy}), 1620 Summary(NoEvalCall) 1621 .ArgConstraint(NotNull(ArgNo(0))) 1622 .ArgConstraint(NotNull(ArgNo(1)))); 1623 1624 // int fstatat(int fd, const char *restrict path, 1625 // struct stat *restrict buf, int flag); 1626 addToFunctionSummaryMap( 1627 "fstatat", 1628 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy, 1629 StructStatPtrRestrictTy, IntTy}, 1630 RetType{IntTy}), 1631 Summary(NoEvalCall) 1632 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1633 .ArgConstraint(NotNull(ArgNo(1))) 1634 .ArgConstraint(NotNull(ArgNo(2)))); 1635 1636 // DIR *opendir(const char *name); 1637 addToFunctionSummaryMap( 1638 "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}), 1639 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1640 1641 // DIR *fdopendir(int fd); 1642 addToFunctionSummaryMap("fdopendir", 1643 Signature(ArgTypes{IntTy}, RetType{DirPtrTy}), 1644 Summary(NoEvalCall) 1645 .ArgConstraint(ArgumentCondition( 1646 0, WithinRange, Range(0, IntMax)))); 1647 1648 // int isatty(int fildes); 1649 addToFunctionSummaryMap("isatty", 1650 Signature(ArgTypes{IntTy}, RetType{IntTy}), 1651 Summary(NoEvalCall) 1652 .ArgConstraint(ArgumentCondition( 1653 0, WithinRange, Range(0, IntMax)))); 1654 1655 // FILE *popen(const char *command, const char *type); 1656 addToFunctionSummaryMap( 1657 "popen", 1658 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}), 1659 Summary(NoEvalCall) 1660 .ArgConstraint(NotNull(ArgNo(0))) 1661 .ArgConstraint(NotNull(ArgNo(1)))); 1662 1663 // int pclose(FILE *stream); 1664 addToFunctionSummaryMap( 1665 "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1666 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1667 1668 // int close(int fildes); 1669 addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1670 Summary(NoEvalCall) 1671 .ArgConstraint(ArgumentCondition( 1672 0, WithinRange, Range(0, IntMax)))); 1673 1674 // long fpathconf(int fildes, int name); 1675 addToFunctionSummaryMap("fpathconf", 1676 Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}), 1677 Summary(NoEvalCall) 1678 .ArgConstraint(ArgumentCondition( 1679 0, WithinRange, Range(0, IntMax)))); 1680 1681 // long pathconf(const char *path, int name); 1682 addToFunctionSummaryMap( 1683 "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}), 1684 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1685 1686 // FILE *fdopen(int fd, const char *mode); 1687 addToFunctionSummaryMap( 1688 "fdopen", 1689 Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}), 1690 Summary(NoEvalCall) 1691 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1692 .ArgConstraint(NotNull(ArgNo(1)))); 1693 1694 // void rewinddir(DIR *dir); 1695 addToFunctionSummaryMap( 1696 "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}), 1697 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1698 1699 // void seekdir(DIR *dirp, long loc); 1700 addToFunctionSummaryMap( 1701 "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}), 1702 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1703 1704 // int rand_r(unsigned int *seedp); 1705 addToFunctionSummaryMap( 1706 "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}), 1707 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1708 1709 // int fileno(FILE *stream); 1710 addToFunctionSummaryMap( 1711 "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1712 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1713 1714 // int fseeko(FILE *stream, off_t offset, int whence); 1715 addToFunctionSummaryMap( 1716 "fseeko", 1717 Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}), 1718 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1719 1720 // off_t ftello(FILE *stream); 1721 addToFunctionSummaryMap( 1722 "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}), 1723 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1724 1725 // void *mmap(void *addr, size_t length, int prot, int flags, int fd, 1726 // off_t offset); 1727 addToFunctionSummaryMap( 1728 "mmap", 1729 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy}, 1730 RetType{VoidPtrTy}), 1731 Summary(NoEvalCall) 1732 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1733 .ArgConstraint( 1734 ArgumentCondition(4, WithinRange, Range(0, IntMax)))); 1735 1736 Optional<QualType> Off64_tTy = lookupTy("off64_t"); 1737 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, 1738 // off64_t offset); 1739 addToFunctionSummaryMap( 1740 "mmap64", 1741 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy}, 1742 RetType{VoidPtrTy}), 1743 Summary(NoEvalCall) 1744 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1745 .ArgConstraint( 1746 ArgumentCondition(4, WithinRange, Range(0, IntMax)))); 1747 1748 // int pipe(int fildes[2]); 1749 addToFunctionSummaryMap( 1750 "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}), 1751 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1752 1753 // off_t lseek(int fildes, off_t offset, int whence); 1754 addToFunctionSummaryMap( 1755 "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}), 1756 Summary(NoEvalCall) 1757 .ArgConstraint( 1758 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1759 1760 // ssize_t readlink(const char *restrict path, char *restrict buf, 1761 // size_t bufsize); 1762 addToFunctionSummaryMap( 1763 "readlink", 1764 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1765 RetType{Ssize_tTy}), 1766 Summary(NoEvalCall) 1767 .ArgConstraint(NotNull(ArgNo(0))) 1768 .ArgConstraint(NotNull(ArgNo(1))) 1769 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1770 /*BufSize=*/ArgNo(2))) 1771 .ArgConstraint( 1772 ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); 1773 1774 // ssize_t readlinkat(int fd, const char *restrict path, 1775 // char *restrict buf, size_t bufsize); 1776 addToFunctionSummaryMap( 1777 "readlinkat", 1778 Signature( 1779 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1780 RetType{Ssize_tTy}), 1781 Summary(NoEvalCall) 1782 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1783 .ArgConstraint(NotNull(ArgNo(1))) 1784 .ArgConstraint(NotNull(ArgNo(2))) 1785 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), 1786 /*BufSize=*/ArgNo(3))) 1787 .ArgConstraint( 1788 ArgumentCondition(3, WithinRange, Range(0, SizeMax)))); 1789 1790 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char 1791 // *newpath); 1792 addToFunctionSummaryMap( 1793 "renameat", 1794 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy}, 1795 RetType{IntTy}), 1796 Summary(NoEvalCall) 1797 .ArgConstraint(NotNull(ArgNo(1))) 1798 .ArgConstraint(NotNull(ArgNo(3)))); 1799 1800 // char *realpath(const char *restrict file_name, 1801 // char *restrict resolved_name); 1802 addToFunctionSummaryMap( 1803 "realpath", 1804 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy}, 1805 RetType{CharPtrTy}), 1806 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1807 1808 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy)); 1809 1810 // int execv(const char *path, char *const argv[]); 1811 addToFunctionSummaryMap( 1812 "execv", 1813 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 1814 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1815 1816 // int execvp(const char *file, char *const argv[]); 1817 addToFunctionSummaryMap( 1818 "execvp", 1819 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 1820 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1821 1822 // int getopt(int argc, char * const argv[], const char *optstring); 1823 addToFunctionSummaryMap( 1824 "getopt", 1825 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy}, 1826 RetType{IntTy}), 1827 Summary(NoEvalCall) 1828 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1829 .ArgConstraint(NotNull(ArgNo(1))) 1830 .ArgConstraint(NotNull(ArgNo(2)))); 1831 1832 Optional<QualType> StructSockaddrTy = lookupTy("sockaddr"); 1833 Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy); 1834 Optional<QualType> ConstStructSockaddrPtrTy = 1835 getPointerTy(getConstTy(StructSockaddrTy)); 1836 Optional<QualType> StructSockaddrPtrRestrictTy = 1837 getRestrictTy(StructSockaddrPtrTy); 1838 Optional<QualType> ConstStructSockaddrPtrRestrictTy = 1839 getRestrictTy(ConstStructSockaddrPtrTy); 1840 Optional<QualType> Socklen_tTy = lookupTy("socklen_t"); 1841 Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy); 1842 Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy); 1843 Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy); 1844 1845 // In 'socket.h' of some libc implementations with C99, sockaddr parameter 1846 // is a transparent union of the underlying sockaddr_ family of pointers 1847 // instead of being a pointer to struct sockaddr. In these cases, the 1848 // standardized signature will not match, thus we try to match with another 1849 // signature that has the joker Irrelevant type. We also remove those 1850 // constraints which require pointer types for the sockaddr param. 1851 auto Accept = 1852 Summary(NoEvalCall) 1853 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))); 1854 if (!addToFunctionSummaryMap( 1855 "accept", 1856 // int accept(int socket, struct sockaddr *restrict address, 1857 // socklen_t *restrict address_len); 1858 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1859 Socklen_tPtrRestrictTy}, 1860 RetType{IntTy}), 1861 Accept)) 1862 addToFunctionSummaryMap( 1863 "accept", 1864 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1865 RetType{IntTy}), 1866 Accept); 1867 1868 // int bind(int socket, const struct sockaddr *address, socklen_t 1869 // address_len); 1870 if (!addToFunctionSummaryMap( 1871 "bind", 1872 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 1873 RetType{IntTy}), 1874 Summary(NoEvalCall) 1875 .ArgConstraint( 1876 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1877 .ArgConstraint(NotNull(ArgNo(1))) 1878 .ArgConstraint( 1879 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2))) 1880 .ArgConstraint( 1881 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))))) 1882 // Do not add constraints on sockaddr. 1883 addToFunctionSummaryMap( 1884 "bind", 1885 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 1886 Summary(NoEvalCall) 1887 .ArgConstraint( 1888 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1889 .ArgConstraint( 1890 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))); 1891 1892 // int getpeername(int socket, struct sockaddr *restrict address, 1893 // socklen_t *restrict address_len); 1894 if (!addToFunctionSummaryMap( 1895 "getpeername", 1896 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1897 Socklen_tPtrRestrictTy}, 1898 RetType{IntTy}), 1899 Summary(NoEvalCall) 1900 .ArgConstraint( 1901 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1902 .ArgConstraint(NotNull(ArgNo(1))) 1903 .ArgConstraint(NotNull(ArgNo(2))))) 1904 addToFunctionSummaryMap( 1905 "getpeername", 1906 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1907 RetType{IntTy}), 1908 Summary(NoEvalCall) 1909 .ArgConstraint( 1910 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1911 1912 // int getsockname(int socket, struct sockaddr *restrict address, 1913 // socklen_t *restrict address_len); 1914 if (!addToFunctionSummaryMap( 1915 "getsockname", 1916 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1917 Socklen_tPtrRestrictTy}, 1918 RetType{IntTy}), 1919 Summary(NoEvalCall) 1920 .ArgConstraint( 1921 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1922 .ArgConstraint(NotNull(ArgNo(1))) 1923 .ArgConstraint(NotNull(ArgNo(2))))) 1924 addToFunctionSummaryMap( 1925 "getsockname", 1926 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1927 RetType{IntTy}), 1928 Summary(NoEvalCall) 1929 .ArgConstraint( 1930 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1931 1932 // int connect(int socket, const struct sockaddr *address, socklen_t 1933 // address_len); 1934 if (!addToFunctionSummaryMap( 1935 "connect", 1936 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 1937 RetType{IntTy}), 1938 Summary(NoEvalCall) 1939 .ArgConstraint( 1940 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1941 .ArgConstraint(NotNull(ArgNo(1))))) 1942 addToFunctionSummaryMap( 1943 "connect", 1944 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 1945 Summary(NoEvalCall) 1946 .ArgConstraint( 1947 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1948 1949 auto Recvfrom = 1950 Summary(NoEvalCall) 1951 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1952 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1953 /*BufSize=*/ArgNo(2))); 1954 if (!addToFunctionSummaryMap( 1955 "recvfrom", 1956 // ssize_t recvfrom(int socket, void *restrict buffer, 1957 // size_t length, 1958 // int flags, struct sockaddr *restrict address, 1959 // socklen_t *restrict address_len); 1960 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 1961 StructSockaddrPtrRestrictTy, 1962 Socklen_tPtrRestrictTy}, 1963 RetType{Ssize_tTy}), 1964 Recvfrom)) 1965 addToFunctionSummaryMap( 1966 "recvfrom", 1967 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 1968 Irrelevant, Socklen_tPtrRestrictTy}, 1969 RetType{Ssize_tTy}), 1970 Recvfrom); 1971 1972 auto Sendto = 1973 Summary(NoEvalCall) 1974 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1975 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1976 /*BufSize=*/ArgNo(2))); 1977 if (!addToFunctionSummaryMap( 1978 "sendto", 1979 // ssize_t sendto(int socket, const void *message, size_t length, 1980 // int flags, const struct sockaddr *dest_addr, 1981 // socklen_t dest_len); 1982 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, 1983 ConstStructSockaddrPtrTy, Socklen_tTy}, 1984 RetType{Ssize_tTy}), 1985 Sendto)) 1986 addToFunctionSummaryMap( 1987 "sendto", 1988 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant, 1989 Socklen_tTy}, 1990 RetType{Ssize_tTy}), 1991 Sendto); 1992 1993 // int listen(int sockfd, int backlog); 1994 addToFunctionSummaryMap("listen", 1995 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 1996 Summary(NoEvalCall) 1997 .ArgConstraint(ArgumentCondition( 1998 0, WithinRange, Range(0, IntMax)))); 1999 2000 // ssize_t recv(int sockfd, void *buf, size_t len, int flags); 2001 addToFunctionSummaryMap( 2002 "recv", 2003 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, 2004 RetType{Ssize_tTy}), 2005 Summary(NoEvalCall) 2006 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2007 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2008 /*BufSize=*/ArgNo(2)))); 2009 2010 Optional<QualType> StructMsghdrTy = lookupTy("msghdr"); 2011 Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy); 2012 Optional<QualType> ConstStructMsghdrPtrTy = 2013 getPointerTy(getConstTy(StructMsghdrTy)); 2014 2015 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 2016 addToFunctionSummaryMap("recvmsg", 2017 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy}, 2018 RetType{Ssize_tTy}), 2019 Summary(NoEvalCall) 2020 .ArgConstraint(ArgumentCondition( 2021 0, WithinRange, Range(0, IntMax)))); 2022 2023 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 2024 addToFunctionSummaryMap( 2025 "sendmsg", 2026 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy}, 2027 RetType{Ssize_tTy}), 2028 Summary(NoEvalCall) 2029 .ArgConstraint( 2030 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2031 2032 // int setsockopt(int socket, int level, int option_name, 2033 // const void *option_value, socklen_t option_len); 2034 addToFunctionSummaryMap( 2035 "setsockopt", 2036 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy}, 2037 RetType{IntTy}), 2038 Summary(NoEvalCall) 2039 .ArgConstraint(NotNull(ArgNo(3))) 2040 .ArgConstraint( 2041 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4))) 2042 .ArgConstraint( 2043 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax)))); 2044 2045 // int getsockopt(int socket, int level, int option_name, 2046 // void *restrict option_value, 2047 // socklen_t *restrict option_len); 2048 addToFunctionSummaryMap( 2049 "getsockopt", 2050 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy, 2051 Socklen_tPtrRestrictTy}, 2052 RetType{IntTy}), 2053 Summary(NoEvalCall) 2054 .ArgConstraint(NotNull(ArgNo(3))) 2055 .ArgConstraint(NotNull(ArgNo(4)))); 2056 2057 // ssize_t send(int sockfd, const void *buf, size_t len, int flags); 2058 addToFunctionSummaryMap( 2059 "send", 2060 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy}, 2061 RetType{Ssize_tTy}), 2062 Summary(NoEvalCall) 2063 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2064 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2065 /*BufSize=*/ArgNo(2)))); 2066 2067 // int socketpair(int domain, int type, int protocol, int sv[2]); 2068 addToFunctionSummaryMap( 2069 "socketpair", 2070 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}), 2071 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(3)))); 2072 2073 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, 2074 // char *restrict node, socklen_t nodelen, 2075 // char *restrict service, 2076 // socklen_t servicelen, int flags); 2077 // 2078 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr 2079 // parameter is never handled as a transparent union in netdb.h 2080 addToFunctionSummaryMap( 2081 "getnameinfo", 2082 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy, 2083 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy, 2084 Socklen_tTy, IntTy}, 2085 RetType{IntTy}), 2086 Summary(NoEvalCall) 2087 .ArgConstraint( 2088 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))) 2089 .ArgConstraint( 2090 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax))) 2091 .ArgConstraint( 2092 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3))) 2093 .ArgConstraint( 2094 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax))) 2095 .ArgConstraint( 2096 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5))) 2097 .ArgConstraint( 2098 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax)))); 2099 2100 Optional<QualType> StructUtimbufTy = lookupTy("utimbuf"); 2101 Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy); 2102 2103 // int utime(const char *filename, struct utimbuf *buf); 2104 addToFunctionSummaryMap( 2105 "utime", 2106 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}), 2107 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2108 2109 Optional<QualType> StructTimespecTy = lookupTy("timespec"); 2110 Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy); 2111 Optional<QualType> ConstStructTimespecPtrTy = 2112 getPointerTy(getConstTy(StructTimespecTy)); 2113 2114 // int futimens(int fd, const struct timespec times[2]); 2115 addToFunctionSummaryMap( 2116 "futimens", 2117 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}), 2118 Summary(NoEvalCall) 2119 .ArgConstraint( 2120 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2121 2122 // int utimensat(int dirfd, const char *pathname, 2123 // const struct timespec times[2], int flags); 2124 addToFunctionSummaryMap( 2125 "utimensat", 2126 Signature( 2127 ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy}, 2128 RetType{IntTy}), 2129 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 2130 2131 Optional<QualType> StructTimevalTy = lookupTy("timeval"); 2132 Optional<QualType> ConstStructTimevalPtrTy = 2133 getPointerTy(getConstTy(StructTimevalTy)); 2134 2135 // int utimes(const char *filename, const struct timeval times[2]); 2136 addToFunctionSummaryMap( 2137 "utimes", 2138 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy}, 2139 RetType{IntTy}), 2140 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2141 2142 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); 2143 addToFunctionSummaryMap( 2144 "nanosleep", 2145 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy}, 2146 RetType{IntTy}), 2147 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2148 2149 Optional<QualType> Time_tTy = lookupTy("time_t"); 2150 Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy)); 2151 Optional<QualType> ConstTime_tPtrRestrictTy = 2152 getRestrictTy(ConstTime_tPtrTy); 2153 2154 Optional<QualType> StructTmTy = lookupTy("tm"); 2155 Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy); 2156 Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy); 2157 Optional<QualType> ConstStructTmPtrTy = 2158 getPointerTy(getConstTy(StructTmTy)); 2159 Optional<QualType> ConstStructTmPtrRestrictTy = 2160 getRestrictTy(ConstStructTmPtrTy); 2161 2162 // struct tm * localtime(const time_t *tp); 2163 addToFunctionSummaryMap( 2164 "localtime", 2165 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 2166 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2167 2168 // struct tm *localtime_r(const time_t *restrict timer, 2169 // struct tm *restrict result); 2170 addToFunctionSummaryMap( 2171 "localtime_r", 2172 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 2173 RetType{StructTmPtrTy}), 2174 Summary(NoEvalCall) 2175 .ArgConstraint(NotNull(ArgNo(0))) 2176 .ArgConstraint(NotNull(ArgNo(1)))); 2177 2178 // char *asctime_r(const struct tm *restrict tm, char *restrict buf); 2179 addToFunctionSummaryMap( 2180 "asctime_r", 2181 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy}, 2182 RetType{CharPtrTy}), 2183 Summary(NoEvalCall) 2184 .ArgConstraint(NotNull(ArgNo(0))) 2185 .ArgConstraint(NotNull(ArgNo(1))) 2186 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2187 /*MinBufSize=*/BVF.getValue(26, IntTy)))); 2188 2189 // char *ctime_r(const time_t *timep, char *buf); 2190 addToFunctionSummaryMap( 2191 "ctime_r", 2192 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}), 2193 Summary(NoEvalCall) 2194 .ArgConstraint(NotNull(ArgNo(0))) 2195 .ArgConstraint(NotNull(ArgNo(1))) 2196 .ArgConstraint(BufferSize( 2197 /*Buffer=*/ArgNo(1), 2198 /*MinBufSize=*/BVF.getValue(26, IntTy)))); 2199 2200 // struct tm *gmtime_r(const time_t *restrict timer, 2201 // struct tm *restrict result); 2202 addToFunctionSummaryMap( 2203 "gmtime_r", 2204 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 2205 RetType{StructTmPtrTy}), 2206 Summary(NoEvalCall) 2207 .ArgConstraint(NotNull(ArgNo(0))) 2208 .ArgConstraint(NotNull(ArgNo(1)))); 2209 2210 // struct tm * gmtime(const time_t *tp); 2211 addToFunctionSummaryMap( 2212 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 2213 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2214 2215 Optional<QualType> Clockid_tTy = lookupTy("clockid_t"); 2216 2217 // int clock_gettime(clockid_t clock_id, struct timespec *tp); 2218 addToFunctionSummaryMap( 2219 "clock_gettime", 2220 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}), 2221 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 2222 2223 Optional<QualType> StructItimervalTy = lookupTy("itimerval"); 2224 Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy); 2225 2226 // int getitimer(int which, struct itimerval *curr_value); 2227 addToFunctionSummaryMap( 2228 "getitimer", 2229 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}), 2230 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 2231 2232 Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t"); 2233 Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy); 2234 Optional<QualType> Pthread_tTy = lookupTy("pthread_t"); 2235 Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy); 2236 Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy); 2237 Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t"); 2238 Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy); 2239 Optional<QualType> Pthread_mutex_tPtrRestrictTy = 2240 getRestrictTy(Pthread_mutex_tPtrTy); 2241 Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t"); 2242 Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy); 2243 Optional<QualType> ConstPthread_attr_tPtrTy = 2244 getPointerTy(getConstTy(Pthread_attr_tTy)); 2245 Optional<QualType> ConstPthread_attr_tPtrRestrictTy = 2246 getRestrictTy(ConstPthread_attr_tPtrTy); 2247 Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t"); 2248 Optional<QualType> ConstPthread_mutexattr_tPtrTy = 2249 getPointerTy(getConstTy(Pthread_mutexattr_tTy)); 2250 Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy = 2251 getRestrictTy(ConstPthread_mutexattr_tPtrTy); 2252 2253 QualType PthreadStartRoutineTy = getPointerTy( 2254 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy, 2255 FunctionProtoType::ExtProtoInfo())); 2256 2257 // int pthread_cond_signal(pthread_cond_t *cond); 2258 // int pthread_cond_broadcast(pthread_cond_t *cond); 2259 addToFunctionSummaryMap( 2260 {"pthread_cond_signal", "pthread_cond_broadcast"}, 2261 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}), 2262 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2263 2264 // int pthread_create(pthread_t *restrict thread, 2265 // const pthread_attr_t *restrict attr, 2266 // void *(*start_routine)(void*), void *restrict arg); 2267 addToFunctionSummaryMap( 2268 "pthread_create", 2269 Signature(ArgTypes{Pthread_tPtrRestrictTy, 2270 ConstPthread_attr_tPtrRestrictTy, 2271 PthreadStartRoutineTy, VoidPtrRestrictTy}, 2272 RetType{IntTy}), 2273 Summary(NoEvalCall) 2274 .ArgConstraint(NotNull(ArgNo(0))) 2275 .ArgConstraint(NotNull(ArgNo(2)))); 2276 2277 // int pthread_attr_destroy(pthread_attr_t *attr); 2278 // int pthread_attr_init(pthread_attr_t *attr); 2279 addToFunctionSummaryMap( 2280 {"pthread_attr_destroy", "pthread_attr_init"}, 2281 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}), 2282 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2283 2284 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, 2285 // size_t *restrict stacksize); 2286 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, 2287 // size_t *restrict guardsize); 2288 addToFunctionSummaryMap( 2289 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"}, 2290 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy}, 2291 RetType{IntTy}), 2292 Summary(NoEvalCall) 2293 .ArgConstraint(NotNull(ArgNo(0))) 2294 .ArgConstraint(NotNull(ArgNo(1)))); 2295 2296 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); 2297 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); 2298 addToFunctionSummaryMap( 2299 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"}, 2300 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}), 2301 Summary(NoEvalCall) 2302 .ArgConstraint(NotNull(ArgNo(0))) 2303 .ArgConstraint( 2304 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 2305 2306 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const 2307 // pthread_mutexattr_t *restrict attr); 2308 addToFunctionSummaryMap( 2309 "pthread_mutex_init", 2310 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy, 2311 ConstPthread_mutexattr_tPtrRestrictTy}, 2312 RetType{IntTy}), 2313 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2314 2315 // int pthread_mutex_destroy(pthread_mutex_t *mutex); 2316 // int pthread_mutex_lock(pthread_mutex_t *mutex); 2317 // int pthread_mutex_trylock(pthread_mutex_t *mutex); 2318 // int pthread_mutex_unlock(pthread_mutex_t *mutex); 2319 addToFunctionSummaryMap( 2320 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock", 2321 "pthread_mutex_unlock"}, 2322 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}), 2323 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2324 } 2325 2326 // Functions for testing. 2327 if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) { 2328 addToFunctionSummaryMap( 2329 "__two_constrained_args", 2330 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 2331 Summary(EvalCallAsPure) 2332 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))) 2333 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1)))); 2334 addToFunctionSummaryMap( 2335 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2336 Summary(EvalCallAsPure) 2337 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))) 2338 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2)))); 2339 addToFunctionSummaryMap( 2340 "__defaultparam", 2341 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}), 2342 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0)))); 2343 addToFunctionSummaryMap( 2344 "__variadic", 2345 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}), 2346 Summary(EvalCallAsPure) 2347 .ArgConstraint(NotNull(ArgNo(0))) 2348 .ArgConstraint(NotNull(ArgNo(1)))); 2349 addToFunctionSummaryMap( 2350 "__buf_size_arg_constraint", 2351 Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}), 2352 Summary(EvalCallAsPure) 2353 .ArgConstraint( 2354 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))); 2355 addToFunctionSummaryMap( 2356 "__buf_size_arg_constraint_mul", 2357 Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}), 2358 Summary(EvalCallAsPure) 2359 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 2360 /*BufSizeMultiplier=*/ArgNo(2)))); 2361 addToFunctionSummaryMap( 2362 "__buf_size_arg_constraint_concrete", 2363 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}), 2364 Summary(EvalCallAsPure) 2365 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), 2366 /*BufSize=*/BVF.getValue(10, IntTy)))); 2367 addToFunctionSummaryMap( 2368 {"__test_restrict_param_0", "__test_restrict_param_1", 2369 "__test_restrict_param_2"}, 2370 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}), 2371 Summary(EvalCallAsPure)); 2372 } 2373 } 2374 2375 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 2376 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>(); 2377 Checker->DisplayLoadedSummaries = 2378 mgr.getAnalyzerOptions().getCheckerBooleanOption( 2379 Checker, "DisplayLoadedSummaries"); 2380 Checker->ModelPOSIX = 2381 mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX"); 2382 } 2383 2384 bool ento::shouldRegisterStdCLibraryFunctionsChecker( 2385 const CheckerManager &mgr) { 2386 return true; 2387 } 2388 2389 #define REGISTER_CHECKER(name) \ 2390 void ento::register##name(CheckerManager &mgr) { \ 2391 StdLibraryFunctionsChecker *checker = \ 2392 mgr.getChecker<StdLibraryFunctionsChecker>(); \ 2393 checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \ 2394 checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \ 2395 mgr.getCurrentCheckerName(); \ 2396 } \ 2397 \ 2398 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 2399 2400 REGISTER_CHECKER(StdCLibraryFunctionArgsChecker) 2401 REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker) 2402