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