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