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