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