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