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