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