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({ArgumentCondition(2, WithinRange, Range(1, IntMax)), 2869 ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2870 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))}, 2871 ErrnoMustNotBeChecked, GenericSuccessMsg) 2872 .Case({ArgumentCondition(2, WithinRange, SingleValue(0)), 2873 ReturnValueCondition(WithinRange, SingleValue(0))}, 2874 ErrnoMustNotBeChecked, 2875 "Assuming that argument 'bufsize' is 0") 2876 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 2877 .ArgConstraint(NotNull(ArgNo(0))) 2878 .ArgConstraint(NotNull(ArgNo(1))) 2879 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2880 /*BufSize=*/ArgNo(2))) 2881 .ArgConstraint( 2882 ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); 2883 2884 // ssize_t readlinkat(int fd, const char *restrict path, 2885 // char *restrict buf, size_t bufsize); 2886 addToFunctionSummaryMap( 2887 "readlinkat", 2888 Signature( 2889 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 2890 RetType{Ssize_tTy}), 2891 Summary(NoEvalCall) 2892 .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)), 2893 ReturnValueCondition(LessThanOrEq, ArgNo(3)), 2894 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))}, 2895 ErrnoMustNotBeChecked, GenericSuccessMsg) 2896 .Case({ArgumentCondition(3, WithinRange, SingleValue(0)), 2897 ReturnValueCondition(WithinRange, SingleValue(0))}, 2898 ErrnoMustNotBeChecked, 2899 "Assuming that argument 'bufsize' is 0") 2900 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 2901 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2902 .ArgConstraint(NotNull(ArgNo(1))) 2903 .ArgConstraint(NotNull(ArgNo(2))) 2904 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), 2905 /*BufSize=*/ArgNo(3))) 2906 .ArgConstraint( 2907 ArgumentCondition(3, WithinRange, Range(0, SizeMax)))); 2908 2909 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char 2910 // *newpath); 2911 addToFunctionSummaryMap( 2912 "renameat", 2913 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy}, 2914 RetType{IntTy}), 2915 Summary(NoEvalCall) 2916 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 2917 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 2918 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0))) 2919 .ArgConstraint(NotNull(ArgNo(1))) 2920 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2))) 2921 .ArgConstraint(NotNull(ArgNo(3)))); 2922 2923 // char *realpath(const char *restrict file_name, 2924 // char *restrict resolved_name); 2925 // FIXME: Improve for errno modeling. 2926 addToFunctionSummaryMap( 2927 "realpath", 2928 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy}, 2929 RetType{CharPtrTy}), 2930 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2931 2932 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy)); 2933 2934 // int execv(const char *path, char *const argv[]); 2935 addToFunctionSummaryMap( 2936 "execv", 2937 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 2938 Summary(NoEvalCall) 2939 .Case({ReturnValueCondition(WithinRange, SingleValue(-1))}, 2940 ErrnoIrrelevant) 2941 .ArgConstraint(NotNull(ArgNo(0)))); 2942 2943 // int execvp(const char *file, char *const argv[]); 2944 addToFunctionSummaryMap( 2945 "execvp", 2946 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 2947 Summary(NoEvalCall) 2948 .Case({ReturnValueCondition(WithinRange, SingleValue(-1))}, 2949 ErrnoIrrelevant) 2950 .ArgConstraint(NotNull(ArgNo(0)))); 2951 2952 // int getopt(int argc, char * const argv[], const char *optstring); 2953 addToFunctionSummaryMap( 2954 "getopt", 2955 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy}, 2956 RetType{IntTy}), 2957 Summary(NoEvalCall) 2958 .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))}, 2959 ErrnoIrrelevant) 2960 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2961 .ArgConstraint(NotNull(ArgNo(1))) 2962 .ArgConstraint(NotNull(ArgNo(2)))); 2963 2964 std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr"); 2965 std::optional<QualType> StructSockaddrPtrTy = 2966 getPointerTy(StructSockaddrTy); 2967 std::optional<QualType> ConstStructSockaddrPtrTy = 2968 getPointerTy(getConstTy(StructSockaddrTy)); 2969 std::optional<QualType> StructSockaddrPtrRestrictTy = 2970 getRestrictTy(StructSockaddrPtrTy); 2971 std::optional<QualType> ConstStructSockaddrPtrRestrictTy = 2972 getRestrictTy(ConstStructSockaddrPtrTy); 2973 std::optional<QualType> Socklen_tTy = lookupTy("socklen_t"); 2974 std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy); 2975 std::optional<QualType> Socklen_tPtrRestrictTy = 2976 getRestrictTy(Socklen_tPtrTy); 2977 std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy); 2978 2979 // In 'socket.h' of some libc implementations with C99, sockaddr parameter 2980 // is a transparent union of the underlying sockaddr_ family of pointers 2981 // instead of being a pointer to struct sockaddr. In these cases, the 2982 // standardized signature will not match, thus we try to match with another 2983 // signature that has the joker Irrelevant type. We also remove those 2984 // constraints which require pointer types for the sockaddr param. 2985 2986 // int socket(int domain, int type, int protocol); 2987 addToFunctionSummaryMap( 2988 "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}), 2989 Summary(NoEvalCall) 2990 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked, 2991 GenericSuccessMsg) 2992 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)); 2993 2994 auto Accept = 2995 Summary(NoEvalCall) 2996 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked, 2997 GenericSuccessMsg) 2998 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 2999 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))); 3000 if (!addToFunctionSummaryMap( 3001 "accept", 3002 // int accept(int socket, struct sockaddr *restrict address, 3003 // socklen_t *restrict address_len); 3004 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 3005 Socklen_tPtrRestrictTy}, 3006 RetType{IntTy}), 3007 Accept)) 3008 addToFunctionSummaryMap( 3009 "accept", 3010 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 3011 RetType{IntTy}), 3012 Accept); 3013 3014 // int bind(int socket, const struct sockaddr *address, socklen_t 3015 // address_len); 3016 if (!addToFunctionSummaryMap( 3017 "bind", 3018 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 3019 RetType{IntTy}), 3020 Summary(NoEvalCall) 3021 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3022 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3023 .ArgConstraint( 3024 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3025 .ArgConstraint(NotNull(ArgNo(1))) 3026 .ArgConstraint( 3027 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2))) 3028 .ArgConstraint( 3029 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))))) 3030 // Do not add constraints on sockaddr. 3031 addToFunctionSummaryMap( 3032 "bind", 3033 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 3034 Summary(NoEvalCall) 3035 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3036 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3037 .ArgConstraint( 3038 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3039 .ArgConstraint( 3040 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))); 3041 3042 // int getpeername(int socket, struct sockaddr *restrict address, 3043 // socklen_t *restrict address_len); 3044 if (!addToFunctionSummaryMap( 3045 "getpeername", 3046 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 3047 Socklen_tPtrRestrictTy}, 3048 RetType{IntTy}), 3049 Summary(NoEvalCall) 3050 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3051 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3052 .ArgConstraint( 3053 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3054 .ArgConstraint(NotNull(ArgNo(1))) 3055 .ArgConstraint(NotNull(ArgNo(2))))) 3056 addToFunctionSummaryMap( 3057 "getpeername", 3058 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 3059 RetType{IntTy}), 3060 Summary(NoEvalCall) 3061 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3062 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3063 .ArgConstraint( 3064 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3065 3066 // int getsockname(int socket, struct sockaddr *restrict address, 3067 // socklen_t *restrict address_len); 3068 if (!addToFunctionSummaryMap( 3069 "getsockname", 3070 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 3071 Socklen_tPtrRestrictTy}, 3072 RetType{IntTy}), 3073 Summary(NoEvalCall) 3074 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3075 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3076 .ArgConstraint( 3077 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3078 .ArgConstraint(NotNull(ArgNo(1))) 3079 .ArgConstraint(NotNull(ArgNo(2))))) 3080 addToFunctionSummaryMap( 3081 "getsockname", 3082 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 3083 RetType{IntTy}), 3084 Summary(NoEvalCall) 3085 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3086 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3087 .ArgConstraint( 3088 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3089 3090 // int connect(int socket, const struct sockaddr *address, socklen_t 3091 // address_len); 3092 if (!addToFunctionSummaryMap( 3093 "connect", 3094 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 3095 RetType{IntTy}), 3096 Summary(NoEvalCall) 3097 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3098 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3099 .ArgConstraint( 3100 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3101 .ArgConstraint(NotNull(ArgNo(1))))) 3102 addToFunctionSummaryMap( 3103 "connect", 3104 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 3105 Summary(NoEvalCall) 3106 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3107 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3108 .ArgConstraint( 3109 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3110 3111 auto Recvfrom = 3112 Summary(NoEvalCall) 3113 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 3114 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))}, 3115 ErrnoMustNotBeChecked, GenericSuccessMsg) 3116 .Case({ReturnValueCondition(WithinRange, SingleValue(0)), 3117 ArgumentCondition(2, WithinRange, SingleValue(0))}, 3118 ErrnoMustNotBeChecked, GenericSuccessMsg) 3119 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3120 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3121 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 3122 /*BufSize=*/ArgNo(2))); 3123 if (!addToFunctionSummaryMap( 3124 "recvfrom", 3125 // ssize_t recvfrom(int socket, void *restrict buffer, 3126 // size_t length, 3127 // int flags, struct sockaddr *restrict address, 3128 // socklen_t *restrict address_len); 3129 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 3130 StructSockaddrPtrRestrictTy, 3131 Socklen_tPtrRestrictTy}, 3132 RetType{Ssize_tTy}), 3133 Recvfrom)) 3134 addToFunctionSummaryMap( 3135 "recvfrom", 3136 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 3137 Irrelevant, Socklen_tPtrRestrictTy}, 3138 RetType{Ssize_tTy}), 3139 Recvfrom); 3140 3141 auto Sendto = 3142 Summary(NoEvalCall) 3143 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 3144 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))}, 3145 ErrnoMustNotBeChecked, GenericSuccessMsg) 3146 .Case({ReturnValueCondition(WithinRange, SingleValue(0)), 3147 ArgumentCondition(2, WithinRange, SingleValue(0))}, 3148 ErrnoMustNotBeChecked, GenericSuccessMsg) 3149 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3150 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3151 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 3152 /*BufSize=*/ArgNo(2))); 3153 if (!addToFunctionSummaryMap( 3154 "sendto", 3155 // ssize_t sendto(int socket, const void *message, size_t length, 3156 // int flags, const struct sockaddr *dest_addr, 3157 // socklen_t dest_len); 3158 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, 3159 ConstStructSockaddrPtrTy, Socklen_tTy}, 3160 RetType{Ssize_tTy}), 3161 Sendto)) 3162 addToFunctionSummaryMap( 3163 "sendto", 3164 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant, 3165 Socklen_tTy}, 3166 RetType{Ssize_tTy}), 3167 Sendto); 3168 3169 // int listen(int sockfd, int backlog); 3170 addToFunctionSummaryMap( 3171 "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 3172 Summary(NoEvalCall) 3173 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3174 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3175 .ArgConstraint( 3176 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3177 3178 // ssize_t recv(int sockfd, void *buf, size_t len, int flags); 3179 addToFunctionSummaryMap( 3180 "recv", 3181 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, 3182 RetType{Ssize_tTy}), 3183 Summary(NoEvalCall) 3184 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 3185 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))}, 3186 ErrnoMustNotBeChecked, GenericSuccessMsg) 3187 .Case({ReturnValueCondition(WithinRange, SingleValue(0)), 3188 ArgumentCondition(2, WithinRange, SingleValue(0))}, 3189 ErrnoMustNotBeChecked, GenericSuccessMsg) 3190 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3191 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3192 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 3193 /*BufSize=*/ArgNo(2)))); 3194 3195 std::optional<QualType> StructMsghdrTy = lookupTy("msghdr"); 3196 std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy); 3197 std::optional<QualType> ConstStructMsghdrPtrTy = 3198 getPointerTy(getConstTy(StructMsghdrTy)); 3199 3200 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 3201 addToFunctionSummaryMap( 3202 "recvmsg", 3203 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy}, 3204 RetType{Ssize_tTy}), 3205 Summary(NoEvalCall) 3206 .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))}, 3207 ErrnoMustNotBeChecked, GenericSuccessMsg) 3208 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3209 .ArgConstraint( 3210 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3211 3212 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 3213 addToFunctionSummaryMap( 3214 "sendmsg", 3215 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy}, 3216 RetType{Ssize_tTy}), 3217 Summary(NoEvalCall) 3218 .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))}, 3219 ErrnoMustNotBeChecked, GenericSuccessMsg) 3220 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3221 .ArgConstraint( 3222 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3223 3224 // int setsockopt(int socket, int level, int option_name, 3225 // const void *option_value, socklen_t option_len); 3226 addToFunctionSummaryMap( 3227 "setsockopt", 3228 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy}, 3229 RetType{IntTy}), 3230 Summary(NoEvalCall) 3231 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3232 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3233 .ArgConstraint(NotNull(ArgNo(3))) 3234 .ArgConstraint( 3235 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4))) 3236 .ArgConstraint( 3237 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax)))); 3238 3239 // int getsockopt(int socket, int level, int option_name, 3240 // void *restrict option_value, 3241 // socklen_t *restrict option_len); 3242 addToFunctionSummaryMap( 3243 "getsockopt", 3244 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy, 3245 Socklen_tPtrRestrictTy}, 3246 RetType{IntTy}), 3247 Summary(NoEvalCall) 3248 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3249 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3250 .ArgConstraint(NotNull(ArgNo(3))) 3251 .ArgConstraint(NotNull(ArgNo(4)))); 3252 3253 // ssize_t send(int sockfd, const void *buf, size_t len, int flags); 3254 addToFunctionSummaryMap( 3255 "send", 3256 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy}, 3257 RetType{Ssize_tTy}), 3258 Summary(NoEvalCall) 3259 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 3260 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))}, 3261 ErrnoMustNotBeChecked, GenericSuccessMsg) 3262 .Case({ReturnValueCondition(WithinRange, SingleValue(0)), 3263 ArgumentCondition(2, WithinRange, SingleValue(0))}, 3264 ErrnoMustNotBeChecked, GenericSuccessMsg) 3265 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3266 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 3267 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 3268 /*BufSize=*/ArgNo(2)))); 3269 3270 // int socketpair(int domain, int type, int protocol, int sv[2]); 3271 addToFunctionSummaryMap( 3272 "socketpair", 3273 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}), 3274 Summary(NoEvalCall) 3275 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3276 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3277 .ArgConstraint(NotNull(ArgNo(3)))); 3278 3279 // int shutdown(int socket, int how); 3280 addToFunctionSummaryMap( 3281 "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 3282 Summary(NoEvalCall) 3283 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3284 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3285 .ArgConstraint( 3286 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3287 3288 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, 3289 // char *restrict node, socklen_t nodelen, 3290 // char *restrict service, 3291 // socklen_t servicelen, int flags); 3292 // 3293 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr 3294 // parameter is never handled as a transparent union in netdb.h 3295 addToFunctionSummaryMap( 3296 "getnameinfo", 3297 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy, 3298 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy, 3299 Socklen_tTy, IntTy}, 3300 RetType{IntTy}), 3301 Summary(NoEvalCall) 3302 .ArgConstraint( 3303 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))) 3304 .ArgConstraint( 3305 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax))) 3306 .ArgConstraint( 3307 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3))) 3308 .ArgConstraint( 3309 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax))) 3310 .ArgConstraint( 3311 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5))) 3312 .ArgConstraint( 3313 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax)))); 3314 3315 std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf"); 3316 std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy); 3317 3318 // int utime(const char *filename, struct utimbuf *buf); 3319 addToFunctionSummaryMap( 3320 "utime", 3321 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}), 3322 Summary(NoEvalCall) 3323 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3324 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3325 .ArgConstraint(NotNull(ArgNo(0)))); 3326 3327 std::optional<QualType> StructTimespecTy = lookupTy("timespec"); 3328 std::optional<QualType> StructTimespecPtrTy = 3329 getPointerTy(StructTimespecTy); 3330 std::optional<QualType> ConstStructTimespecPtrTy = 3331 getPointerTy(getConstTy(StructTimespecTy)); 3332 3333 // int futimens(int fd, const struct timespec times[2]); 3334 addToFunctionSummaryMap( 3335 "futimens", 3336 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}), 3337 Summary(NoEvalCall) 3338 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3339 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3340 .ArgConstraint( 3341 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 3342 3343 // int utimensat(int dirfd, const char *pathname, 3344 // const struct timespec times[2], int flags); 3345 addToFunctionSummaryMap( 3346 "utimensat", 3347 Signature( 3348 ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy}, 3349 RetType{IntTy}), 3350 Summary(NoEvalCall) 3351 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3352 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3353 .ArgConstraint(NotNull(ArgNo(1)))); 3354 3355 std::optional<QualType> StructTimevalTy = lookupTy("timeval"); 3356 std::optional<QualType> ConstStructTimevalPtrTy = 3357 getPointerTy(getConstTy(StructTimevalTy)); 3358 3359 // int utimes(const char *filename, const struct timeval times[2]); 3360 addToFunctionSummaryMap( 3361 "utimes", 3362 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy}, 3363 RetType{IntTy}), 3364 Summary(NoEvalCall) 3365 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3366 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3367 .ArgConstraint(NotNull(ArgNo(0)))); 3368 3369 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); 3370 addToFunctionSummaryMap( 3371 "nanosleep", 3372 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy}, 3373 RetType{IntTy}), 3374 Summary(NoEvalCall) 3375 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3376 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3377 .ArgConstraint(NotNull(ArgNo(0)))); 3378 3379 std::optional<QualType> Time_tTy = lookupTy("time_t"); 3380 std::optional<QualType> ConstTime_tPtrTy = 3381 getPointerTy(getConstTy(Time_tTy)); 3382 std::optional<QualType> ConstTime_tPtrRestrictTy = 3383 getRestrictTy(ConstTime_tPtrTy); 3384 3385 std::optional<QualType> StructTmTy = lookupTy("tm"); 3386 std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy); 3387 std::optional<QualType> StructTmPtrRestrictTy = 3388 getRestrictTy(StructTmPtrTy); 3389 std::optional<QualType> ConstStructTmPtrTy = 3390 getPointerTy(getConstTy(StructTmTy)); 3391 std::optional<QualType> ConstStructTmPtrRestrictTy = 3392 getRestrictTy(ConstStructTmPtrTy); 3393 3394 // struct tm * localtime(const time_t *tp); 3395 addToFunctionSummaryMap( 3396 "localtime", 3397 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 3398 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3399 3400 // struct tm *localtime_r(const time_t *restrict timer, 3401 // struct tm *restrict result); 3402 addToFunctionSummaryMap( 3403 "localtime_r", 3404 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 3405 RetType{StructTmPtrTy}), 3406 Summary(NoEvalCall) 3407 .ArgConstraint(NotNull(ArgNo(0))) 3408 .ArgConstraint(NotNull(ArgNo(1)))); 3409 3410 // char *asctime_r(const struct tm *restrict tm, char *restrict buf); 3411 addToFunctionSummaryMap( 3412 "asctime_r", 3413 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy}, 3414 RetType{CharPtrTy}), 3415 Summary(NoEvalCall) 3416 .ArgConstraint(NotNull(ArgNo(0))) 3417 .ArgConstraint(NotNull(ArgNo(1))) 3418 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 3419 /*MinBufSize=*/BVF.getValue(26, IntTy)))); 3420 3421 // char *ctime_r(const time_t *timep, char *buf); 3422 addToFunctionSummaryMap( 3423 "ctime_r", 3424 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}), 3425 Summary(NoEvalCall) 3426 .ArgConstraint(NotNull(ArgNo(0))) 3427 .ArgConstraint(NotNull(ArgNo(1))) 3428 .ArgConstraint(BufferSize( 3429 /*Buffer=*/ArgNo(1), 3430 /*MinBufSize=*/BVF.getValue(26, IntTy)))); 3431 3432 // struct tm *gmtime_r(const time_t *restrict timer, 3433 // struct tm *restrict result); 3434 addToFunctionSummaryMap( 3435 "gmtime_r", 3436 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 3437 RetType{StructTmPtrTy}), 3438 Summary(NoEvalCall) 3439 .ArgConstraint(NotNull(ArgNo(0))) 3440 .ArgConstraint(NotNull(ArgNo(1)))); 3441 3442 // struct tm * gmtime(const time_t *tp); 3443 addToFunctionSummaryMap( 3444 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 3445 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3446 3447 std::optional<QualType> Clockid_tTy = lookupTy("clockid_t"); 3448 3449 // int clock_gettime(clockid_t clock_id, struct timespec *tp); 3450 addToFunctionSummaryMap( 3451 "clock_gettime", 3452 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}), 3453 Summary(NoEvalCall) 3454 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3455 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3456 .ArgConstraint(NotNull(ArgNo(1)))); 3457 3458 std::optional<QualType> StructItimervalTy = lookupTy("itimerval"); 3459 std::optional<QualType> StructItimervalPtrTy = 3460 getPointerTy(StructItimervalTy); 3461 3462 // int getitimer(int which, struct itimerval *curr_value); 3463 addToFunctionSummaryMap( 3464 "getitimer", 3465 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}), 3466 Summary(NoEvalCall) 3467 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) 3468 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) 3469 .ArgConstraint(NotNull(ArgNo(1)))); 3470 3471 std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t"); 3472 std::optional<QualType> Pthread_cond_tPtrTy = 3473 getPointerTy(Pthread_cond_tTy); 3474 std::optional<QualType> Pthread_tTy = lookupTy("pthread_t"); 3475 std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy); 3476 std::optional<QualType> Pthread_tPtrRestrictTy = 3477 getRestrictTy(Pthread_tPtrTy); 3478 std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t"); 3479 std::optional<QualType> Pthread_mutex_tPtrTy = 3480 getPointerTy(Pthread_mutex_tTy); 3481 std::optional<QualType> Pthread_mutex_tPtrRestrictTy = 3482 getRestrictTy(Pthread_mutex_tPtrTy); 3483 std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t"); 3484 std::optional<QualType> Pthread_attr_tPtrTy = 3485 getPointerTy(Pthread_attr_tTy); 3486 std::optional<QualType> ConstPthread_attr_tPtrTy = 3487 getPointerTy(getConstTy(Pthread_attr_tTy)); 3488 std::optional<QualType> ConstPthread_attr_tPtrRestrictTy = 3489 getRestrictTy(ConstPthread_attr_tPtrTy); 3490 std::optional<QualType> Pthread_mutexattr_tTy = 3491 lookupTy("pthread_mutexattr_t"); 3492 std::optional<QualType> ConstPthread_mutexattr_tPtrTy = 3493 getPointerTy(getConstTy(Pthread_mutexattr_tTy)); 3494 std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy = 3495 getRestrictTy(ConstPthread_mutexattr_tPtrTy); 3496 3497 QualType PthreadStartRoutineTy = getPointerTy( 3498 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy, 3499 FunctionProtoType::ExtProtoInfo())); 3500 3501 // int pthread_cond_signal(pthread_cond_t *cond); 3502 // int pthread_cond_broadcast(pthread_cond_t *cond); 3503 addToFunctionSummaryMap( 3504 {"pthread_cond_signal", "pthread_cond_broadcast"}, 3505 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}), 3506 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3507 3508 // int pthread_create(pthread_t *restrict thread, 3509 // const pthread_attr_t *restrict attr, 3510 // void *(*start_routine)(void*), void *restrict arg); 3511 addToFunctionSummaryMap( 3512 "pthread_create", 3513 Signature(ArgTypes{Pthread_tPtrRestrictTy, 3514 ConstPthread_attr_tPtrRestrictTy, 3515 PthreadStartRoutineTy, VoidPtrRestrictTy}, 3516 RetType{IntTy}), 3517 Summary(NoEvalCall) 3518 .ArgConstraint(NotNull(ArgNo(0))) 3519 .ArgConstraint(NotNull(ArgNo(2)))); 3520 3521 // int pthread_attr_destroy(pthread_attr_t *attr); 3522 // int pthread_attr_init(pthread_attr_t *attr); 3523 addToFunctionSummaryMap( 3524 {"pthread_attr_destroy", "pthread_attr_init"}, 3525 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}), 3526 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3527 3528 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, 3529 // size_t *restrict stacksize); 3530 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, 3531 // size_t *restrict guardsize); 3532 addToFunctionSummaryMap( 3533 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"}, 3534 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy}, 3535 RetType{IntTy}), 3536 Summary(NoEvalCall) 3537 .ArgConstraint(NotNull(ArgNo(0))) 3538 .ArgConstraint(NotNull(ArgNo(1)))); 3539 3540 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); 3541 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); 3542 addToFunctionSummaryMap( 3543 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"}, 3544 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}), 3545 Summary(NoEvalCall) 3546 .ArgConstraint(NotNull(ArgNo(0))) 3547 .ArgConstraint( 3548 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 3549 3550 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const 3551 // pthread_mutexattr_t *restrict attr); 3552 addToFunctionSummaryMap( 3553 "pthread_mutex_init", 3554 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy, 3555 ConstPthread_mutexattr_tPtrRestrictTy}, 3556 RetType{IntTy}), 3557 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3558 3559 // int pthread_mutex_destroy(pthread_mutex_t *mutex); 3560 // int pthread_mutex_lock(pthread_mutex_t *mutex); 3561 // int pthread_mutex_trylock(pthread_mutex_t *mutex); 3562 // int pthread_mutex_unlock(pthread_mutex_t *mutex); 3563 addToFunctionSummaryMap( 3564 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock", 3565 "pthread_mutex_unlock"}, 3566 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}), 3567 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 3568 } 3569 3570 // Functions for testing. 3571 if (AddTestFunctions) { 3572 const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue(); 3573 3574 addToFunctionSummaryMap( 3575 "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}), 3576 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0)))); 3577 3578 addToFunctionSummaryMap( 3579 "__not_null_buffer", 3580 Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}), 3581 Summary(EvalCallAsPure) 3582 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))); 3583 3584 // Test inside range constraints. 3585 addToFunctionSummaryMap( 3586 "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3587 Summary(EvalCallAsPure) 3588 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0)))); 3589 addToFunctionSummaryMap( 3590 "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3591 Summary(EvalCallAsPure) 3592 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))); 3593 addToFunctionSummaryMap( 3594 "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3595 Summary(EvalCallAsPure) 3596 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2)))); 3597 addToFunctionSummaryMap( 3598 "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3599 Summary(EvalCallAsPure) 3600 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1)))); 3601 addToFunctionSummaryMap( 3602 "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3603 Summary(EvalCallAsPure) 3604 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1)))); 3605 addToFunctionSummaryMap( 3606 "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3607 Summary(EvalCallAsPure) 3608 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10)))); 3609 addToFunctionSummaryMap("__range_m1_inf", 3610 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3611 Summary(EvalCallAsPure) 3612 .ArgConstraint(ArgumentCondition( 3613 0U, WithinRange, Range(-1, IntMax)))); 3614 addToFunctionSummaryMap("__range_0_inf", 3615 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3616 Summary(EvalCallAsPure) 3617 .ArgConstraint(ArgumentCondition( 3618 0U, WithinRange, Range(0, IntMax)))); 3619 addToFunctionSummaryMap("__range_1_inf", 3620 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3621 Summary(EvalCallAsPure) 3622 .ArgConstraint(ArgumentCondition( 3623 0U, WithinRange, Range(1, IntMax)))); 3624 addToFunctionSummaryMap("__range_minf_m1", 3625 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3626 Summary(EvalCallAsPure) 3627 .ArgConstraint(ArgumentCondition( 3628 0U, WithinRange, Range(IntMin, -1)))); 3629 addToFunctionSummaryMap("__range_minf_0", 3630 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3631 Summary(EvalCallAsPure) 3632 .ArgConstraint(ArgumentCondition( 3633 0U, WithinRange, Range(IntMin, 0)))); 3634 addToFunctionSummaryMap("__range_minf_1", 3635 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3636 Summary(EvalCallAsPure) 3637 .ArgConstraint(ArgumentCondition( 3638 0U, WithinRange, Range(IntMin, 1)))); 3639 addToFunctionSummaryMap("__range_1_2__4_6", 3640 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3641 Summary(EvalCallAsPure) 3642 .ArgConstraint(ArgumentCondition( 3643 0U, WithinRange, Range({1, 2}, {4, 6})))); 3644 addToFunctionSummaryMap( 3645 "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3646 Summary(EvalCallAsPure) 3647 .ArgConstraint(ArgumentCondition(0U, WithinRange, 3648 Range({1, 2}, {4, IntMax})))); 3649 3650 // Test out of range constraints. 3651 addToFunctionSummaryMap( 3652 "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3653 Summary(EvalCallAsPure) 3654 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0)))); 3655 addToFunctionSummaryMap( 3656 "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3657 Summary(EvalCallAsPure) 3658 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))); 3659 addToFunctionSummaryMap( 3660 "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3661 Summary(EvalCallAsPure) 3662 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2)))); 3663 addToFunctionSummaryMap( 3664 "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3665 Summary(EvalCallAsPure) 3666 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1)))); 3667 addToFunctionSummaryMap( 3668 "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3669 Summary(EvalCallAsPure) 3670 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1)))); 3671 addToFunctionSummaryMap( 3672 "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3673 Summary(EvalCallAsPure) 3674 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10)))); 3675 addToFunctionSummaryMap("__range_out_m1_inf", 3676 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3677 Summary(EvalCallAsPure) 3678 .ArgConstraint(ArgumentCondition( 3679 0U, OutOfRange, Range(-1, IntMax)))); 3680 addToFunctionSummaryMap("__range_out_0_inf", 3681 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3682 Summary(EvalCallAsPure) 3683 .ArgConstraint(ArgumentCondition( 3684 0U, OutOfRange, Range(0, IntMax)))); 3685 addToFunctionSummaryMap("__range_out_1_inf", 3686 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3687 Summary(EvalCallAsPure) 3688 .ArgConstraint(ArgumentCondition( 3689 0U, OutOfRange, Range(1, IntMax)))); 3690 addToFunctionSummaryMap("__range_out_minf_m1", 3691 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3692 Summary(EvalCallAsPure) 3693 .ArgConstraint(ArgumentCondition( 3694 0U, OutOfRange, Range(IntMin, -1)))); 3695 addToFunctionSummaryMap("__range_out_minf_0", 3696 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3697 Summary(EvalCallAsPure) 3698 .ArgConstraint(ArgumentCondition( 3699 0U, OutOfRange, Range(IntMin, 0)))); 3700 addToFunctionSummaryMap("__range_out_minf_1", 3701 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3702 Summary(EvalCallAsPure) 3703 .ArgConstraint(ArgumentCondition( 3704 0U, OutOfRange, Range(IntMin, 1)))); 3705 addToFunctionSummaryMap("__range_out_1_2__4_6", 3706 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3707 Summary(EvalCallAsPure) 3708 .ArgConstraint(ArgumentCondition( 3709 0U, OutOfRange, Range({1, 2}, {4, 6})))); 3710 addToFunctionSummaryMap( 3711 "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3712 Summary(EvalCallAsPure) 3713 .ArgConstraint( 3714 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax})))); 3715 3716 // Test range kind. 3717 addToFunctionSummaryMap( 3718 "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3719 Summary(EvalCallAsPure) 3720 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))); 3721 addToFunctionSummaryMap( 3722 "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3723 Summary(EvalCallAsPure) 3724 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))); 3725 3726 addToFunctionSummaryMap( 3727 "__two_constrained_args", 3728 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 3729 Summary(EvalCallAsPure) 3730 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))) 3731 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1)))); 3732 addToFunctionSummaryMap( 3733 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}), 3734 Summary(EvalCallAsPure) 3735 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))) 3736 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2)))); 3737 addToFunctionSummaryMap( 3738 "__defaultparam", 3739 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}), 3740 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0)))); 3741 addToFunctionSummaryMap( 3742 "__variadic", 3743 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}), 3744 Summary(EvalCallAsPure) 3745 .ArgConstraint(NotNull(ArgNo(0))) 3746 .ArgConstraint(NotNull(ArgNo(1)))); 3747 addToFunctionSummaryMap( 3748 "__buf_size_arg_constraint", 3749 Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}), 3750 Summary(EvalCallAsPure) 3751 .ArgConstraint( 3752 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))); 3753 addToFunctionSummaryMap( 3754 "__buf_size_arg_constraint_mul", 3755 Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}), 3756 Summary(EvalCallAsPure) 3757 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 3758 /*BufSizeMultiplier=*/ArgNo(2)))); 3759 addToFunctionSummaryMap( 3760 "__buf_size_arg_constraint_concrete", 3761 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}), 3762 Summary(EvalCallAsPure) 3763 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), 3764 /*BufSize=*/BVF.getValue(10, IntTy)))); 3765 addToFunctionSummaryMap( 3766 {"__test_restrict_param_0", "__test_restrict_param_1", 3767 "__test_restrict_param_2"}, 3768 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}), 3769 Summary(EvalCallAsPure)); 3770 3771 // Test the application of cases. 3772 addToFunctionSummaryMap( 3773 "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}), 3774 Summary(EvalCallAsPure) 3775 .Case({ReturnValueCondition(WithinRange, SingleValue(0))}, 3776 ErrnoIrrelevant, "Function returns 0") 3777 .Case({ReturnValueCondition(WithinRange, SingleValue(1))}, 3778 ErrnoIrrelevant, "Function returns 1")); 3779 addToFunctionSummaryMap( 3780 "__test_case_range_1_2__4_6", 3781 Signature(ArgTypes{IntTy}, RetType{IntTy}), 3782 Summary(EvalCallAsPure) 3783 .Case({ArgumentCondition(0U, WithinRange, 3784 IntRangeVector{{IntMin, 0}, {3, 3}}), 3785 ReturnValueCondition(WithinRange, SingleValue(1))}, 3786 ErrnoIrrelevant) 3787 .Case({ArgumentCondition(0U, WithinRange, 3788 IntRangeVector{{3, 3}, {7, IntMax}}), 3789 ReturnValueCondition(WithinRange, SingleValue(2))}, 3790 ErrnoIrrelevant) 3791 .Case({ArgumentCondition(0U, WithinRange, 3792 IntRangeVector{{IntMin, 0}, {7, IntMax}}), 3793 ReturnValueCondition(WithinRange, SingleValue(3))}, 3794 ErrnoIrrelevant) 3795 .Case({ArgumentCondition( 3796 0U, WithinRange, 3797 IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}), 3798 ReturnValueCondition(WithinRange, SingleValue(4))}, 3799 ErrnoIrrelevant)); 3800 } 3801 } 3802 3803 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 3804 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>(); 3805 Checker->CheckName = mgr.getCurrentCheckerName(); 3806 const AnalyzerOptions &Opts = mgr.getAnalyzerOptions(); 3807 Checker->DisplayLoadedSummaries = 3808 Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries"); 3809 Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX"); 3810 Checker->ShouldAssumeControlledEnvironment = 3811 Opts.ShouldAssumeControlledEnvironment; 3812 } 3813 3814 bool ento::shouldRegisterStdCLibraryFunctionsChecker( 3815 const CheckerManager &mgr) { 3816 return true; 3817 } 3818 3819 void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) { 3820 auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>(); 3821 Checker->AddTestFunctions = true; 3822 } 3823 3824 bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker( 3825 const CheckerManager &mgr) { 3826 return true; 3827 } 3828