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