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 Preprocessor &PP = C.getPreprocessor(); 1396 1397 // Helper class to lookup a type by its name. 1398 class LookupType { 1399 const ASTContext &ACtx; 1400 1401 public: 1402 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {} 1403 1404 // Find the type. If not found then the optional is not set. 1405 std::optional<QualType> operator()(StringRef Name) { 1406 IdentifierInfo &II = ACtx.Idents.get(Name); 1407 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 1408 if (LookupRes.empty()) 1409 return std::nullopt; 1410 1411 // Prioritze typedef declarations. 1412 // This is needed in case of C struct typedefs. E.g.: 1413 // typedef struct FILE FILE; 1414 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' 1415 // and we have a TypedefDecl with the name 'FILE'. 1416 for (Decl *D : LookupRes) 1417 if (auto *TD = dyn_cast<TypedefNameDecl>(D)) 1418 return ACtx.getTypeDeclType(TD).getCanonicalType(); 1419 1420 // Find the first TypeDecl. 1421 // There maybe cases when a function has the same name as a struct. 1422 // E.g. in POSIX: `struct stat` and the function `stat()`: 1423 // int stat(const char *restrict path, struct stat *restrict buf); 1424 for (Decl *D : LookupRes) 1425 if (auto *TD = dyn_cast<TypeDecl>(D)) 1426 return ACtx.getTypeDeclType(TD).getCanonicalType(); 1427 return std::nullopt; 1428 } 1429 } lookupTy(ACtx); 1430 1431 // Below are auxiliary classes to handle optional types that we get as a 1432 // result of the lookup. 1433 class GetRestrictTy { 1434 const ASTContext &ACtx; 1435 1436 public: 1437 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {} 1438 QualType operator()(QualType Ty) { 1439 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty; 1440 } 1441 std::optional<QualType> operator()(std::optional<QualType> Ty) { 1442 if (Ty) 1443 return operator()(*Ty); 1444 return std::nullopt; 1445 } 1446 } getRestrictTy(ACtx); 1447 class GetPointerTy { 1448 const ASTContext &ACtx; 1449 1450 public: 1451 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {} 1452 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); } 1453 std::optional<QualType> operator()(std::optional<QualType> Ty) { 1454 if (Ty) 1455 return operator()(*Ty); 1456 return std::nullopt; 1457 } 1458 } getPointerTy(ACtx); 1459 class { 1460 public: 1461 std::optional<QualType> operator()(std::optional<QualType> Ty) { 1462 return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt; 1463 } 1464 QualType operator()(QualType Ty) { return Ty.withConst(); } 1465 } getConstTy; 1466 class GetMaxValue { 1467 BasicValueFactory &BVF; 1468 1469 public: 1470 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {} 1471 std::optional<RangeInt> operator()(QualType Ty) { 1472 return BVF.getMaxValue(Ty).getLimitedValue(); 1473 } 1474 std::optional<RangeInt> operator()(std::optional<QualType> Ty) { 1475 if (Ty) { 1476 return operator()(*Ty); 1477 } 1478 return std::nullopt; 1479 } 1480 } getMaxValue(BVF); 1481 1482 // These types are useful for writing specifications quickly, 1483 // New specifications should probably introduce more types. 1484 // Some types are hard to obtain from the AST, eg. "ssize_t". 1485 // In such cases it should be possible to provide multiple variants 1486 // of function summary for common cases (eg. ssize_t could be int or long 1487 // or long long, so three summary variants would be enough). 1488 // Of course, function variants are also useful for C++ overloads. 1489 const QualType VoidTy = ACtx.VoidTy; 1490 const QualType CharTy = ACtx.CharTy; 1491 const QualType WCharTy = ACtx.WCharTy; 1492 const QualType IntTy = ACtx.IntTy; 1493 const QualType UnsignedIntTy = ACtx.UnsignedIntTy; 1494 const QualType LongTy = ACtx.LongTy; 1495 const QualType SizeTy = ACtx.getSizeType(); 1496 1497 const QualType VoidPtrTy = getPointerTy(VoidTy); // void * 1498 const QualType IntPtrTy = getPointerTy(IntTy); // int * 1499 const QualType UnsignedIntPtrTy = 1500 getPointerTy(UnsignedIntTy); // unsigned int * 1501 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy); 1502 const QualType ConstVoidPtrTy = 1503 getPointerTy(getConstTy(VoidTy)); // const void * 1504 const QualType CharPtrTy = getPointerTy(CharTy); // char * 1505 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy); 1506 const QualType ConstCharPtrTy = 1507 getPointerTy(getConstTy(CharTy)); // const char * 1508 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy); 1509 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t * 1510 const QualType ConstWchar_tPtrTy = 1511 getPointerTy(getConstTy(WCharTy)); // const wchar_t * 1512 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy); 1513 const QualType SizePtrTy = getPointerTy(SizeTy); 1514 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy); 1515 1516 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 1517 const RangeInt UnsignedIntMax = 1518 BVF.getMaxValue(UnsignedIntTy).getLimitedValue(); 1519 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 1520 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue(); 1521 1522 // Set UCharRangeMax to min of int or uchar maximum value. 1523 // The C standard states that the arguments of functions like isalpha must 1524 // be representable as an unsigned char. Their type is 'int', so the max 1525 // value of the argument should be min(UCharMax, IntMax). This just happen 1526 // to be true for commonly used and well tested instruction set 1527 // architectures, but not for others. 1528 const RangeInt UCharRangeMax = 1529 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax); 1530 1531 // Get platform dependent values of some macros. 1532 // Try our best to parse this from the Preprocessor, otherwise fallback to a 1533 // default value (what is found in a library header). 1534 const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1); 1535 const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100); 1536 1537 // Auxiliary class to aid adding summaries to the summary map. 1538 struct AddToFunctionSummaryMap { 1539 const ASTContext &ACtx; 1540 FunctionSummaryMapType ⤅ 1541 bool DisplayLoadedSummaries; 1542 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM, 1543 bool DisplayLoadedSummaries) 1544 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) { 1545 } 1546 1547 // Add a summary to a FunctionDecl found by lookup. The lookup is performed 1548 // by the given Name, and in the global scope. The summary will be attached 1549 // to the found FunctionDecl only if the signatures match. 1550 // 1551 // Returns true if the summary has been added, false otherwise. 1552 bool operator()(StringRef Name, Signature Sign, Summary Sum) { 1553 if (Sign.isInvalid()) 1554 return false; 1555 IdentifierInfo &II = ACtx.Idents.get(Name); 1556 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 1557 if (LookupRes.empty()) 1558 return false; 1559 for (Decl *D : LookupRes) { 1560 if (auto *FD = dyn_cast<FunctionDecl>(D)) { 1561 if (Sum.matchesAndSet(Sign, FD)) { 1562 auto Res = Map.insert({FD->getCanonicalDecl(), Sum}); 1563 assert(Res.second && "Function already has a summary set!"); 1564 (void)Res; 1565 if (DisplayLoadedSummaries) { 1566 llvm::errs() << "Loaded summary for: "; 1567 FD->print(llvm::errs()); 1568 llvm::errs() << "\n"; 1569 } 1570 return true; 1571 } 1572 } 1573 } 1574 return false; 1575 } 1576 // Add the same summary for different names with the Signature explicitly 1577 // given. 1578 void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) { 1579 for (StringRef Name : Names) 1580 operator()(Name, Sign, Sum); 1581 } 1582 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries); 1583 1584 // Below are helpers functions to create the summaries. 1585 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges, 1586 StringRef Desc = "") { 1587 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc); 1588 }; 1589 auto BufferSize = [](auto... Args) { 1590 return std::make_shared<BufferSizeConstraint>(Args...); 1591 }; 1592 struct { 1593 auto operator()(RangeKind Kind, IntRangeVector Ranges) { 1594 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges); 1595 } 1596 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) { 1597 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN); 1598 } 1599 } ReturnValueCondition; 1600 struct { 1601 auto operator()(RangeInt b, RangeInt e) { 1602 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}}; 1603 } 1604 auto operator()(RangeInt b, std::optional<RangeInt> e) { 1605 if (e) 1606 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}}; 1607 return IntRangeVector{}; 1608 } 1609 auto operator()(std::pair<RangeInt, RangeInt> i0, 1610 std::pair<RangeInt, std::optional<RangeInt>> i1) { 1611 if (i1.second) 1612 return IntRangeVector{i0, {i1.first, *(i1.second)}}; 1613 return IntRangeVector{i0}; 1614 } 1615 } Range; 1616 auto SingleValue = [](RangeInt v) { 1617 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}}; 1618 }; 1619 auto LessThanOrEq = BO_LE; 1620 auto NotNull = [&](ArgNo ArgN) { 1621 return std::make_shared<NotNullConstraint>(ArgN); 1622 }; 1623 auto IsNull = [&](ArgNo ArgN) { 1624 return std::make_shared<NotNullConstraint>(ArgN, false); 1625 }; 1626 1627 std::optional<QualType> FileTy = lookupTy("FILE"); 1628 std::optional<QualType> FilePtrTy = getPointerTy(FileTy); 1629 std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy); 1630 1631 std::optional<QualType> FPosTTy = lookupTy("fpos_t"); 1632 std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy); 1633 std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy)); 1634 std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy); 1635 1636 // We are finally ready to define specifications for all supported functions. 1637 // 1638 // Argument ranges should always cover all variants. If return value 1639 // is completely unknown, omit it from the respective range set. 1640 // 1641 // Every item in the list of range sets represents a particular 1642 // execution path the analyzer would need to explore once 1643 // the call is modeled - a new program state is constructed 1644 // for every range set, and each range line in the range set 1645 // corresponds to a specific constraint within this state. 1646 1647 // The isascii() family of functions. 1648 // The behavior is undefined if the value of the argument is not 1649 // representable as unsigned char or is not equal to EOF. See e.g. C99 1650 // 7.4.1.2 The isalpha function (p: 181-182). 1651 addToFunctionSummaryMap( 1652 "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1653 Summary(EvalCallAsPure) 1654 // Boils down to isupper() or islower() or isdigit(). 1655 .Case({ArgumentCondition(0U, WithinRange, 1656 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}), 1657 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1658 ErrnoIrrelevant, "Assuming the character is alphanumeric") 1659 // The locale-specific range. 1660 // No post-condition. We are completely unaware of 1661 // locale-specific return values. 1662 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}, 1663 ErrnoIrrelevant) 1664 .Case( 1665 {ArgumentCondition( 1666 0U, OutOfRange, 1667 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1668 ReturnValueCondition(WithinRange, SingleValue(0))}, 1669 ErrnoIrrelevant, "Assuming the character is non-alphanumeric") 1670 .ArgConstraint(ArgumentCondition(0U, WithinRange, 1671 {{EOFv, EOFv}, {0, UCharRangeMax}}, 1672 "an unsigned char value or EOF"))); 1673 addToFunctionSummaryMap( 1674 "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1675 Summary(EvalCallAsPure) 1676 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}), 1677 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1678 ErrnoIrrelevant, "Assuming the character is alphabetical") 1679 // The locale-specific range. 1680 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}, 1681 ErrnoIrrelevant) 1682 .Case({ArgumentCondition( 1683 0U, OutOfRange, 1684 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1685 ReturnValueCondition(WithinRange, SingleValue(0))}, 1686 ErrnoIrrelevant, "Assuming the character is non-alphabetical")); 1687 addToFunctionSummaryMap( 1688 "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1689 Summary(EvalCallAsPure) 1690 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1691 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1692 ErrnoIrrelevant, "Assuming the character is an ASCII character") 1693 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)), 1694 ReturnValueCondition(WithinRange, SingleValue(0))}, 1695 ErrnoIrrelevant, 1696 "Assuming the character is not an ASCII character")); 1697 addToFunctionSummaryMap( 1698 "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1699 Summary(EvalCallAsPure) 1700 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}), 1701 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1702 ErrnoIrrelevant, "Assuming the character is a blank character") 1703 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}), 1704 ReturnValueCondition(WithinRange, SingleValue(0))}, 1705 ErrnoIrrelevant, 1706 "Assuming the character is not a blank character")); 1707 addToFunctionSummaryMap( 1708 "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1709 Summary(EvalCallAsPure) 1710 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}), 1711 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1712 ErrnoIrrelevant, 1713 "Assuming the character is a control character") 1714 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}), 1715 ReturnValueCondition(WithinRange, SingleValue(0))}, 1716 ErrnoIrrelevant, 1717 "Assuming the character is not a control character")); 1718 addToFunctionSummaryMap( 1719 "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1720 Summary(EvalCallAsPure) 1721 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')), 1722 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1723 ErrnoIrrelevant, "Assuming the character is a digit") 1724 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')), 1725 ReturnValueCondition(WithinRange, SingleValue(0))}, 1726 ErrnoIrrelevant, "Assuming the character is not a digit")); 1727 addToFunctionSummaryMap( 1728 "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1729 Summary(EvalCallAsPure) 1730 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)), 1731 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1732 ErrnoIrrelevant, 1733 "Assuming the character has graphical representation") 1734 .Case( 1735 {ArgumentCondition(0U, OutOfRange, Range(33, 126)), 1736 ReturnValueCondition(WithinRange, SingleValue(0))}, 1737 ErrnoIrrelevant, 1738 "Assuming the character does not have graphical representation")); 1739 addToFunctionSummaryMap( 1740 "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1741 Summary(EvalCallAsPure) 1742 // Is certainly lowercase. 1743 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')), 1744 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1745 ErrnoIrrelevant, "Assuming the character is a lowercase letter") 1746 // Is ascii but not lowercase. 1747 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1748 ArgumentCondition(0U, OutOfRange, Range('a', 'z')), 1749 ReturnValueCondition(WithinRange, SingleValue(0))}, 1750 ErrnoIrrelevant, 1751 "Assuming the character is not a lowercase letter") 1752 // The locale-specific range. 1753 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}, 1754 ErrnoIrrelevant) 1755 // Is not an unsigned char. 1756 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)), 1757 ReturnValueCondition(WithinRange, SingleValue(0))}, 1758 ErrnoIrrelevant)); 1759 addToFunctionSummaryMap( 1760 "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1761 Summary(EvalCallAsPure) 1762 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)), 1763 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1764 ErrnoIrrelevant, "Assuming the character is printable") 1765 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)), 1766 ReturnValueCondition(WithinRange, SingleValue(0))}, 1767 ErrnoIrrelevant, "Assuming the character is non-printable")); 1768 addToFunctionSummaryMap( 1769 "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1770 Summary(EvalCallAsPure) 1771 .Case({ArgumentCondition( 1772 0U, WithinRange, 1773 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1774 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1775 ErrnoIrrelevant, "Assuming the character is a punctuation mark") 1776 .Case({ArgumentCondition( 1777 0U, OutOfRange, 1778 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1779 ReturnValueCondition(WithinRange, SingleValue(0))}, 1780 ErrnoIrrelevant, 1781 "Assuming the character is not a punctuation mark")); 1782 addToFunctionSummaryMap( 1783 "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1784 Summary(EvalCallAsPure) 1785 // Space, '\f', '\n', '\r', '\t', '\v'. 1786 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}), 1787 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1788 ErrnoIrrelevant, 1789 "Assuming the character is a whitespace character") 1790 // The locale-specific range. 1791 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}, 1792 ErrnoIrrelevant) 1793 .Case({ArgumentCondition(0U, OutOfRange, 1794 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}), 1795 ReturnValueCondition(WithinRange, SingleValue(0))}, 1796 ErrnoIrrelevant, 1797 "Assuming the character is not a whitespace character")); 1798 addToFunctionSummaryMap( 1799 "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1800 Summary(EvalCallAsPure) 1801 // Is certainly uppercase. 1802 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')), 1803 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1804 ErrnoIrrelevant, 1805 "Assuming the character is an uppercase letter") 1806 // The locale-specific range. 1807 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}, 1808 ErrnoIrrelevant) 1809 // Other. 1810 .Case({ArgumentCondition(0U, OutOfRange, 1811 {{'A', 'Z'}, {128, UCharRangeMax}}), 1812 ReturnValueCondition(WithinRange, SingleValue(0))}, 1813 ErrnoIrrelevant, 1814 "Assuming the character is not an uppercase letter")); 1815 addToFunctionSummaryMap( 1816 "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1817 Summary(EvalCallAsPure) 1818 .Case({ArgumentCondition(0U, WithinRange, 1819 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1820 ReturnValueCondition(OutOfRange, SingleValue(0))}, 1821 ErrnoIrrelevant, 1822 "Assuming the character is a hexadecimal digit") 1823 .Case({ArgumentCondition(0U, OutOfRange, 1824 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1825 ReturnValueCondition(WithinRange, SingleValue(0))}, 1826 ErrnoIrrelevant, 1827 "Assuming the character is not a hexadecimal digit")); 1828 addToFunctionSummaryMap( 1829 "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1830 Summary(EvalCallAsPure) 1831 .ArgConstraint(ArgumentCondition(0U, WithinRange, 1832 {{EOFv, EOFv}, {0, UCharRangeMax}}, 1833 "an unsigned char value or EOF"))); 1834 addToFunctionSummaryMap( 1835 "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1836 Summary(EvalCallAsPure) 1837 .ArgConstraint(ArgumentCondition(0U, WithinRange, 1838 {{EOFv, EOFv}, {0, UCharRangeMax}}, 1839 "an unsigned char value or EOF"))); 1840 addToFunctionSummaryMap( 1841 "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1842 Summary(EvalCallAsPure) 1843 .ArgConstraint(ArgumentCondition(0U, WithinRange, 1844 {{EOFv, EOFv}, {0, UCharRangeMax}}, 1845 "an unsigned char value or EOF"))); 1846 1847 // The getc() family of functions that returns either a char or an EOF. 1848 addToFunctionSummaryMap( 1849 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1850 Summary(NoEvalCall) 1851 .Case({ReturnValueCondition(WithinRange, 1852 {{EOFv, EOFv}, {0, UCharRangeMax}})}, 1853 ErrnoIrrelevant)); 1854 addToFunctionSummaryMap( 1855 "getchar", Signature(ArgTypes{}, RetType{IntTy}), 1856 Summary(NoEvalCall) 1857 .Case({ReturnValueCondition(WithinRange, 1858 {{EOFv, EOFv}, {0, UCharRangeMax}})}, 1859 ErrnoIrrelevant)); 1860 1861 // read()-like functions that never return more than buffer size. 1862 auto FreadSummary = 1863 Summary(NoEvalCall) 1864 .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)), 1865 ArgumentCondition(2U, WithinRange, Range(1, SizeMax)), 1866 ReturnValueCondition(BO_LT, ArgNo(2)), 1867 ReturnValueCondition(WithinRange, Range(0, SizeMax))}, 1868 ErrnoNEZeroIrrelevant) 1869 .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)), 1870 ReturnValueCondition(BO_EQ, ArgNo(2)), 1871 ReturnValueCondition(WithinRange, Range(0, SizeMax))}, 1872 ErrnoMustNotBeChecked) 1873 .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)), 1874 ReturnValueCondition(WithinRange, SingleValue(0))}, 1875 ErrnoMustNotBeChecked) 1876 .ArgConstraint(NotNull(ArgNo(0))) 1877 .ArgConstraint(NotNull(ArgNo(3))) 1878 // FIXME: It should be allowed to have a null buffer if any of 1879 // args 1 or 2 are zero. Remove NotNull check of arg 0, add a check 1880 // for non-null buffer if non-zero size to BufferSizeConstraint? 1881 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 1882 /*BufSizeMultiplier=*/ArgNo(2))); 1883 1884 // size_t fread(void *restrict ptr, size_t size, size_t nitems, 1885 // FILE *restrict stream); 1886 addToFunctionSummaryMap( 1887 "fread", 1888 Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy}, 1889 RetType{SizeTy}), 1890 FreadSummary); 1891 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, 1892 // FILE *restrict stream); 1893 addToFunctionSummaryMap("fwrite", 1894 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, 1895 SizeTy, FilePtrRestrictTy}, 1896 RetType{SizeTy}), 1897 FreadSummary); 1898 1899 std::optional<QualType> Ssize_tTy = lookupTy("ssize_t"); 1900 std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy); 1901 1902 auto ReadSummary = 1903 Summary(NoEvalCall) 1904 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1905 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}, 1906 ErrnoIrrelevant); 1907 1908 // FIXME these are actually defined by POSIX and not by the C standard, we 1909 // should handle them together with the rest of the POSIX functions. 1910 // ssize_t read(int fildes, void *buf, size_t nbyte); 1911 addToFunctionSummaryMap( 1912 "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}), 1913 ReadSummary); 1914 // ssize_t write(int fildes, const void *buf, size_t nbyte); 1915 addToFunctionSummaryMap( 1916 "write", 1917 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}), 1918 ReadSummary); 1919 1920 auto GetLineSummary = 1921 Summary(NoEvalCall) 1922 .Case({ReturnValueCondition(WithinRange, 1923 Range({-1, -1}, {1, Ssize_tMax}))}, 1924 ErrnoIrrelevant); 1925 1926 QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy)); 1927 1928 // getline()-like functions either fail or read at least the delimiter. 1929 // FIXME these are actually defined by POSIX and not by the C standard, we 1930 // should handle them together with the rest of the POSIX functions. 1931 // ssize_t getline(char **restrict lineptr, size_t *restrict n, 1932 // FILE *restrict stream); 1933 addToFunctionSummaryMap( 1934 "getline", 1935 Signature( 1936 ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy}, 1937 RetType{Ssize_tTy}), 1938 GetLineSummary); 1939 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n, 1940 // int delimiter, FILE *restrict stream); 1941 addToFunctionSummaryMap( 1942 "getdelim", 1943 Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy, 1944 FilePtrRestrictTy}, 1945 RetType{Ssize_tTy}), 1946 GetLineSummary); 1947 1948 { 1949 Summary GetenvSummary = 1950 Summary(NoEvalCall) 1951 .ArgConstraint(NotNull(ArgNo(0))) 1952 .Case({NotNull(Ret)}, ErrnoIrrelevant, 1953 "Assuming the environment variable exists"); 1954 // In untrusted environments the envvar might not exist. 1955 if (!ShouldAssumeControlledEnvironment) 1956 GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant, 1957 "Assuming the environment variable does not exist"); 1958 1959 // char *getenv(const char *name); 1960 addToFunctionSummaryMap( 1961 "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}), 1962 std::move(GetenvSummary)); 1963 } 1964 1965 if (ModelPOSIX) { 1966 const auto ReturnsZeroOrMinusOne = 1967 ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))}; 1968 const auto ReturnsZero = 1969 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))}; 1970 const auto ReturnsMinusOne = 1971 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))}; 1972 const auto ReturnsNonnegative = 1973 ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))}; 1974 const auto ReturnsNonZero = 1975 ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))}; 1976 const auto ReturnsFileDescriptor = 1977 ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))}; 1978 const auto &ReturnsValidFileDescriptor = ReturnsNonnegative; 1979 1980 auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) { 1981 return std::make_shared<RangeConstraint>( 1982 ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}), 1983 "a valid file descriptor or AT_FDCWD"); 1984 }; 1985 1986 // FILE *fopen(const char *restrict pathname, const char *restrict mode); 1987 addToFunctionSummaryMap( 1988 "fopen", 1989 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy}, 1990 RetType{FilePtrTy}), 1991 Summary(NoEvalCall) 1992 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked) 1993 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant) 1994 .ArgConstraint(NotNull(ArgNo(0))) 1995 .ArgConstraint(NotNull(ArgNo(1)))); 1996 1997 // FILE *tmpfile(void); 1998 addToFunctionSummaryMap("tmpfile", 1999 Signature(ArgTypes{}, RetType{FilePtrTy}), 2000 Summary(NoEvalCall) 2001 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked) 2002 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant)); 2003 2004 // FILE *freopen(const char *restrict pathname, const char *restrict mode, 2005 // FILE *restrict stream); 2006 addToFunctionSummaryMap( 2007 "freopen", 2008 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy, 2009 FilePtrRestrictTy}, 2010 RetType{FilePtrTy}), 2011 Summary(NoEvalCall) 2012 .Case({ReturnValueCondition(BO_EQ, ArgNo(2))}, 2013 ErrnoMustNotBeChecked) 2014 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant) 2015 .ArgConstraint(NotNull(ArgNo(1))) 2016 .ArgConstraint(NotNull(ArgNo(2)))); 2017 2018 // int fclose(FILE *stream); 2019 addToFunctionSummaryMap( 2020 "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 2021 Summary(NoEvalCall) 2022 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2023 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))}, 2024 ErrnoNEZeroIrrelevant) 2025 .ArgConstraint(NotNull(ArgNo(0)))); 2026 2027 // int fseek(FILE *stream, long offset, int whence); 2028 // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use 2029 // these for condition of arg 2. 2030 // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2). 2031 addToFunctionSummaryMap( 2032 "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}), 2033 Summary(NoEvalCall) 2034 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2035 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2036 .ArgConstraint(NotNull(ArgNo(0))) 2037 .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}}))); 2038 2039 // int fgetpos(FILE *restrict stream, fpos_t *restrict pos); 2040 // From 'The Open Group Base Specifications Issue 7, 2018 edition': 2041 // "The fgetpos() function shall not change the setting of errno if 2042 // successful." 2043 addToFunctionSummaryMap( 2044 "fgetpos", 2045 Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy}, 2046 RetType{IntTy}), 2047 Summary(NoEvalCall) 2048 .Case(ReturnsZero, ErrnoUnchanged) 2049 .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant) 2050 .ArgConstraint(NotNull(ArgNo(0))) 2051 .ArgConstraint(NotNull(ArgNo(1)))); 2052 2053 // int fsetpos(FILE *stream, const fpos_t *pos); 2054 // From 'The Open Group Base Specifications Issue 7, 2018 edition': 2055 // "The fsetpos() function shall not change the setting of errno if 2056 // successful." 2057 addToFunctionSummaryMap( 2058 "fsetpos", 2059 Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}), 2060 Summary(NoEvalCall) 2061 .Case(ReturnsZero, ErrnoUnchanged) 2062 .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant) 2063 .ArgConstraint(NotNull(ArgNo(0))) 2064 .ArgConstraint(NotNull(ArgNo(1)))); 2065 2066 // long ftell(FILE *stream); 2067 // From 'The Open Group Base Specifications Issue 7, 2018 edition': 2068 // "The ftell() function shall not change the setting of errno if 2069 // successful." 2070 addToFunctionSummaryMap( 2071 "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}), 2072 Summary(NoEvalCall) 2073 .Case({ReturnValueCondition(WithinRange, Range(1, LongMax))}, 2074 ErrnoUnchanged) 2075 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2076 .ArgConstraint(NotNull(ArgNo(0)))); 2077 2078 // int fileno(FILE *stream); 2079 addToFunctionSummaryMap( 2080 "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 2081 Summary(NoEvalCall) 2082 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked) 2083 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2084 .ArgConstraint(NotNull(ArgNo(0)))); 2085 2086 // void rewind(FILE *stream); 2087 // This function indicates error only by setting of 'errno'. 2088 addToFunctionSummaryMap("rewind", 2089 Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}), 2090 Summary(NoEvalCall) 2091 .Case({}, ErrnoMustBeChecked) 2092 .ArgConstraint(NotNull(ArgNo(0)))); 2093 2094 // void clearerr(FILE *stream); 2095 addToFunctionSummaryMap( 2096 "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}), 2097 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2098 2099 // int feof(FILE *stream); 2100 addToFunctionSummaryMap( 2101 "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 2102 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2103 2104 // int ferror(FILE *stream); 2105 addToFunctionSummaryMap( 2106 "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 2107 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2108 2109 // long a64l(const char *str64); 2110 addToFunctionSummaryMap( 2111 "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}), 2112 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2113 2114 // char *l64a(long value); 2115 addToFunctionSummaryMap("l64a", 2116 Signature(ArgTypes{LongTy}, RetType{CharPtrTy}), 2117 Summary(NoEvalCall) 2118 .ArgConstraint(ArgumentCondition( 2119 0, WithinRange, Range(0, LongMax)))); 2120 2121 // int access(const char *pathname, int amode); 2122 addToFunctionSummaryMap( 2123 "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}), 2124 Summary(NoEvalCall) 2125 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2126 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2127 .ArgConstraint(NotNull(ArgNo(0)))); 2128 2129 // int faccessat(int dirfd, const char *pathname, int mode, int flags); 2130 addToFunctionSummaryMap( 2131 "faccessat", 2132 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy}, 2133 RetType{IntTy}), 2134 Summary(NoEvalCall) 2135 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2136 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2137 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2138 .ArgConstraint(NotNull(ArgNo(1)))); 2139 2140 // int dup(int fildes); 2141 addToFunctionSummaryMap( 2142 "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2143 Summary(NoEvalCall) 2144 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked) 2145 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2146 .ArgConstraint( 2147 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2148 2149 // int dup2(int fildes1, int filedes2); 2150 addToFunctionSummaryMap( 2151 "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 2152 Summary(NoEvalCall) 2153 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked) 2154 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2155 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2156 .ArgConstraint( 2157 ArgumentCondition(1, WithinRange, Range(0, IntMax)))); 2158 2159 // int fdatasync(int fildes); 2160 addToFunctionSummaryMap("fdatasync", 2161 Signature(ArgTypes{IntTy}, RetType{IntTy}), 2162 Summary(NoEvalCall) 2163 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2164 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2165 .ArgConstraint(ArgumentCondition( 2166 0, WithinRange, Range(0, IntMax)))); 2167 2168 // int fnmatch(const char *pattern, const char *string, int flags); 2169 addToFunctionSummaryMap( 2170 "fnmatch", 2171 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy}, 2172 RetType{IntTy}), 2173 Summary(NoEvalCall) 2174 .ArgConstraint(NotNull(ArgNo(0))) 2175 .ArgConstraint(NotNull(ArgNo(1)))); 2176 2177 // int fsync(int fildes); 2178 addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2179 Summary(NoEvalCall) 2180 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2181 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2182 .ArgConstraint(ArgumentCondition( 2183 0, WithinRange, Range(0, IntMax)))); 2184 2185 std::optional<QualType> Off_tTy = lookupTy("off_t"); 2186 2187 // int truncate(const char *path, off_t length); 2188 addToFunctionSummaryMap( 2189 "truncate", 2190 Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}), 2191 Summary(NoEvalCall) 2192 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2193 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2194 .ArgConstraint(NotNull(ArgNo(0)))); 2195 2196 // int symlink(const char *oldpath, const char *newpath); 2197 addToFunctionSummaryMap( 2198 "symlink", 2199 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}), 2200 Summary(NoEvalCall) 2201 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2202 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2203 .ArgConstraint(NotNull(ArgNo(0))) 2204 .ArgConstraint(NotNull(ArgNo(1)))); 2205 2206 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath); 2207 addToFunctionSummaryMap( 2208 "symlinkat", 2209 Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, 2210 RetType{IntTy}), 2211 Summary(NoEvalCall) 2212 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2213 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2214 .ArgConstraint(NotNull(ArgNo(0))) 2215 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1))) 2216 .ArgConstraint(NotNull(ArgNo(2)))); 2217 2218 // int lockf(int fd, int cmd, off_t len); 2219 addToFunctionSummaryMap( 2220 "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}), 2221 Summary(NoEvalCall) 2222 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2223 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2224 .ArgConstraint( 2225 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2226 2227 std::optional<QualType> Mode_tTy = lookupTy("mode_t"); 2228 2229 // int creat(const char *pathname, mode_t mode); 2230 addToFunctionSummaryMap( 2231 "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 2232 Summary(NoEvalCall) 2233 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked) 2234 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2235 .ArgConstraint(NotNull(ArgNo(0)))); 2236 2237 // unsigned int sleep(unsigned int seconds); 2238 addToFunctionSummaryMap( 2239 "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}), 2240 Summary(NoEvalCall) 2241 .ArgConstraint( 2242 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 2243 2244 std::optional<QualType> DirTy = lookupTy("DIR"); 2245 std::optional<QualType> DirPtrTy = getPointerTy(DirTy); 2246 2247 // int dirfd(DIR *dirp); 2248 addToFunctionSummaryMap( 2249 "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}), 2250 Summary(NoEvalCall) 2251 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked) 2252 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2253 .ArgConstraint(NotNull(ArgNo(0)))); 2254 2255 // unsigned int alarm(unsigned int seconds); 2256 addToFunctionSummaryMap( 2257 "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}), 2258 Summary(NoEvalCall) 2259 .ArgConstraint( 2260 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 2261 2262 // int closedir(DIR *dir); 2263 addToFunctionSummaryMap("closedir", 2264 Signature(ArgTypes{DirPtrTy}, RetType{IntTy}), 2265 Summary(NoEvalCall) 2266 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2267 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2268 .ArgConstraint(NotNull(ArgNo(0)))); 2269 2270 // char *strdup(const char *s); 2271 addToFunctionSummaryMap( 2272 "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}), 2273 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2274 2275 // char *strndup(const char *s, size_t n); 2276 addToFunctionSummaryMap( 2277 "strndup", 2278 Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}), 2279 Summary(NoEvalCall) 2280 .ArgConstraint(NotNull(ArgNo(0))) 2281 .ArgConstraint( 2282 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 2283 2284 // wchar_t *wcsdup(const wchar_t *s); 2285 addToFunctionSummaryMap( 2286 "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}), 2287 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2288 2289 // int mkstemp(char *template); 2290 addToFunctionSummaryMap( 2291 "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}), 2292 Summary(NoEvalCall) 2293 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked) 2294 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2295 .ArgConstraint(NotNull(ArgNo(0)))); 2296 2297 // char *mkdtemp(char *template); 2298 // FIXME: Improve for errno modeling. 2299 addToFunctionSummaryMap( 2300 "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}), 2301 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2302 2303 // char *getcwd(char *buf, size_t size); 2304 // FIXME: Improve for errno modeling. 2305 addToFunctionSummaryMap( 2306 "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}), 2307 Summary(NoEvalCall) 2308 .ArgConstraint( 2309 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 2310 2311 // int mkdir(const char *pathname, mode_t mode); 2312 addToFunctionSummaryMap( 2313 "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 2314 Summary(NoEvalCall) 2315 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2316 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2317 .ArgConstraint(NotNull(ArgNo(0)))); 2318 2319 // int mkdirat(int dirfd, const char *pathname, mode_t mode); 2320 addToFunctionSummaryMap( 2321 "mkdirat", 2322 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 2323 Summary(NoEvalCall) 2324 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2325 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2326 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2327 .ArgConstraint(NotNull(ArgNo(1)))); 2328 2329 std::optional<QualType> Dev_tTy = lookupTy("dev_t"); 2330 2331 // int mknod(const char *pathname, mode_t mode, dev_t dev); 2332 addToFunctionSummaryMap( 2333 "mknod", 2334 Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}), 2335 Summary(NoEvalCall) 2336 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2337 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2338 .ArgConstraint(NotNull(ArgNo(0)))); 2339 2340 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); 2341 addToFunctionSummaryMap( 2342 "mknodat", 2343 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy}, 2344 RetType{IntTy}), 2345 Summary(NoEvalCall) 2346 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2347 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2348 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2349 .ArgConstraint(NotNull(ArgNo(1)))); 2350 2351 // int chmod(const char *path, mode_t mode); 2352 addToFunctionSummaryMap( 2353 "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 2354 Summary(NoEvalCall) 2355 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2356 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2357 .ArgConstraint(NotNull(ArgNo(0)))); 2358 2359 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); 2360 addToFunctionSummaryMap( 2361 "fchmodat", 2362 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy}, 2363 RetType{IntTy}), 2364 Summary(NoEvalCall) 2365 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2366 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2367 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2368 .ArgConstraint(NotNull(ArgNo(1)))); 2369 2370 // int fchmod(int fildes, mode_t mode); 2371 addToFunctionSummaryMap( 2372 "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}), 2373 Summary(NoEvalCall) 2374 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2375 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2376 .ArgConstraint( 2377 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2378 2379 std::optional<QualType> Uid_tTy = lookupTy("uid_t"); 2380 std::optional<QualType> Gid_tTy = lookupTy("gid_t"); 2381 2382 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, 2383 // int flags); 2384 addToFunctionSummaryMap( 2385 "fchownat", 2386 Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy}, 2387 RetType{IntTy}), 2388 Summary(NoEvalCall) 2389 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2390 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2391 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2392 .ArgConstraint(NotNull(ArgNo(1)))); 2393 2394 // int chown(const char *path, uid_t owner, gid_t group); 2395 addToFunctionSummaryMap( 2396 "chown", 2397 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 2398 Summary(NoEvalCall) 2399 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2400 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2401 .ArgConstraint(NotNull(ArgNo(0)))); 2402 2403 // int lchown(const char *path, uid_t owner, gid_t group); 2404 addToFunctionSummaryMap( 2405 "lchown", 2406 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 2407 Summary(NoEvalCall) 2408 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2409 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2410 .ArgConstraint(NotNull(ArgNo(0)))); 2411 2412 // int fchown(int fildes, uid_t owner, gid_t group); 2413 addToFunctionSummaryMap( 2414 "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 2415 Summary(NoEvalCall) 2416 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2417 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2418 .ArgConstraint( 2419 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2420 2421 // int rmdir(const char *pathname); 2422 addToFunctionSummaryMap("rmdir", 2423 Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 2424 Summary(NoEvalCall) 2425 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2426 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2427 .ArgConstraint(NotNull(ArgNo(0)))); 2428 2429 // int chdir(const char *path); 2430 addToFunctionSummaryMap("chdir", 2431 Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 2432 Summary(NoEvalCall) 2433 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2434 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2435 .ArgConstraint(NotNull(ArgNo(0)))); 2436 2437 // int link(const char *oldpath, const char *newpath); 2438 addToFunctionSummaryMap( 2439 "link", 2440 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}), 2441 Summary(NoEvalCall) 2442 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2443 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2444 .ArgConstraint(NotNull(ArgNo(0))) 2445 .ArgConstraint(NotNull(ArgNo(1)))); 2446 2447 // int linkat(int fd1, const char *path1, int fd2, const char *path2, 2448 // int flag); 2449 addToFunctionSummaryMap( 2450 "linkat", 2451 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy}, 2452 RetType{IntTy}), 2453 Summary(NoEvalCall) 2454 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2455 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2456 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2457 .ArgConstraint(NotNull(ArgNo(1))) 2458 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2))) 2459 .ArgConstraint(NotNull(ArgNo(3)))); 2460 2461 // int unlink(const char *pathname); 2462 addToFunctionSummaryMap("unlink", 2463 Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 2464 Summary(NoEvalCall) 2465 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2466 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2467 .ArgConstraint(NotNull(ArgNo(0)))); 2468 2469 // int unlinkat(int fd, const char *path, int flag); 2470 addToFunctionSummaryMap( 2471 "unlinkat", 2472 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}), 2473 Summary(NoEvalCall) 2474 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2475 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2476 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2477 .ArgConstraint(NotNull(ArgNo(1)))); 2478 2479 std::optional<QualType> StructStatTy = lookupTy("stat"); 2480 std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy); 2481 std::optional<QualType> StructStatPtrRestrictTy = 2482 getRestrictTy(StructStatPtrTy); 2483 2484 // int fstat(int fd, struct stat *statbuf); 2485 addToFunctionSummaryMap( 2486 "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}), 2487 Summary(NoEvalCall) 2488 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2489 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2490 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2491 .ArgConstraint(NotNull(ArgNo(1)))); 2492 2493 // int stat(const char *restrict path, struct stat *restrict buf); 2494 addToFunctionSummaryMap( 2495 "stat", 2496 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy}, 2497 RetType{IntTy}), 2498 Summary(NoEvalCall) 2499 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2500 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2501 .ArgConstraint(NotNull(ArgNo(0))) 2502 .ArgConstraint(NotNull(ArgNo(1)))); 2503 2504 // int lstat(const char *restrict path, struct stat *restrict buf); 2505 addToFunctionSummaryMap( 2506 "lstat", 2507 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy}, 2508 RetType{IntTy}), 2509 Summary(NoEvalCall) 2510 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2511 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2512 .ArgConstraint(NotNull(ArgNo(0))) 2513 .ArgConstraint(NotNull(ArgNo(1)))); 2514 2515 // int fstatat(int fd, const char *restrict path, 2516 // struct stat *restrict buf, int flag); 2517 addToFunctionSummaryMap( 2518 "fstatat", 2519 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy, 2520 StructStatPtrRestrictTy, IntTy}, 2521 RetType{IntTy}), 2522 Summary(NoEvalCall) 2523 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2524 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2525 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2526 .ArgConstraint(NotNull(ArgNo(1))) 2527 .ArgConstraint(NotNull(ArgNo(2)))); 2528 2529 // DIR *opendir(const char *name); 2530 // FIXME: Improve for errno modeling. 2531 addToFunctionSummaryMap( 2532 "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}), 2533 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2534 2535 // DIR *fdopendir(int fd); 2536 // FIXME: Improve for errno modeling. 2537 addToFunctionSummaryMap("fdopendir", 2538 Signature(ArgTypes{IntTy}, RetType{DirPtrTy}), 2539 Summary(NoEvalCall) 2540 .ArgConstraint(ArgumentCondition( 2541 0, WithinRange, Range(0, IntMax)))); 2542 2543 // int isatty(int fildes); 2544 addToFunctionSummaryMap( 2545 "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2546 Summary(NoEvalCall) 2547 .Case({ReturnValueCondition(WithinRange, Range(0, 1))}, 2548 ErrnoIrrelevant) 2549 .ArgConstraint( 2550 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2551 2552 // FILE *popen(const char *command, const char *type); 2553 // FIXME: Improve for errno modeling. 2554 addToFunctionSummaryMap( 2555 "popen", 2556 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}), 2557 Summary(NoEvalCall) 2558 .ArgConstraint(NotNull(ArgNo(0))) 2559 .ArgConstraint(NotNull(ArgNo(1)))); 2560 2561 // int pclose(FILE *stream); 2562 // FIXME: Improve for errno modeling. 2563 addToFunctionSummaryMap( 2564 "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 2565 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2566 2567 // int close(int fildes); 2568 addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2569 Summary(NoEvalCall) 2570 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2571 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2572 .ArgConstraint(ArgumentCondition( 2573 0, WithinRange, Range(-1, IntMax)))); 2574 2575 // long fpathconf(int fildes, int name); 2576 addToFunctionSummaryMap("fpathconf", 2577 Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}), 2578 Summary(NoEvalCall) 2579 .ArgConstraint(ArgumentCondition( 2580 0, WithinRange, Range(0, IntMax)))); 2581 2582 // long pathconf(const char *path, int name); 2583 addToFunctionSummaryMap( 2584 "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}), 2585 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2586 2587 // FILE *fdopen(int fd, const char *mode); 2588 // FIXME: Improve for errno modeling. 2589 addToFunctionSummaryMap( 2590 "fdopen", 2591 Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}), 2592 Summary(NoEvalCall) 2593 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2594 .ArgConstraint(NotNull(ArgNo(1)))); 2595 2596 // void rewinddir(DIR *dir); 2597 addToFunctionSummaryMap( 2598 "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}), 2599 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2600 2601 // void seekdir(DIR *dirp, long loc); 2602 addToFunctionSummaryMap( 2603 "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}), 2604 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2605 2606 // int rand_r(unsigned int *seedp); 2607 addToFunctionSummaryMap( 2608 "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}), 2609 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2610 2611 // int fseeko(FILE *stream, off_t offset, int whence); 2612 addToFunctionSummaryMap( 2613 "fseeko", 2614 Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}), 2615 Summary(NoEvalCall) 2616 .Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant) 2617 .ArgConstraint(NotNull(ArgNo(0)))); 2618 2619 // off_t ftello(FILE *stream); 2620 addToFunctionSummaryMap( 2621 "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}), 2622 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2623 2624 // void *mmap(void *addr, size_t length, int prot, int flags, int fd, 2625 // off_t offset); 2626 // FIXME: Improve for errno modeling. 2627 addToFunctionSummaryMap( 2628 "mmap", 2629 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy}, 2630 RetType{VoidPtrTy}), 2631 Summary(NoEvalCall) 2632 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 2633 .ArgConstraint( 2634 ArgumentCondition(4, WithinRange, Range(-1, IntMax)))); 2635 2636 std::optional<QualType> Off64_tTy = lookupTy("off64_t"); 2637 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, 2638 // off64_t offset); 2639 // FIXME: Improve for errno modeling. 2640 addToFunctionSummaryMap( 2641 "mmap64", 2642 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy}, 2643 RetType{VoidPtrTy}), 2644 Summary(NoEvalCall) 2645 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 2646 .ArgConstraint( 2647 ArgumentCondition(4, WithinRange, Range(-1, IntMax)))); 2648 2649 // int pipe(int fildes[2]); 2650 addToFunctionSummaryMap("pipe", 2651 Signature(ArgTypes{IntPtrTy}, RetType{IntTy}), 2652 Summary(NoEvalCall) 2653 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2654 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2655 .ArgConstraint(NotNull(ArgNo(0)))); 2656 2657 // off_t lseek(int fildes, off_t offset, int whence); 2658 // In the first case we can not tell for sure if it failed or not. 2659 // A return value different from of the expected offset (that is unknown 2660 // here) may indicate failure. For this reason we do not enforce the errno 2661 // check (can cause false positive). 2662 addToFunctionSummaryMap( 2663 "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}), 2664 Summary(NoEvalCall) 2665 .Case(ReturnsNonnegative, ErrnoIrrelevant) 2666 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2667 .ArgConstraint( 2668 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2669 2670 // ssize_t readlink(const char *restrict path, char *restrict buf, 2671 // size_t bufsize); 2672 addToFunctionSummaryMap( 2673 "readlink", 2674 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 2675 RetType{Ssize_tTy}), 2676 Summary(NoEvalCall) 2677 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2678 ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))}, 2679 ErrnoMustNotBeChecked) 2680 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2681 .ArgConstraint(NotNull(ArgNo(0))) 2682 .ArgConstraint(NotNull(ArgNo(1))) 2683 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2684 /*BufSize=*/ArgNo(2))) 2685 .ArgConstraint( 2686 ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); 2687 2688 // ssize_t readlinkat(int fd, const char *restrict path, 2689 // char *restrict buf, size_t bufsize); 2690 addToFunctionSummaryMap( 2691 "readlinkat", 2692 Signature( 2693 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 2694 RetType{Ssize_tTy}), 2695 Summary(NoEvalCall) 2696 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)), 2697 ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))}, 2698 ErrnoMustNotBeChecked) 2699 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2700 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2701 .ArgConstraint(NotNull(ArgNo(1))) 2702 .ArgConstraint(NotNull(ArgNo(2))) 2703 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), 2704 /*BufSize=*/ArgNo(3))) 2705 .ArgConstraint( 2706 ArgumentCondition(3, WithinRange, Range(0, SizeMax)))); 2707 2708 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char 2709 // *newpath); 2710 addToFunctionSummaryMap( 2711 "renameat", 2712 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy}, 2713 RetType{IntTy}), 2714 Summary(NoEvalCall) 2715 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2716 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2717 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2718 .ArgConstraint(NotNull(ArgNo(1))) 2719 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2))) 2720 .ArgConstraint(NotNull(ArgNo(3)))); 2721 2722 // char *realpath(const char *restrict file_name, 2723 // char *restrict resolved_name); 2724 // FIXME: Improve for errno modeling. 2725 addToFunctionSummaryMap( 2726 "realpath", 2727 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy}, 2728 RetType{CharPtrTy}), 2729 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2730 2731 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy)); 2732 2733 // int execv(const char *path, char *const argv[]); 2734 addToFunctionSummaryMap( 2735 "execv", 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 execvp(const char *file, char *const argv[]); 2743 addToFunctionSummaryMap( 2744 "execvp", 2745 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 2746 Summary(NoEvalCall) 2747 .Case({ReturnValueCondition(WithinRange, SingleValue(-1))}, 2748 ErrnoIrrelevant) 2749 .ArgConstraint(NotNull(ArgNo(0)))); 2750 2751 // int getopt(int argc, char * const argv[], const char *optstring); 2752 addToFunctionSummaryMap( 2753 "getopt", 2754 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy}, 2755 RetType{IntTy}), 2756 Summary(NoEvalCall) 2757 .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))}, 2758 ErrnoIrrelevant) 2759 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2760 .ArgConstraint(NotNull(ArgNo(1))) 2761 .ArgConstraint(NotNull(ArgNo(2)))); 2762 2763 std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr"); 2764 std::optional<QualType> StructSockaddrPtrTy = 2765 getPointerTy(StructSockaddrTy); 2766 std::optional<QualType> ConstStructSockaddrPtrTy = 2767 getPointerTy(getConstTy(StructSockaddrTy)); 2768 std::optional<QualType> StructSockaddrPtrRestrictTy = 2769 getRestrictTy(StructSockaddrPtrTy); 2770 std::optional<QualType> ConstStructSockaddrPtrRestrictTy = 2771 getRestrictTy(ConstStructSockaddrPtrTy); 2772 std::optional<QualType> Socklen_tTy = lookupTy("socklen_t"); 2773 std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy); 2774 std::optional<QualType> Socklen_tPtrRestrictTy = 2775 getRestrictTy(Socklen_tPtrTy); 2776 std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy); 2777 2778 // In 'socket.h' of some libc implementations with C99, sockaddr parameter 2779 // is a transparent union of the underlying sockaddr_ family of pointers 2780 // instead of being a pointer to struct sockaddr. In these cases, the 2781 // standardized signature will not match, thus we try to match with another 2782 // signature that has the joker Irrelevant type. We also remove those 2783 // constraints which require pointer types for the sockaddr param. 2784 auto Accept = 2785 Summary(NoEvalCall) 2786 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked) 2787 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2788 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))); 2789 if (!addToFunctionSummaryMap( 2790 "accept", 2791 // int accept(int socket, struct sockaddr *restrict address, 2792 // socklen_t *restrict address_len); 2793 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 2794 Socklen_tPtrRestrictTy}, 2795 RetType{IntTy}), 2796 Accept)) 2797 addToFunctionSummaryMap( 2798 "accept", 2799 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 2800 RetType{IntTy}), 2801 Accept); 2802 2803 // int bind(int socket, const struct sockaddr *address, socklen_t 2804 // address_len); 2805 if (!addToFunctionSummaryMap( 2806 "bind", 2807 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 2808 RetType{IntTy}), 2809 Summary(NoEvalCall) 2810 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2811 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2812 .ArgConstraint( 2813 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2814 .ArgConstraint(NotNull(ArgNo(1))) 2815 .ArgConstraint( 2816 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2))) 2817 .ArgConstraint( 2818 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))))) 2819 // Do not add constraints on sockaddr. 2820 addToFunctionSummaryMap( 2821 "bind", 2822 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 2823 Summary(NoEvalCall) 2824 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2825 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2826 .ArgConstraint( 2827 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2828 .ArgConstraint( 2829 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))); 2830 2831 // int getpeername(int socket, struct sockaddr *restrict address, 2832 // socklen_t *restrict address_len); 2833 if (!addToFunctionSummaryMap( 2834 "getpeername", 2835 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 2836 Socklen_tPtrRestrictTy}, 2837 RetType{IntTy}), 2838 Summary(NoEvalCall) 2839 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2840 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2841 .ArgConstraint( 2842 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2843 .ArgConstraint(NotNull(ArgNo(1))) 2844 .ArgConstraint(NotNull(ArgNo(2))))) 2845 addToFunctionSummaryMap( 2846 "getpeername", 2847 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 2848 RetType{IntTy}), 2849 Summary(NoEvalCall) 2850 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2851 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2852 .ArgConstraint( 2853 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2854 2855 // int getsockname(int socket, struct sockaddr *restrict address, 2856 // socklen_t *restrict address_len); 2857 if (!addToFunctionSummaryMap( 2858 "getsockname", 2859 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 2860 Socklen_tPtrRestrictTy}, 2861 RetType{IntTy}), 2862 Summary(NoEvalCall) 2863 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2864 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2865 .ArgConstraint( 2866 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2867 .ArgConstraint(NotNull(ArgNo(1))) 2868 .ArgConstraint(NotNull(ArgNo(2))))) 2869 addToFunctionSummaryMap( 2870 "getsockname", 2871 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 2872 RetType{IntTy}), 2873 Summary(NoEvalCall) 2874 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2875 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2876 .ArgConstraint( 2877 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2878 2879 // int connect(int socket, const struct sockaddr *address, socklen_t 2880 // address_len); 2881 if (!addToFunctionSummaryMap( 2882 "connect", 2883 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 2884 RetType{IntTy}), 2885 Summary(NoEvalCall) 2886 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2887 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2888 .ArgConstraint( 2889 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2890 .ArgConstraint(NotNull(ArgNo(1))))) 2891 addToFunctionSummaryMap( 2892 "connect", 2893 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 2894 Summary(NoEvalCall) 2895 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2896 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2897 .ArgConstraint( 2898 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2899 2900 auto Recvfrom = 2901 Summary(NoEvalCall) 2902 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2903 ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))}, 2904 ErrnoMustNotBeChecked) 2905 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2906 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2907 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2908 /*BufSize=*/ArgNo(2))); 2909 if (!addToFunctionSummaryMap( 2910 "recvfrom", 2911 // ssize_t recvfrom(int socket, void *restrict buffer, 2912 // size_t length, 2913 // int flags, struct sockaddr *restrict address, 2914 // socklen_t *restrict address_len); 2915 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 2916 StructSockaddrPtrRestrictTy, 2917 Socklen_tPtrRestrictTy}, 2918 RetType{Ssize_tTy}), 2919 Recvfrom)) 2920 addToFunctionSummaryMap( 2921 "recvfrom", 2922 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 2923 Irrelevant, Socklen_tPtrRestrictTy}, 2924 RetType{Ssize_tTy}), 2925 Recvfrom); 2926 2927 auto Sendto = 2928 Summary(NoEvalCall) 2929 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2930 ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))}, 2931 ErrnoMustNotBeChecked) 2932 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2933 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2934 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2935 /*BufSize=*/ArgNo(2))); 2936 if (!addToFunctionSummaryMap( 2937 "sendto", 2938 // ssize_t sendto(int socket, const void *message, size_t length, 2939 // int flags, const struct sockaddr *dest_addr, 2940 // socklen_t dest_len); 2941 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, 2942 ConstStructSockaddrPtrTy, Socklen_tTy}, 2943 RetType{Ssize_tTy}), 2944 Sendto)) 2945 addToFunctionSummaryMap( 2946 "sendto", 2947 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant, 2948 Socklen_tTy}, 2949 RetType{Ssize_tTy}), 2950 Sendto); 2951 2952 // int listen(int sockfd, int backlog); 2953 addToFunctionSummaryMap("listen", 2954 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 2955 Summary(NoEvalCall) 2956 .Case(ReturnsZero, ErrnoMustNotBeChecked) 2957 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2958 .ArgConstraint(ArgumentCondition( 2959 0, WithinRange, Range(0, IntMax)))); 2960 2961 // ssize_t recv(int sockfd, void *buf, size_t len, int flags); 2962 addToFunctionSummaryMap( 2963 "recv", 2964 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, 2965 RetType{Ssize_tTy}), 2966 Summary(NoEvalCall) 2967 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2968 ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))}, 2969 ErrnoMustNotBeChecked) 2970 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2971 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2972 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2973 /*BufSize=*/ArgNo(2)))); 2974 2975 std::optional<QualType> StructMsghdrTy = lookupTy("msghdr"); 2976 std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy); 2977 std::optional<QualType> ConstStructMsghdrPtrTy = 2978 getPointerTy(getConstTy(StructMsghdrTy)); 2979 2980 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 2981 addToFunctionSummaryMap( 2982 "recvmsg", 2983 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy}, 2984 RetType{Ssize_tTy}), 2985 Summary(NoEvalCall) 2986 .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))}, 2987 ErrnoMustNotBeChecked) 2988 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 2989 .ArgConstraint( 2990 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2991 2992 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 2993 addToFunctionSummaryMap( 2994 "sendmsg", 2995 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy}, 2996 RetType{Ssize_tTy}), 2997 Summary(NoEvalCall) 2998 .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))}, 2999 ErrnoMustNotBeChecked) 3000 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3001 .ArgConstraint( 3002 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3003 3004 // int setsockopt(int socket, int level, int option_name, 3005 // const void *option_value, socklen_t option_len); 3006 addToFunctionSummaryMap( 3007 "setsockopt", 3008 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy}, 3009 RetType{IntTy}), 3010 Summary(NoEvalCall) 3011 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3012 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3013 .ArgConstraint(NotNull(ArgNo(3))) 3014 .ArgConstraint( 3015 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4))) 3016 .ArgConstraint( 3017 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax)))); 3018 3019 // int getsockopt(int socket, int level, int option_name, 3020 // void *restrict option_value, 3021 // socklen_t *restrict option_len); 3022 addToFunctionSummaryMap( 3023 "getsockopt", 3024 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy, 3025 Socklen_tPtrRestrictTy}, 3026 RetType{IntTy}), 3027 Summary(NoEvalCall) 3028 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3029 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3030 .ArgConstraint(NotNull(ArgNo(3))) 3031 .ArgConstraint(NotNull(ArgNo(4)))); 3032 3033 // ssize_t send(int sockfd, const void *buf, size_t len, int flags); 3034 addToFunctionSummaryMap( 3035 "send", 3036 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy}, 3037 RetType{Ssize_tTy}), 3038 Summary(NoEvalCall) 3039 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 3040 ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))}, 3041 ErrnoMustNotBeChecked) 3042 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3043 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3044 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 3045 /*BufSize=*/ArgNo(2)))); 3046 3047 // int socketpair(int domain, int type, int protocol, int sv[2]); 3048 addToFunctionSummaryMap( 3049 "socketpair", 3050 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}), 3051 Summary(NoEvalCall) 3052 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3053 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3054 .ArgConstraint(NotNull(ArgNo(3)))); 3055 3056 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, 3057 // char *restrict node, socklen_t nodelen, 3058 // char *restrict service, 3059 // socklen_t servicelen, int flags); 3060 // 3061 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr 3062 // parameter is never handled as a transparent union in netdb.h 3063 addToFunctionSummaryMap( 3064 "getnameinfo", 3065 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy, 3066 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy, 3067 Socklen_tTy, IntTy}, 3068 RetType{IntTy}), 3069 Summary(NoEvalCall) 3070 .ArgConstraint( 3071 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))) 3072 .ArgConstraint( 3073 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax))) 3074 .ArgConstraint( 3075 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3))) 3076 .ArgConstraint( 3077 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax))) 3078 .ArgConstraint( 3079 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5))) 3080 .ArgConstraint( 3081 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax)))); 3082 3083 std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf"); 3084 std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy); 3085 3086 // int utime(const char *filename, struct utimbuf *buf); 3087 addToFunctionSummaryMap( 3088 "utime", 3089 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}), 3090 Summary(NoEvalCall) 3091 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3092 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3093 .ArgConstraint(NotNull(ArgNo(0)))); 3094 3095 std::optional<QualType> StructTimespecTy = lookupTy("timespec"); 3096 std::optional<QualType> StructTimespecPtrTy = 3097 getPointerTy(StructTimespecTy); 3098 std::optional<QualType> ConstStructTimespecPtrTy = 3099 getPointerTy(getConstTy(StructTimespecTy)); 3100 3101 // int futimens(int fd, const struct timespec times[2]); 3102 addToFunctionSummaryMap( 3103 "futimens", 3104 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}), 3105 Summary(NoEvalCall) 3106 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3107 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3108 .ArgConstraint( 3109 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3110 3111 // int utimensat(int dirfd, const char *pathname, 3112 // const struct timespec times[2], int flags); 3113 addToFunctionSummaryMap("utimensat", 3114 Signature(ArgTypes{IntTy, ConstCharPtrTy, 3115 ConstStructTimespecPtrTy, IntTy}, 3116 RetType{IntTy}), 3117 Summary(NoEvalCall) 3118 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3119 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3120 .ArgConstraint(NotNull(ArgNo(1)))); 3121 3122 std::optional<QualType> StructTimevalTy = lookupTy("timeval"); 3123 std::optional<QualType> ConstStructTimevalPtrTy = 3124 getPointerTy(getConstTy(StructTimevalTy)); 3125 3126 // int utimes(const char *filename, const struct timeval times[2]); 3127 addToFunctionSummaryMap( 3128 "utimes", 3129 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy}, 3130 RetType{IntTy}), 3131 Summary(NoEvalCall) 3132 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3133 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3134 .ArgConstraint(NotNull(ArgNo(0)))); 3135 3136 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); 3137 addToFunctionSummaryMap( 3138 "nanosleep", 3139 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy}, 3140 RetType{IntTy}), 3141 Summary(NoEvalCall) 3142 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3143 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3144 .ArgConstraint(NotNull(ArgNo(0)))); 3145 3146 std::optional<QualType> Time_tTy = lookupTy("time_t"); 3147 std::optional<QualType> ConstTime_tPtrTy = 3148 getPointerTy(getConstTy(Time_tTy)); 3149 std::optional<QualType> ConstTime_tPtrRestrictTy = 3150 getRestrictTy(ConstTime_tPtrTy); 3151 3152 std::optional<QualType> StructTmTy = lookupTy("tm"); 3153 std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy); 3154 std::optional<QualType> StructTmPtrRestrictTy = 3155 getRestrictTy(StructTmPtrTy); 3156 std::optional<QualType> ConstStructTmPtrTy = 3157 getPointerTy(getConstTy(StructTmTy)); 3158 std::optional<QualType> ConstStructTmPtrRestrictTy = 3159 getRestrictTy(ConstStructTmPtrTy); 3160 3161 // struct tm * localtime(const time_t *tp); 3162 addToFunctionSummaryMap( 3163 "localtime", 3164 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 3165 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3166 3167 // struct tm *localtime_r(const time_t *restrict timer, 3168 // struct tm *restrict result); 3169 addToFunctionSummaryMap( 3170 "localtime_r", 3171 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 3172 RetType{StructTmPtrTy}), 3173 Summary(NoEvalCall) 3174 .ArgConstraint(NotNull(ArgNo(0))) 3175 .ArgConstraint(NotNull(ArgNo(1)))); 3176 3177 // char *asctime_r(const struct tm *restrict tm, char *restrict buf); 3178 addToFunctionSummaryMap( 3179 "asctime_r", 3180 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy}, 3181 RetType{CharPtrTy}), 3182 Summary(NoEvalCall) 3183 .ArgConstraint(NotNull(ArgNo(0))) 3184 .ArgConstraint(NotNull(ArgNo(1))) 3185 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 3186 /*MinBufSize=*/BVF.getValue(26, IntTy)))); 3187 3188 // char *ctime_r(const time_t *timep, char *buf); 3189 addToFunctionSummaryMap( 3190 "ctime_r", 3191 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}), 3192 Summary(NoEvalCall) 3193 .ArgConstraint(NotNull(ArgNo(0))) 3194 .ArgConstraint(NotNull(ArgNo(1))) 3195 .ArgConstraint(BufferSize( 3196 /*Buffer=*/ArgNo(1), 3197 /*MinBufSize=*/BVF.getValue(26, IntTy)))); 3198 3199 // struct tm *gmtime_r(const time_t *restrict timer, 3200 // struct tm *restrict result); 3201 addToFunctionSummaryMap( 3202 "gmtime_r", 3203 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 3204 RetType{StructTmPtrTy}), 3205 Summary(NoEvalCall) 3206 .ArgConstraint(NotNull(ArgNo(0))) 3207 .ArgConstraint(NotNull(ArgNo(1)))); 3208 3209 // struct tm * gmtime(const time_t *tp); 3210 addToFunctionSummaryMap( 3211 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 3212 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3213 3214 std::optional<QualType> Clockid_tTy = lookupTy("clockid_t"); 3215 3216 // int clock_gettime(clockid_t clock_id, struct timespec *tp); 3217 addToFunctionSummaryMap( 3218 "clock_gettime", 3219 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}), 3220 Summary(NoEvalCall) 3221 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3222 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3223 .ArgConstraint(NotNull(ArgNo(1)))); 3224 3225 std::optional<QualType> StructItimervalTy = lookupTy("itimerval"); 3226 std::optional<QualType> StructItimervalPtrTy = 3227 getPointerTy(StructItimervalTy); 3228 3229 // int getitimer(int which, struct itimerval *curr_value); 3230 addToFunctionSummaryMap( 3231 "getitimer", 3232 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}), 3233 Summary(NoEvalCall) 3234 .Case(ReturnsZero, ErrnoMustNotBeChecked) 3235 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant) 3236 .ArgConstraint(NotNull(ArgNo(1)))); 3237 3238 std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t"); 3239 std::optional<QualType> Pthread_cond_tPtrTy = 3240 getPointerTy(Pthread_cond_tTy); 3241 std::optional<QualType> Pthread_tTy = lookupTy("pthread_t"); 3242 std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy); 3243 std::optional<QualType> Pthread_tPtrRestrictTy = 3244 getRestrictTy(Pthread_tPtrTy); 3245 std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t"); 3246 std::optional<QualType> Pthread_mutex_tPtrTy = 3247 getPointerTy(Pthread_mutex_tTy); 3248 std::optional<QualType> Pthread_mutex_tPtrRestrictTy = 3249 getRestrictTy(Pthread_mutex_tPtrTy); 3250 std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t"); 3251 std::optional<QualType> Pthread_attr_tPtrTy = 3252 getPointerTy(Pthread_attr_tTy); 3253 std::optional<QualType> ConstPthread_attr_tPtrTy = 3254 getPointerTy(getConstTy(Pthread_attr_tTy)); 3255 std::optional<QualType> ConstPthread_attr_tPtrRestrictTy = 3256 getRestrictTy(ConstPthread_attr_tPtrTy); 3257 std::optional<QualType> Pthread_mutexattr_tTy = 3258 lookupTy("pthread_mutexattr_t"); 3259 std::optional<QualType> ConstPthread_mutexattr_tPtrTy = 3260 getPointerTy(getConstTy(Pthread_mutexattr_tTy)); 3261 std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy = 3262 getRestrictTy(ConstPthread_mutexattr_tPtrTy); 3263 3264 QualType PthreadStartRoutineTy = getPointerTy( 3265 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy, 3266 FunctionProtoType::ExtProtoInfo())); 3267 3268 // int pthread_cond_signal(pthread_cond_t *cond); 3269 // int pthread_cond_broadcast(pthread_cond_t *cond); 3270 addToFunctionSummaryMap( 3271 {"pthread_cond_signal", "pthread_cond_broadcast"}, 3272 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}), 3273 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3274 3275 // int pthread_create(pthread_t *restrict thread, 3276 // const pthread_attr_t *restrict attr, 3277 // void *(*start_routine)(void*), void *restrict arg); 3278 addToFunctionSummaryMap( 3279 "pthread_create", 3280 Signature(ArgTypes{Pthread_tPtrRestrictTy, 3281 ConstPthread_attr_tPtrRestrictTy, 3282 PthreadStartRoutineTy, VoidPtrRestrictTy}, 3283 RetType{IntTy}), 3284 Summary(NoEvalCall) 3285 .ArgConstraint(NotNull(ArgNo(0))) 3286 .ArgConstraint(NotNull(ArgNo(2)))); 3287 3288 // int pthread_attr_destroy(pthread_attr_t *attr); 3289 // int pthread_attr_init(pthread_attr_t *attr); 3290 addToFunctionSummaryMap( 3291 {"pthread_attr_destroy", "pthread_attr_init"}, 3292 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}), 3293 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3294 3295 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, 3296 // size_t *restrict stacksize); 3297 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, 3298 // size_t *restrict guardsize); 3299 addToFunctionSummaryMap( 3300 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"}, 3301 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy}, 3302 RetType{IntTy}), 3303 Summary(NoEvalCall) 3304 .ArgConstraint(NotNull(ArgNo(0))) 3305 .ArgConstraint(NotNull(ArgNo(1)))); 3306 3307 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); 3308 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); 3309 addToFunctionSummaryMap( 3310 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"}, 3311 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}), 3312 Summary(NoEvalCall) 3313 .ArgConstraint(NotNull(ArgNo(0))) 3314 .ArgConstraint( 3315 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 3316 3317 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const 3318 // pthread_mutexattr_t *restrict attr); 3319 addToFunctionSummaryMap( 3320 "pthread_mutex_init", 3321 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy, 3322 ConstPthread_mutexattr_tPtrRestrictTy}, 3323 RetType{IntTy}), 3324 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3325 3326 // int pthread_mutex_destroy(pthread_mutex_t *mutex); 3327 // int pthread_mutex_lock(pthread_mutex_t *mutex); 3328 // int pthread_mutex_trylock(pthread_mutex_t *mutex); 3329 // int pthread_mutex_unlock(pthread_mutex_t *mutex); 3330 addToFunctionSummaryMap( 3331 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock", 3332 "pthread_mutex_unlock"}, 3333 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}), 3334 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3335 } 3336 3337 // Functions for testing. 3338 if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) { 3339 const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue(); 3340 3341 addToFunctionSummaryMap( 3342 "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}), 3343 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0)))); 3344 3345 // Test inside range constraints. 3346 addToFunctionSummaryMap( 3347 "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3348 Summary(EvalCallAsPure) 3349 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0)))); 3350 addToFunctionSummaryMap( 3351 "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3352 Summary(EvalCallAsPure) 3353 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))); 3354 addToFunctionSummaryMap( 3355 "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3356 Summary(EvalCallAsPure) 3357 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2)))); 3358 addToFunctionSummaryMap( 3359 "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3360 Summary(EvalCallAsPure) 3361 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1)))); 3362 addToFunctionSummaryMap( 3363 "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3364 Summary(EvalCallAsPure) 3365 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1)))); 3366 addToFunctionSummaryMap( 3367 "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3368 Summary(EvalCallAsPure) 3369 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10)))); 3370 addToFunctionSummaryMap("__range_m1_inf", 3371 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3372 Summary(EvalCallAsPure) 3373 .ArgConstraint(ArgumentCondition( 3374 0U, WithinRange, Range(-1, IntMax)))); 3375 addToFunctionSummaryMap("__range_0_inf", 3376 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3377 Summary(EvalCallAsPure) 3378 .ArgConstraint(ArgumentCondition( 3379 0U, WithinRange, Range(0, IntMax)))); 3380 addToFunctionSummaryMap("__range_1_inf", 3381 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3382 Summary(EvalCallAsPure) 3383 .ArgConstraint(ArgumentCondition( 3384 0U, WithinRange, Range(1, IntMax)))); 3385 addToFunctionSummaryMap("__range_minf_m1", 3386 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3387 Summary(EvalCallAsPure) 3388 .ArgConstraint(ArgumentCondition( 3389 0U, WithinRange, Range(IntMin, -1)))); 3390 addToFunctionSummaryMap("__range_minf_0", 3391 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3392 Summary(EvalCallAsPure) 3393 .ArgConstraint(ArgumentCondition( 3394 0U, WithinRange, Range(IntMin, 0)))); 3395 addToFunctionSummaryMap("__range_minf_1", 3396 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3397 Summary(EvalCallAsPure) 3398 .ArgConstraint(ArgumentCondition( 3399 0U, WithinRange, Range(IntMin, 1)))); 3400 addToFunctionSummaryMap("__range_1_2__4_6", 3401 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3402 Summary(EvalCallAsPure) 3403 .ArgConstraint(ArgumentCondition( 3404 0U, WithinRange, Range({1, 2}, {4, 6})))); 3405 addToFunctionSummaryMap( 3406 "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3407 Summary(EvalCallAsPure) 3408 .ArgConstraint(ArgumentCondition(0U, WithinRange, 3409 Range({1, 2}, {4, IntMax})))); 3410 3411 // Test out of range constraints. 3412 addToFunctionSummaryMap( 3413 "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3414 Summary(EvalCallAsPure) 3415 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0)))); 3416 addToFunctionSummaryMap( 3417 "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3418 Summary(EvalCallAsPure) 3419 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))); 3420 addToFunctionSummaryMap( 3421 "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3422 Summary(EvalCallAsPure) 3423 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2)))); 3424 addToFunctionSummaryMap( 3425 "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3426 Summary(EvalCallAsPure) 3427 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1)))); 3428 addToFunctionSummaryMap( 3429 "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3430 Summary(EvalCallAsPure) 3431 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1)))); 3432 addToFunctionSummaryMap( 3433 "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3434 Summary(EvalCallAsPure) 3435 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10)))); 3436 addToFunctionSummaryMap("__range_out_m1_inf", 3437 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3438 Summary(EvalCallAsPure) 3439 .ArgConstraint(ArgumentCondition( 3440 0U, OutOfRange, Range(-1, IntMax)))); 3441 addToFunctionSummaryMap("__range_out_0_inf", 3442 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3443 Summary(EvalCallAsPure) 3444 .ArgConstraint(ArgumentCondition( 3445 0U, OutOfRange, Range(0, IntMax)))); 3446 addToFunctionSummaryMap("__range_out_1_inf", 3447 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3448 Summary(EvalCallAsPure) 3449 .ArgConstraint(ArgumentCondition( 3450 0U, OutOfRange, Range(1, IntMax)))); 3451 addToFunctionSummaryMap("__range_out_minf_m1", 3452 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3453 Summary(EvalCallAsPure) 3454 .ArgConstraint(ArgumentCondition( 3455 0U, OutOfRange, Range(IntMin, -1)))); 3456 addToFunctionSummaryMap("__range_out_minf_0", 3457 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3458 Summary(EvalCallAsPure) 3459 .ArgConstraint(ArgumentCondition( 3460 0U, OutOfRange, Range(IntMin, 0)))); 3461 addToFunctionSummaryMap("__range_out_minf_1", 3462 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3463 Summary(EvalCallAsPure) 3464 .ArgConstraint(ArgumentCondition( 3465 0U, OutOfRange, Range(IntMin, 1)))); 3466 addToFunctionSummaryMap("__range_out_1_2__4_6", 3467 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3468 Summary(EvalCallAsPure) 3469 .ArgConstraint(ArgumentCondition( 3470 0U, OutOfRange, Range({1, 2}, {4, 6})))); 3471 addToFunctionSummaryMap( 3472 "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3473 Summary(EvalCallAsPure) 3474 .ArgConstraint( 3475 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax})))); 3476 3477 // Test range kind. 3478 addToFunctionSummaryMap( 3479 "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3480 Summary(EvalCallAsPure) 3481 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))); 3482 addToFunctionSummaryMap( 3483 "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3484 Summary(EvalCallAsPure) 3485 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))); 3486 3487 addToFunctionSummaryMap( 3488 "__two_constrained_args", 3489 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 3490 Summary(EvalCallAsPure) 3491 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))) 3492 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1)))); 3493 addToFunctionSummaryMap( 3494 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3495 Summary(EvalCallAsPure) 3496 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))) 3497 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2)))); 3498 addToFunctionSummaryMap( 3499 "__defaultparam", 3500 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}), 3501 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0)))); 3502 addToFunctionSummaryMap( 3503 "__variadic", 3504 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}), 3505 Summary(EvalCallAsPure) 3506 .ArgConstraint(NotNull(ArgNo(0))) 3507 .ArgConstraint(NotNull(ArgNo(1)))); 3508 addToFunctionSummaryMap( 3509 "__buf_size_arg_constraint", 3510 Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}), 3511 Summary(EvalCallAsPure) 3512 .ArgConstraint( 3513 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))); 3514 addToFunctionSummaryMap( 3515 "__buf_size_arg_constraint_mul", 3516 Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}), 3517 Summary(EvalCallAsPure) 3518 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 3519 /*BufSizeMultiplier=*/ArgNo(2)))); 3520 addToFunctionSummaryMap( 3521 "__buf_size_arg_constraint_concrete", 3522 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}), 3523 Summary(EvalCallAsPure) 3524 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), 3525 /*BufSize=*/BVF.getValue(10, IntTy)))); 3526 addToFunctionSummaryMap( 3527 {"__test_restrict_param_0", "__test_restrict_param_1", 3528 "__test_restrict_param_2"}, 3529 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}), 3530 Summary(EvalCallAsPure)); 3531 3532 // Test the application of cases. 3533 addToFunctionSummaryMap( 3534 "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}), 3535 Summary(EvalCallAsPure) 3536 .Case({ReturnValueCondition(WithinRange, SingleValue(0))}, 3537 ErrnoIrrelevant, "Function returns 0") 3538 .Case({ReturnValueCondition(WithinRange, SingleValue(1))}, 3539 ErrnoIrrelevant, "Function returns 1")); 3540 addToFunctionSummaryMap( 3541 "__test_case_range_1_2__4_6", 3542 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3543 Summary(EvalCallAsPure) 3544 .Case({ArgumentCondition(0U, WithinRange, 3545 IntRangeVector{{IntMin, 0}, {3, 3}}), 3546 ReturnValueCondition(WithinRange, SingleValue(1))}, 3547 ErrnoIrrelevant) 3548 .Case({ArgumentCondition(0U, WithinRange, 3549 IntRangeVector{{3, 3}, {7, IntMax}}), 3550 ReturnValueCondition(WithinRange, SingleValue(2))}, 3551 ErrnoIrrelevant) 3552 .Case({ArgumentCondition(0U, WithinRange, 3553 IntRangeVector{{IntMin, 0}, {7, IntMax}}), 3554 ReturnValueCondition(WithinRange, SingleValue(3))}, 3555 ErrnoIrrelevant) 3556 .Case({ArgumentCondition( 3557 0U, WithinRange, 3558 IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}), 3559 ReturnValueCondition(WithinRange, SingleValue(4))}, 3560 ErrnoIrrelevant)); 3561 } 3562 3563 SummariesInitialized = true; 3564 } 3565 3566 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 3567 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>(); 3568 const AnalyzerOptions &Opts = mgr.getAnalyzerOptions(); 3569 Checker->DisplayLoadedSummaries = 3570 Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries"); 3571 Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX"); 3572 Checker->ShouldAssumeControlledEnvironment = 3573 Opts.ShouldAssumeControlledEnvironment; 3574 } 3575 3576 bool ento::shouldRegisterStdCLibraryFunctionsChecker( 3577 const CheckerManager &mgr) { 3578 return true; 3579 } 3580 3581 #define REGISTER_CHECKER(name) \ 3582 void ento::register##name(CheckerManager &mgr) { \ 3583 StdLibraryFunctionsChecker *checker = \ 3584 mgr.getChecker<StdLibraryFunctionsChecker>(); \ 3585 checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \ 3586 checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \ 3587 mgr.getCurrentCheckerName(); \ 3588 } \ 3589 \ 3590 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 3591 3592 REGISTER_CHECKER(StdCLibraryFunctionArgsChecker) 3593 REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker) 3594