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