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