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