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