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