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