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