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 // The following standard C functions are currently supported: 42 // 43 // fgetc getline isdigit isupper toascii 44 // fread isalnum isgraph isxdigit 45 // fwrite isalpha islower read 46 // getc isascii isprint write 47 // getchar isblank ispunct toupper 48 // getdelim iscntrl isspace tolower 49 // 50 //===----------------------------------------------------------------------===// 51 52 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 53 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 54 #include "clang/StaticAnalyzer/Core/Checker.h" 55 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 56 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 57 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 58 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" 59 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" 60 61 using namespace clang; 62 using namespace clang::ento; 63 64 namespace { 65 class StdLibraryFunctionsChecker 66 : public Checker<check::PreCall, check::PostCall, eval::Call> { 67 68 class Summary; 69 70 /// Specify how much the analyzer engine should entrust modeling this function 71 /// to us. If he doesn't, he performs additional invalidations. 72 enum InvalidationKind { NoEvalCall, EvalCallAsPure }; 73 74 // The universal integral type to use in value range descriptions. 75 // Unsigned to make sure overflows are well-defined. 76 typedef uint64_t RangeInt; 77 78 /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is 79 /// a non-negative integer, which less than 5 and not equal to 2. For 80 /// `ComparesToArgument', holds information about how exactly to compare to 81 /// the argument. 82 typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector; 83 84 /// A reference to an argument or return value by its number. 85 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but 86 /// obviously uint32_t should be enough for all practical purposes. 87 typedef uint32_t ArgNo; 88 static const ArgNo Ret; 89 90 class ValueConstraint; 91 92 // Pointer to the ValueConstraint. We need a copyable, polymorphic and 93 // default initialize able type (vector needs that). A raw pointer was good, 94 // however, we cannot default initialize that. unique_ptr makes the Summary 95 // class non-copyable, therefore not an option. Releasing the copyability 96 // requirement would render the initialization of the Summary map infeasible. 97 using ValueConstraintPtr = std::shared_ptr<ValueConstraint>; 98 99 /// Polymorphic base class that represents a constraint on a given argument 100 /// (or return value) of a function. Derived classes implement different kind 101 /// of constraints, e.g range constraints or correlation between two 102 /// arguments. 103 class ValueConstraint { 104 public: 105 ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {} 106 virtual ~ValueConstraint() {} 107 /// Apply the effects of the constraint on the given program state. If null 108 /// is returned then the constraint is not feasible. 109 virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 110 const Summary &Summary, 111 CheckerContext &C) const = 0; 112 virtual ValueConstraintPtr negate() const { 113 llvm_unreachable("Not implemented"); 114 }; 115 116 // Check whether the constraint is malformed or not. It is malformed if the 117 // specified argument has a mismatch with the given FunctionDecl (e.g. the 118 // arg number is out-of-range of the function's argument list). 119 bool checkValidity(const FunctionDecl *FD) const { 120 const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams(); 121 assert(ValidArg && "Arg out of range!"); 122 if (!ValidArg) 123 return false; 124 // Subclasses may further refine the validation. 125 return checkSpecificValidity(FD); 126 } 127 ArgNo getArgNo() const { return ArgN; } 128 129 virtual StringRef getName() const = 0; 130 131 protected: 132 ArgNo ArgN; // Argument to which we apply the constraint. 133 134 /// Do polymorphic sanity check on the constraint. 135 virtual bool checkSpecificValidity(const FunctionDecl *FD) const { 136 return true; 137 } 138 }; 139 140 /// Given a range, should the argument stay inside or outside this range? 141 enum RangeKind { OutOfRange, WithinRange }; 142 143 /// Encapsulates a range on a single symbol. 144 class RangeConstraint : public ValueConstraint { 145 RangeKind Kind; 146 // A range is formed as a set of intervals (sub-ranges). 147 // E.g. {['A', 'Z'], ['a', 'z']} 148 // 149 // The default constructed RangeConstraint has an empty range set, applying 150 // such constraint does not involve any assumptions, thus the State remains 151 // unchanged. This is meaningful, if the range is dependent on a looked up 152 // type (e.g. [0, Socklen_tMax]). If the type is not found, then the range 153 // is default initialized to be empty. 154 IntRangeVector Ranges; 155 156 public: 157 StringRef getName() const override { return "Range"; } 158 RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges) 159 : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {} 160 161 const IntRangeVector &getRanges() const { return Ranges; } 162 163 private: 164 ProgramStateRef applyAsOutOfRange(ProgramStateRef State, 165 const CallEvent &Call, 166 const Summary &Summary) const; 167 ProgramStateRef applyAsWithinRange(ProgramStateRef State, 168 const CallEvent &Call, 169 const Summary &Summary) const; 170 171 public: 172 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 173 const Summary &Summary, 174 CheckerContext &C) const override { 175 switch (Kind) { 176 case OutOfRange: 177 return applyAsOutOfRange(State, Call, Summary); 178 case WithinRange: 179 return applyAsWithinRange(State, Call, Summary); 180 } 181 llvm_unreachable("Unknown range kind!"); 182 } 183 184 ValueConstraintPtr negate() const override { 185 RangeConstraint Tmp(*this); 186 switch (Kind) { 187 case OutOfRange: 188 Tmp.Kind = WithinRange; 189 break; 190 case WithinRange: 191 Tmp.Kind = OutOfRange; 192 break; 193 } 194 return std::make_shared<RangeConstraint>(Tmp); 195 } 196 197 bool checkSpecificValidity(const FunctionDecl *FD) const override { 198 const bool ValidArg = 199 getArgType(FD, ArgN)->isIntegralType(FD->getASTContext()); 200 assert(ValidArg && 201 "This constraint should be applied on an integral type"); 202 return ValidArg; 203 } 204 }; 205 206 class ComparisonConstraint : public ValueConstraint { 207 BinaryOperator::Opcode Opcode; 208 ArgNo OtherArgN; 209 210 public: 211 virtual StringRef getName() const override { return "Comparison"; }; 212 ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode, 213 ArgNo OtherArgN) 214 : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {} 215 ArgNo getOtherArgNo() const { return OtherArgN; } 216 BinaryOperator::Opcode getOpcode() const { return Opcode; } 217 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 218 const Summary &Summary, 219 CheckerContext &C) const override; 220 }; 221 222 class NotNullConstraint : public ValueConstraint { 223 using ValueConstraint::ValueConstraint; 224 // This variable has a role when we negate the constraint. 225 bool CannotBeNull = true; 226 227 public: 228 StringRef getName() const override { return "NonNull"; } 229 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 230 const Summary &Summary, 231 CheckerContext &C) const override { 232 SVal V = getArgSVal(Call, getArgNo()); 233 if (V.isUndef()) 234 return State; 235 236 DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>(); 237 if (!L.getAs<Loc>()) 238 return State; 239 240 return State->assume(L, CannotBeNull); 241 } 242 243 ValueConstraintPtr negate() const override { 244 NotNullConstraint Tmp(*this); 245 Tmp.CannotBeNull = !this->CannotBeNull; 246 return std::make_shared<NotNullConstraint>(Tmp); 247 } 248 249 bool checkSpecificValidity(const FunctionDecl *FD) const override { 250 const bool ValidArg = getArgType(FD, ArgN)->isPointerType(); 251 assert(ValidArg && 252 "This constraint should be applied only on a pointer type"); 253 return ValidArg; 254 } 255 }; 256 257 // Represents a buffer argument with an additional size constraint. The 258 // constraint may be a concrete value, or a symbolic value in an argument. 259 // Example 1. Concrete value as the minimum buffer size. 260 // char *asctime_r(const struct tm *restrict tm, char *restrict buf); 261 // // `buf` size must be at least 26 bytes according the POSIX standard. 262 // Example 2. Argument as a buffer size. 263 // ctime_s(char *buffer, rsize_t bufsz, const time_t *time); 264 // Example 3. The size is computed as a multiplication of other args. 265 // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 266 // // Here, ptr is the buffer, and its minimum size is `size * nmemb`. 267 class BufferSizeConstraint : public ValueConstraint { 268 // The concrete value which is the minimum size for the buffer. 269 llvm::Optional<llvm::APSInt> ConcreteSize; 270 // The argument which holds the size of the buffer. 271 llvm::Optional<ArgNo> SizeArgN; 272 // The argument which is a multiplier to size. This is set in case of 273 // `fread` like functions where the size is computed as a multiplication of 274 // two arguments. 275 llvm::Optional<ArgNo> SizeMultiplierArgN; 276 // The operator we use in apply. This is negated in negate(). 277 BinaryOperator::Opcode Op = BO_LE; 278 279 public: 280 StringRef getName() const override { return "BufferSize"; } 281 BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize) 282 : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {} 283 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize) 284 : ValueConstraint(Buffer), SizeArgN(BufSize) {} 285 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier) 286 : ValueConstraint(Buffer), SizeArgN(BufSize), 287 SizeMultiplierArgN(BufSizeMultiplier) {} 288 289 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 290 const Summary &Summary, 291 CheckerContext &C) const override { 292 SValBuilder &SvalBuilder = C.getSValBuilder(); 293 // The buffer argument. 294 SVal BufV = getArgSVal(Call, getArgNo()); 295 296 // Get the size constraint. 297 const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() { 298 if (ConcreteSize) { 299 return SVal(SvalBuilder.makeIntVal(*ConcreteSize)); 300 } else if (SizeArgN) { 301 // The size argument. 302 SVal SizeV = getArgSVal(Call, *SizeArgN); 303 // Multiply with another argument if given. 304 if (SizeMultiplierArgN) { 305 SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN); 306 SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV, 307 Summary.getArgType(*SizeArgN)); 308 } 309 return SizeV; 310 } else { 311 llvm_unreachable("The constraint must be either a concrete value or " 312 "encoded in an arguement."); 313 } 314 }(); 315 316 // The dynamic size of the buffer argument, got from the analyzer engine. 317 SVal BufDynSize = getDynamicSizeWithOffset(State, BufV); 318 319 SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize, 320 SvalBuilder.getContext().BoolTy); 321 if (auto F = Feasible.getAs<DefinedOrUnknownSVal>()) 322 return State->assume(*F, true); 323 324 // We can get here only if the size argument or the dynamic size is 325 // undefined. But the dynamic size should never be undefined, only 326 // unknown. So, here, the size of the argument is undefined, i.e. we 327 // cannot apply the constraint. Actually, other checkers like 328 // CallAndMessage should catch this situation earlier, because we call a 329 // function with an uninitialized argument. 330 llvm_unreachable("Size argument or the dynamic size is Undefined"); 331 } 332 333 ValueConstraintPtr negate() const override { 334 BufferSizeConstraint Tmp(*this); 335 Tmp.Op = BinaryOperator::negateComparisonOp(Op); 336 return std::make_shared<BufferSizeConstraint>(Tmp); 337 } 338 339 bool checkSpecificValidity(const FunctionDecl *FD) const override { 340 const bool ValidArg = getArgType(FD, ArgN)->isPointerType(); 341 assert(ValidArg && 342 "This constraint should be applied only on a pointer type"); 343 return ValidArg; 344 } 345 }; 346 347 /// The complete list of constraints that defines a single branch. 348 typedef std::vector<ValueConstraintPtr> ConstraintSet; 349 350 using ArgTypes = std::vector<Optional<QualType>>; 351 using RetType = Optional<QualType>; 352 353 // A placeholder type, we use it whenever we do not care about the concrete 354 // type in a Signature. 355 const QualType Irrelevant{}; 356 bool static isIrrelevant(QualType T) { return T.isNull(); } 357 358 // The signature of a function we want to describe with a summary. This is a 359 // concessive signature, meaning there may be irrelevant types in the 360 // signature which we do not check against a function with concrete types. 361 // All types in the spec need to be canonical. 362 class Signature { 363 using ArgQualTypes = std::vector<QualType>; 364 ArgQualTypes ArgTys; 365 QualType RetTy; 366 // True if any component type is not found by lookup. 367 bool Invalid = false; 368 369 public: 370 // Construct a signature from optional types. If any of the optional types 371 // are not set then the signature will be invalid. 372 Signature(ArgTypes ArgTys, RetType RetTy) { 373 for (Optional<QualType> Arg : ArgTys) { 374 if (!Arg) { 375 Invalid = true; 376 return; 377 } else { 378 assertArgTypeSuitableForSignature(*Arg); 379 this->ArgTys.push_back(*Arg); 380 } 381 } 382 if (!RetTy) { 383 Invalid = true; 384 return; 385 } else { 386 assertRetTypeSuitableForSignature(*RetTy); 387 this->RetTy = *RetTy; 388 } 389 } 390 391 bool isInvalid() const { return Invalid; } 392 bool matches(const FunctionDecl *FD) const; 393 394 private: 395 static void assertArgTypeSuitableForSignature(QualType T) { 396 assert((T.isNull() || !T->isVoidType()) && 397 "We should have no void types in the spec"); 398 assert((T.isNull() || T.isCanonical()) && 399 "We should only have canonical types in the spec"); 400 } 401 static void assertRetTypeSuitableForSignature(QualType T) { 402 assert((T.isNull() || T.isCanonical()) && 403 "We should only have canonical types in the spec"); 404 } 405 }; 406 407 static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) { 408 assert(FD && "Function must be set"); 409 QualType T = (ArgN == Ret) 410 ? FD->getReturnType().getCanonicalType() 411 : FD->getParamDecl(ArgN)->getType().getCanonicalType(); 412 return T; 413 } 414 415 using Cases = std::vector<ConstraintSet>; 416 417 /// A summary includes information about 418 /// * function prototype (signature) 419 /// * approach to invalidation, 420 /// * a list of branches - a list of list of ranges - 421 /// A branch represents a path in the exploded graph of a function (which 422 /// is a tree). So, a branch is a series of assumptions. In other words, 423 /// branches represent split states and additional assumptions on top of 424 /// the splitting assumption. 425 /// For example, consider the branches in `isalpha(x)` 426 /// Branch 1) 427 /// x is in range ['A', 'Z'] or in ['a', 'z'] 428 /// then the return value is not 0. (I.e. out-of-range [0, 0]) 429 /// Branch 2) 430 /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z'] 431 /// then the return value is 0. 432 /// * a list of argument constraints, that must be true on every branch. 433 /// If these constraints are not satisfied that means a fatal error 434 /// usually resulting in undefined behaviour. 435 /// 436 /// Application of a summary: 437 /// The signature and argument constraints together contain information 438 /// about which functions are handled by the summary. The signature can use 439 /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in 440 /// a signature means that type is not compared to the type of the parameter 441 /// in the found FunctionDecl. Argument constraints may specify additional 442 /// rules for the given parameter's type, those rules are checked once the 443 /// signature is matched. 444 class Summary { 445 const InvalidationKind InvalidationKd; 446 Cases CaseConstraints; 447 ConstraintSet ArgConstraints; 448 449 // The function to which the summary applies. This is set after lookup and 450 // match to the signature. 451 const FunctionDecl *FD = nullptr; 452 453 public: 454 Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {} 455 456 Summary &Case(ConstraintSet &&CS) { 457 CaseConstraints.push_back(std::move(CS)); 458 return *this; 459 } 460 Summary &Case(const ConstraintSet &CS) { 461 CaseConstraints.push_back(CS); 462 return *this; 463 } 464 Summary &ArgConstraint(ValueConstraintPtr VC) { 465 assert(VC->getArgNo() != Ret && 466 "Arg constraint should not refer to the return value"); 467 ArgConstraints.push_back(VC); 468 return *this; 469 } 470 471 InvalidationKind getInvalidationKd() const { return InvalidationKd; } 472 const Cases &getCaseConstraints() const { return CaseConstraints; } 473 const ConstraintSet &getArgConstraints() const { return ArgConstraints; } 474 475 QualType getArgType(ArgNo ArgN) const { 476 return StdLibraryFunctionsChecker::getArgType(FD, ArgN); 477 } 478 479 // Returns true if the summary should be applied to the given function. 480 // And if yes then store the function declaration. 481 bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) { 482 bool Result = Sign.matches(FD) && validateByConstraints(FD); 483 if (Result) { 484 assert(!this->FD && "FD must not be set more than once"); 485 this->FD = FD; 486 } 487 return Result; 488 } 489 490 private: 491 // Once we know the exact type of the function then do sanity check on all 492 // the given constraints. 493 bool validateByConstraints(const FunctionDecl *FD) const { 494 for (const ConstraintSet &Case : CaseConstraints) 495 for (const ValueConstraintPtr &Constraint : Case) 496 if (!Constraint->checkValidity(FD)) 497 return false; 498 for (const ValueConstraintPtr &Constraint : ArgConstraints) 499 if (!Constraint->checkValidity(FD)) 500 return false; 501 return true; 502 } 503 }; 504 505 // The map of all functions supported by the checker. It is initialized 506 // lazily, and it doesn't change after initialization. 507 using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>; 508 mutable FunctionSummaryMapType FunctionSummaryMap; 509 510 mutable std::unique_ptr<BugType> BT_InvalidArg; 511 512 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) { 513 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN); 514 } 515 516 public: 517 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 518 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 519 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 520 521 enum CheckKind { 522 CK_StdCLibraryFunctionArgsChecker, 523 CK_StdCLibraryFunctionsTesterChecker, 524 CK_NumCheckKinds 525 }; 526 DefaultBool ChecksEnabled[CK_NumCheckKinds]; 527 CheckerNameRef CheckNames[CK_NumCheckKinds]; 528 529 bool DisplayLoadedSummaries = false; 530 bool ModelPOSIX = false; 531 532 private: 533 Optional<Summary> findFunctionSummary(const FunctionDecl *FD, 534 CheckerContext &C) const; 535 Optional<Summary> findFunctionSummary(const CallEvent &Call, 536 CheckerContext &C) const; 537 538 void initFunctionSummaries(CheckerContext &C) const; 539 540 void reportBug(const CallEvent &Call, ExplodedNode *N, 541 const ValueConstraint *VC, CheckerContext &C) const { 542 if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker]) 543 return; 544 // TODO Add more detailed diagnostic. 545 std::string Msg = 546 (Twine("Function argument constraint is not satisfied, constraint: ") + 547 VC->getName().data() + ", ArgN: " + Twine(VC->getArgNo())) 548 .str(); 549 if (!BT_InvalidArg) 550 BT_InvalidArg = std::make_unique<BugType>( 551 CheckNames[CK_StdCLibraryFunctionArgsChecker], 552 "Unsatisfied argument constraints", categories::LogicError); 553 auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N); 554 bugreporter::trackExpressionValue(N, Call.getArgExpr(VC->getArgNo()), *R); 555 556 // Highlight the range of the argument that was violated. 557 R->addRange(Call.getArgSourceRange(VC->getArgNo())); 558 559 C.emitReport(std::move(R)); 560 } 561 }; 562 563 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret = 564 std::numeric_limits<ArgNo>::max(); 565 566 } // end of anonymous namespace 567 568 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange( 569 ProgramStateRef State, const CallEvent &Call, 570 const Summary &Summary) const { 571 if (Ranges.empty()) 572 return State; 573 574 ProgramStateManager &Mgr = State->getStateManager(); 575 SValBuilder &SVB = Mgr.getSValBuilder(); 576 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 577 ConstraintManager &CM = Mgr.getConstraintManager(); 578 QualType T = Summary.getArgType(getArgNo()); 579 SVal V = getArgSVal(Call, getArgNo()); 580 581 if (auto N = V.getAs<NonLoc>()) { 582 const IntRangeVector &R = getRanges(); 583 size_t E = R.size(); 584 for (size_t I = 0; I != E; ++I) { 585 const llvm::APSInt &Min = BVF.getValue(R[I].first, T); 586 const llvm::APSInt &Max = BVF.getValue(R[I].second, T); 587 assert(Min <= Max); 588 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 589 if (!State) 590 break; 591 } 592 } 593 594 return State; 595 } 596 597 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange( 598 ProgramStateRef State, const CallEvent &Call, 599 const Summary &Summary) const { 600 if (Ranges.empty()) 601 return State; 602 603 ProgramStateManager &Mgr = State->getStateManager(); 604 SValBuilder &SVB = Mgr.getSValBuilder(); 605 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 606 ConstraintManager &CM = Mgr.getConstraintManager(); 607 QualType T = Summary.getArgType(getArgNo()); 608 SVal V = getArgSVal(Call, getArgNo()); 609 610 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R". 611 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary, 612 // and then cut away all holes in R one by one. 613 // 614 // E.g. consider a range list R as [A, B] and [C, D] 615 // -------+--------+------------------+------------+-----------> 616 // A B C D 617 // Then we assume that the value is not in [-inf, A - 1], 618 // then not in [D + 1, +inf], then not in [B + 1, C - 1] 619 if (auto N = V.getAs<NonLoc>()) { 620 const IntRangeVector &R = getRanges(); 621 size_t E = R.size(); 622 623 const llvm::APSInt &MinusInf = BVF.getMinValue(T); 624 const llvm::APSInt &PlusInf = BVF.getMaxValue(T); 625 626 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T); 627 if (Left != PlusInf) { 628 assert(MinusInf <= Left); 629 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false); 630 if (!State) 631 return nullptr; 632 } 633 634 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T); 635 if (Right != MinusInf) { 636 assert(Right <= PlusInf); 637 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false); 638 if (!State) 639 return nullptr; 640 } 641 642 for (size_t I = 1; I != E; ++I) { 643 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T); 644 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T); 645 if (Min <= Max) { 646 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 647 if (!State) 648 return nullptr; 649 } 650 } 651 } 652 653 return State; 654 } 655 656 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply( 657 ProgramStateRef State, const CallEvent &Call, const Summary &Summary, 658 CheckerContext &C) const { 659 660 ProgramStateManager &Mgr = State->getStateManager(); 661 SValBuilder &SVB = Mgr.getSValBuilder(); 662 QualType CondT = SVB.getConditionType(); 663 QualType T = Summary.getArgType(getArgNo()); 664 SVal V = getArgSVal(Call, getArgNo()); 665 666 BinaryOperator::Opcode Op = getOpcode(); 667 ArgNo OtherArg = getOtherArgNo(); 668 SVal OtherV = getArgSVal(Call, OtherArg); 669 QualType OtherT = Summary.getArgType(OtherArg); 670 // Note: we avoid integral promotion for comparison. 671 OtherV = SVB.evalCast(OtherV, T, OtherT); 672 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT) 673 .getAs<DefinedOrUnknownSVal>()) 674 State = State->assume(*CompV, true); 675 return State; 676 } 677 678 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call, 679 CheckerContext &C) const { 680 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 681 if (!FoundSummary) 682 return; 683 684 const Summary &Summary = *FoundSummary; 685 ProgramStateRef State = C.getState(); 686 687 ProgramStateRef NewState = State; 688 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) { 689 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C); 690 ProgramStateRef FailureSt = 691 Constraint->negate()->apply(NewState, Call, Summary, C); 692 // The argument constraint is not satisfied. 693 if (FailureSt && !SuccessSt) { 694 if (ExplodedNode *N = C.generateErrorNode(NewState)) 695 reportBug(Call, N, Constraint.get(), C); 696 break; 697 } else { 698 // We will apply the constraint even if we cannot reason about the 699 // argument. This means both SuccessSt and FailureSt can be true. If we 700 // weren't applying the constraint that would mean that symbolic 701 // execution continues on a code whose behaviour is undefined. 702 assert(SuccessSt); 703 NewState = SuccessSt; 704 } 705 } 706 if (NewState && NewState != State) 707 C.addTransition(NewState); 708 } 709 710 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, 711 CheckerContext &C) const { 712 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 713 if (!FoundSummary) 714 return; 715 716 // Now apply the constraints. 717 const Summary &Summary = *FoundSummary; 718 ProgramStateRef State = C.getState(); 719 720 // Apply case/branch specifications. 721 for (const ConstraintSet &Case : Summary.getCaseConstraints()) { 722 ProgramStateRef NewState = State; 723 for (const ValueConstraintPtr &Constraint : Case) { 724 NewState = Constraint->apply(NewState, Call, Summary, C); 725 if (!NewState) 726 break; 727 } 728 729 if (NewState && NewState != State) 730 C.addTransition(NewState); 731 } 732 } 733 734 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, 735 CheckerContext &C) const { 736 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 737 if (!FoundSummary) 738 return false; 739 740 const Summary &Summary = *FoundSummary; 741 switch (Summary.getInvalidationKd()) { 742 case EvalCallAsPure: { 743 ProgramStateRef State = C.getState(); 744 const LocationContext *LC = C.getLocationContext(); 745 const auto *CE = cast_or_null<CallExpr>(Call.getOriginExpr()); 746 SVal V = C.getSValBuilder().conjureSymbolVal( 747 CE, LC, CE->getType().getCanonicalType(), C.blockCount()); 748 State = State->BindExpr(CE, LC, V); 749 C.addTransition(State); 750 return true; 751 } 752 case NoEvalCall: 753 // Summary tells us to avoid performing eval::Call. The function is possibly 754 // evaluated by another checker, or evaluated conservatively. 755 return false; 756 } 757 llvm_unreachable("Unknown invalidation kind!"); 758 } 759 760 bool StdLibraryFunctionsChecker::Signature::matches( 761 const FunctionDecl *FD) const { 762 assert(!isInvalid()); 763 // Check the number of arguments. 764 if (FD->param_size() != ArgTys.size()) 765 return false; 766 767 // The "restrict" keyword is illegal in C++, however, many libc 768 // implementations use the "__restrict" compiler intrinsic in functions 769 // prototypes. The "__restrict" keyword qualifies a type as a restricted type 770 // even in C++. 771 // In case of any non-C99 languages, we don't want to match based on the 772 // restrict qualifier because we cannot know if the given libc implementation 773 // qualifies the paramter type or not. 774 auto RemoveRestrict = [&FD](QualType T) { 775 if (!FD->getASTContext().getLangOpts().C99) 776 T.removeLocalRestrict(); 777 return T; 778 }; 779 780 // Check the return type. 781 if (!isIrrelevant(RetTy)) { 782 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType()); 783 if (RetTy != FDRetTy) 784 return false; 785 } 786 787 // Check the argument types. 788 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) { 789 QualType ArgTy = ArgTys[I]; 790 if (isIrrelevant(ArgTy)) 791 continue; 792 QualType FDArgTy = 793 RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType()); 794 if (ArgTy != FDArgTy) 795 return false; 796 } 797 798 return true; 799 } 800 801 Optional<StdLibraryFunctionsChecker::Summary> 802 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, 803 CheckerContext &C) const { 804 if (!FD) 805 return None; 806 807 initFunctionSummaries(C); 808 809 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl()); 810 if (FSMI == FunctionSummaryMap.end()) 811 return None; 812 return FSMI->second; 813 } 814 815 Optional<StdLibraryFunctionsChecker::Summary> 816 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call, 817 CheckerContext &C) const { 818 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 819 if (!FD) 820 return None; 821 return findFunctionSummary(FD, C); 822 } 823 824 void StdLibraryFunctionsChecker::initFunctionSummaries( 825 CheckerContext &C) const { 826 if (!FunctionSummaryMap.empty()) 827 return; 828 829 SValBuilder &SVB = C.getSValBuilder(); 830 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 831 const ASTContext &ACtx = BVF.getContext(); 832 833 // Helper class to lookup a type by its name. 834 class LookupType { 835 const ASTContext &ACtx; 836 837 public: 838 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {} 839 840 // Find the type. If not found then the optional is not set. 841 llvm::Optional<QualType> operator()(StringRef Name) { 842 IdentifierInfo &II = ACtx.Idents.get(Name); 843 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 844 if (LookupRes.size() == 0) 845 return None; 846 847 // Prioritze typedef declarations. 848 // This is needed in case of C struct typedefs. E.g.: 849 // typedef struct FILE FILE; 850 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' 851 // and we have a TypedefDecl with the name 'FILE'. 852 for (Decl *D : LookupRes) 853 if (auto *TD = dyn_cast<TypedefNameDecl>(D)) 854 return ACtx.getTypeDeclType(TD).getCanonicalType(); 855 856 // Find the first TypeDecl. 857 // There maybe cases when a function has the same name as a struct. 858 // E.g. in POSIX: `struct stat` and the function `stat()`: 859 // int stat(const char *restrict path, struct stat *restrict buf); 860 for (Decl *D : LookupRes) 861 if (auto *TD = dyn_cast<TypeDecl>(D)) 862 return ACtx.getTypeDeclType(TD).getCanonicalType(); 863 return None; 864 } 865 } lookupTy(ACtx); 866 867 // Below are auxiliary classes to handle optional types that we get as a 868 // result of the lookup. 869 class GetRestrictTy { 870 const ASTContext &ACtx; 871 872 public: 873 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {} 874 QualType operator()(QualType Ty) { 875 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty; 876 } 877 Optional<QualType> operator()(Optional<QualType> Ty) { 878 if (Ty) 879 return operator()(*Ty); 880 return None; 881 } 882 } getRestrictTy(ACtx); 883 class GetPointerTy { 884 const ASTContext &ACtx; 885 886 public: 887 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {} 888 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); } 889 Optional<QualType> operator()(Optional<QualType> Ty) { 890 if (Ty) 891 return operator()(*Ty); 892 return None; 893 } 894 } getPointerTy(ACtx); 895 class { 896 public: 897 Optional<QualType> operator()(Optional<QualType> Ty) { 898 return Ty ? Optional<QualType>(Ty->withConst()) : None; 899 } 900 QualType operator()(QualType Ty) { return Ty.withConst(); } 901 } getConstTy; 902 class GetMaxValue { 903 BasicValueFactory &BVF; 904 905 public: 906 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {} 907 Optional<RangeInt> operator()(QualType Ty) { 908 return BVF.getMaxValue(Ty).getLimitedValue(); 909 } 910 Optional<RangeInt> operator()(Optional<QualType> Ty) { 911 if (Ty) { 912 return operator()(*Ty); 913 } 914 return None; 915 } 916 } getMaxValue(BVF); 917 918 // These types are useful for writing specifications quickly, 919 // New specifications should probably introduce more types. 920 // Some types are hard to obtain from the AST, eg. "ssize_t". 921 // In such cases it should be possible to provide multiple variants 922 // of function summary for common cases (eg. ssize_t could be int or long 923 // or long long, so three summary variants would be enough). 924 // Of course, function variants are also useful for C++ overloads. 925 const QualType VoidTy = ACtx.VoidTy; 926 const QualType CharTy = ACtx.CharTy; 927 const QualType WCharTy = ACtx.WCharTy; 928 const QualType IntTy = ACtx.IntTy; 929 const QualType UnsignedIntTy = ACtx.UnsignedIntTy; 930 const QualType LongTy = ACtx.LongTy; 931 const QualType SizeTy = ACtx.getSizeType(); 932 933 const QualType VoidPtrTy = getPointerTy(VoidTy); // void * 934 const QualType IntPtrTy = getPointerTy(IntTy); // int * 935 const QualType UnsignedIntPtrTy = 936 getPointerTy(UnsignedIntTy); // unsigned int * 937 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy); 938 const QualType ConstVoidPtrTy = 939 getPointerTy(getConstTy(VoidTy)); // const void * 940 const QualType CharPtrTy = getPointerTy(CharTy); // char * 941 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy); 942 const QualType ConstCharPtrTy = 943 getPointerTy(getConstTy(CharTy)); // const char * 944 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy); 945 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t * 946 const QualType ConstWchar_tPtrTy = 947 getPointerTy(getConstTy(WCharTy)); // const wchar_t * 948 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy); 949 const QualType SizePtrTy = getPointerTy(SizeTy); 950 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy); 951 952 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 953 const RangeInt UnsignedIntMax = 954 BVF.getMaxValue(UnsignedIntTy).getLimitedValue(); 955 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 956 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue(); 957 958 // Set UCharRangeMax to min of int or uchar maximum value. 959 // The C standard states that the arguments of functions like isalpha must 960 // be representable as an unsigned char. Their type is 'int', so the max 961 // value of the argument should be min(UCharMax, IntMax). This just happen 962 // to be true for commonly used and well tested instruction set 963 // architectures, but not for others. 964 const RangeInt UCharRangeMax = 965 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax); 966 967 // The platform dependent value of EOF. 968 // Try our best to parse this from the Preprocessor, otherwise fallback to -1. 969 const auto EOFv = [&C]() -> RangeInt { 970 if (const llvm::Optional<int> OptInt = 971 tryExpandAsInteger("EOF", C.getPreprocessor())) 972 return *OptInt; 973 return -1; 974 }(); 975 976 // Auxiliary class to aid adding summaries to the summary map. 977 struct AddToFunctionSummaryMap { 978 const ASTContext &ACtx; 979 FunctionSummaryMapType ⤅ 980 bool DisplayLoadedSummaries; 981 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM, 982 bool DisplayLoadedSummaries) 983 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) { 984 } 985 986 // Add a summary to a FunctionDecl found by lookup. The lookup is performed 987 // by the given Name, and in the global scope. The summary will be attached 988 // to the found FunctionDecl only if the signatures match. 989 // 990 // Returns true if the summary has been added, false otherwise. 991 bool operator()(StringRef Name, Signature Sign, Summary Sum) { 992 if (Sign.isInvalid()) 993 return false; 994 IdentifierInfo &II = ACtx.Idents.get(Name); 995 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 996 if (LookupRes.size() == 0) 997 return false; 998 for (Decl *D : LookupRes) { 999 if (auto *FD = dyn_cast<FunctionDecl>(D)) { 1000 if (Sum.matchesAndSet(Sign, FD)) { 1001 auto Res = Map.insert({FD->getCanonicalDecl(), Sum}); 1002 assert(Res.second && "Function already has a summary set!"); 1003 (void)Res; 1004 if (DisplayLoadedSummaries) { 1005 llvm::errs() << "Loaded summary for: "; 1006 FD->print(llvm::errs()); 1007 llvm::errs() << "\n"; 1008 } 1009 return true; 1010 } 1011 } 1012 } 1013 return false; 1014 } 1015 // Add the same summary for different names with the Signature explicitly 1016 // given. 1017 void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) { 1018 for (StringRef Name : Names) 1019 operator()(Name, Sign, Sum); 1020 } 1021 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries); 1022 1023 // Below are helpers functions to create the summaries. 1024 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, 1025 IntRangeVector Ranges) { 1026 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges); 1027 }; 1028 auto BufferSize = [](auto... Args) { 1029 return std::make_shared<BufferSizeConstraint>(Args...); 1030 }; 1031 struct { 1032 auto operator()(RangeKind Kind, IntRangeVector Ranges) { 1033 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges); 1034 } 1035 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) { 1036 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN); 1037 } 1038 } ReturnValueCondition; 1039 struct { 1040 auto operator()(RangeInt b, RangeInt e) { 1041 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}}; 1042 } 1043 auto operator()(RangeInt b, Optional<RangeInt> e) { 1044 if (e) 1045 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}}; 1046 return IntRangeVector{}; 1047 } 1048 auto operator()(std::pair<RangeInt, RangeInt> i0, 1049 std::pair<RangeInt, Optional<RangeInt>> i1) { 1050 if (i1.second) 1051 return IntRangeVector{i0, {i1.first, *(i1.second)}}; 1052 return IntRangeVector{i0}; 1053 } 1054 } Range; 1055 auto SingleValue = [](RangeInt v) { 1056 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}}; 1057 }; 1058 auto LessThanOrEq = BO_LE; 1059 auto NotNull = [&](ArgNo ArgN) { 1060 return std::make_shared<NotNullConstraint>(ArgN); 1061 }; 1062 1063 Optional<QualType> FileTy = lookupTy("FILE"); 1064 Optional<QualType> FilePtrTy = getPointerTy(FileTy); 1065 Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy); 1066 1067 // We are finally ready to define specifications for all supported functions. 1068 // 1069 // Argument ranges should always cover all variants. If return value 1070 // is completely unknown, omit it from the respective range set. 1071 // 1072 // Every item in the list of range sets represents a particular 1073 // execution path the analyzer would need to explore once 1074 // the call is modeled - a new program state is constructed 1075 // for every range set, and each range line in the range set 1076 // corresponds to a specific constraint within this state. 1077 1078 // The isascii() family of functions. 1079 // The behavior is undefined if the value of the argument is not 1080 // representable as unsigned char or is not equal to EOF. See e.g. C99 1081 // 7.4.1.2 The isalpha function (p: 181-182). 1082 addToFunctionSummaryMap( 1083 "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1084 Summary(EvalCallAsPure) 1085 // Boils down to isupper() or islower() or isdigit(). 1086 .Case({ArgumentCondition(0U, WithinRange, 1087 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}), 1088 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1089 // The locale-specific range. 1090 // No post-condition. We are completely unaware of 1091 // locale-specific return values. 1092 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1093 .Case( 1094 {ArgumentCondition( 1095 0U, OutOfRange, 1096 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1097 ReturnValueCondition(WithinRange, SingleValue(0))}) 1098 .ArgConstraint(ArgumentCondition( 1099 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1100 addToFunctionSummaryMap( 1101 "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1102 Summary(EvalCallAsPure) 1103 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}), 1104 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1105 // The locale-specific range. 1106 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1107 .Case({ArgumentCondition( 1108 0U, OutOfRange, 1109 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1110 ReturnValueCondition(WithinRange, SingleValue(0))})); 1111 addToFunctionSummaryMap( 1112 "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1113 Summary(EvalCallAsPure) 1114 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1115 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1116 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)), 1117 ReturnValueCondition(WithinRange, SingleValue(0))})); 1118 addToFunctionSummaryMap( 1119 "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1120 Summary(EvalCallAsPure) 1121 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}), 1122 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1123 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}), 1124 ReturnValueCondition(WithinRange, SingleValue(0))})); 1125 addToFunctionSummaryMap( 1126 "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1127 Summary(EvalCallAsPure) 1128 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}), 1129 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1130 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}), 1131 ReturnValueCondition(WithinRange, SingleValue(0))})); 1132 addToFunctionSummaryMap( 1133 "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1134 Summary(EvalCallAsPure) 1135 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')), 1136 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1137 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')), 1138 ReturnValueCondition(WithinRange, SingleValue(0))})); 1139 addToFunctionSummaryMap( 1140 "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1141 Summary(EvalCallAsPure) 1142 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)), 1143 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1144 .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)), 1145 ReturnValueCondition(WithinRange, SingleValue(0))})); 1146 addToFunctionSummaryMap( 1147 "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1148 Summary(EvalCallAsPure) 1149 // Is certainly lowercase. 1150 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')), 1151 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1152 // Is ascii but not lowercase. 1153 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1154 ArgumentCondition(0U, OutOfRange, Range('a', 'z')), 1155 ReturnValueCondition(WithinRange, SingleValue(0))}) 1156 // The locale-specific range. 1157 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1158 // Is not an unsigned char. 1159 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)), 1160 ReturnValueCondition(WithinRange, SingleValue(0))})); 1161 addToFunctionSummaryMap( 1162 "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1163 Summary(EvalCallAsPure) 1164 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)), 1165 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1166 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)), 1167 ReturnValueCondition(WithinRange, SingleValue(0))})); 1168 addToFunctionSummaryMap( 1169 "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1170 Summary(EvalCallAsPure) 1171 .Case({ArgumentCondition( 1172 0U, WithinRange, 1173 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1174 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1175 .Case({ArgumentCondition( 1176 0U, OutOfRange, 1177 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1178 ReturnValueCondition(WithinRange, SingleValue(0))})); 1179 addToFunctionSummaryMap( 1180 "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1181 Summary(EvalCallAsPure) 1182 // Space, '\f', '\n', '\r', '\t', '\v'. 1183 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}), 1184 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1185 // The locale-specific range. 1186 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1187 .Case({ArgumentCondition(0U, OutOfRange, 1188 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}), 1189 ReturnValueCondition(WithinRange, SingleValue(0))})); 1190 addToFunctionSummaryMap( 1191 "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1192 Summary(EvalCallAsPure) 1193 // Is certainly uppercase. 1194 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')), 1195 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1196 // The locale-specific range. 1197 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1198 // Other. 1199 .Case({ArgumentCondition(0U, OutOfRange, 1200 {{'A', 'Z'}, {128, UCharRangeMax}}), 1201 ReturnValueCondition(WithinRange, SingleValue(0))})); 1202 addToFunctionSummaryMap( 1203 "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1204 Summary(EvalCallAsPure) 1205 .Case({ArgumentCondition(0U, WithinRange, 1206 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1207 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1208 .Case({ArgumentCondition(0U, OutOfRange, 1209 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1210 ReturnValueCondition(WithinRange, SingleValue(0))})); 1211 addToFunctionSummaryMap( 1212 "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1213 Summary(EvalCallAsPure) 1214 .ArgConstraint(ArgumentCondition( 1215 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1216 addToFunctionSummaryMap( 1217 "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1218 Summary(EvalCallAsPure) 1219 .ArgConstraint(ArgumentCondition( 1220 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1221 addToFunctionSummaryMap( 1222 "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1223 Summary(EvalCallAsPure) 1224 .ArgConstraint(ArgumentCondition( 1225 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1226 1227 // The getc() family of functions that returns either a char or an EOF. 1228 addToFunctionSummaryMap( 1229 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1230 Summary(NoEvalCall) 1231 .Case({ReturnValueCondition(WithinRange, 1232 {{EOFv, EOFv}, {0, UCharRangeMax}})})); 1233 addToFunctionSummaryMap( 1234 "getchar", Signature(ArgTypes{}, RetType{IntTy}), 1235 Summary(NoEvalCall) 1236 .Case({ReturnValueCondition(WithinRange, 1237 {{EOFv, EOFv}, {0, UCharRangeMax}})})); 1238 1239 // read()-like functions that never return more than buffer size. 1240 auto FreadSummary = 1241 Summary(NoEvalCall) 1242 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1243 ReturnValueCondition(WithinRange, Range(0, SizeMax))}) 1244 .ArgConstraint(NotNull(ArgNo(0))) 1245 .ArgConstraint(NotNull(ArgNo(3))) 1246 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 1247 /*BufSizeMultiplier=*/ArgNo(2))); 1248 1249 // size_t fread(void *restrict ptr, size_t size, size_t nitems, 1250 // FILE *restrict stream); 1251 addToFunctionSummaryMap( 1252 "fread", 1253 Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy}, 1254 RetType{SizeTy}), 1255 FreadSummary); 1256 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, 1257 // FILE *restrict stream); 1258 addToFunctionSummaryMap("fwrite", 1259 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, 1260 SizeTy, FilePtrRestrictTy}, 1261 RetType{SizeTy}), 1262 FreadSummary); 1263 1264 Optional<QualType> Ssize_tTy = lookupTy("ssize_t"); 1265 Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy); 1266 1267 auto ReadSummary = 1268 Summary(NoEvalCall) 1269 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1270 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}); 1271 1272 // FIXME these are actually defined by POSIX and not by the C standard, we 1273 // should handle them together with the rest of the POSIX functions. 1274 // ssize_t read(int fildes, void *buf, size_t nbyte); 1275 addToFunctionSummaryMap( 1276 "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}), 1277 ReadSummary); 1278 // ssize_t write(int fildes, const void *buf, size_t nbyte); 1279 addToFunctionSummaryMap( 1280 "write", 1281 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}), 1282 ReadSummary); 1283 1284 auto GetLineSummary = 1285 Summary(NoEvalCall) 1286 .Case({ReturnValueCondition(WithinRange, 1287 Range({-1, -1}, {1, Ssize_tMax}))}); 1288 1289 QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy)); 1290 1291 // getline()-like functions either fail or read at least the delimiter. 1292 // FIXME these are actually defined by POSIX and not by the C standard, we 1293 // should handle them together with the rest of the POSIX functions. 1294 // ssize_t getline(char **restrict lineptr, size_t *restrict n, 1295 // FILE *restrict stream); 1296 addToFunctionSummaryMap( 1297 "getline", 1298 Signature( 1299 ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy}, 1300 RetType{Ssize_tTy}), 1301 GetLineSummary); 1302 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n, 1303 // int delimiter, FILE *restrict stream); 1304 addToFunctionSummaryMap( 1305 "getdelim", 1306 Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy, 1307 FilePtrRestrictTy}, 1308 RetType{Ssize_tTy}), 1309 GetLineSummary); 1310 1311 if (ModelPOSIX) { 1312 1313 // long a64l(const char *str64); 1314 addToFunctionSummaryMap( 1315 "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}), 1316 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1317 1318 // char *l64a(long value); 1319 addToFunctionSummaryMap("l64a", 1320 Signature(ArgTypes{LongTy}, RetType{CharPtrTy}), 1321 Summary(NoEvalCall) 1322 .ArgConstraint(ArgumentCondition( 1323 0, WithinRange, Range(0, LongMax)))); 1324 1325 // int access(const char *pathname, int amode); 1326 addToFunctionSummaryMap( 1327 "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}), 1328 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1329 1330 // int faccessat(int dirfd, const char *pathname, int mode, int flags); 1331 addToFunctionSummaryMap( 1332 "faccessat", 1333 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy}, 1334 RetType{IntTy}), 1335 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 1336 1337 // int dup(int fildes); 1338 addToFunctionSummaryMap("dup", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1339 Summary(NoEvalCall) 1340 .ArgConstraint(ArgumentCondition( 1341 0, WithinRange, Range(0, IntMax)))); 1342 1343 // int dup2(int fildes1, int filedes2); 1344 addToFunctionSummaryMap( 1345 "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 1346 Summary(NoEvalCall) 1347 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1348 .ArgConstraint( 1349 ArgumentCondition(1, WithinRange, Range(0, IntMax)))); 1350 1351 // int fdatasync(int fildes); 1352 addToFunctionSummaryMap("fdatasync", 1353 Signature(ArgTypes{IntTy}, RetType{IntTy}), 1354 Summary(NoEvalCall) 1355 .ArgConstraint(ArgumentCondition( 1356 0, WithinRange, Range(0, IntMax)))); 1357 1358 // int fnmatch(const char *pattern, const char *string, int flags); 1359 addToFunctionSummaryMap( 1360 "fnmatch", 1361 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy}, 1362 RetType{IntTy}), 1363 Summary(EvalCallAsPure) 1364 .ArgConstraint(NotNull(ArgNo(0))) 1365 .ArgConstraint(NotNull(ArgNo(1)))); 1366 1367 // int fsync(int fildes); 1368 addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1369 Summary(NoEvalCall) 1370 .ArgConstraint(ArgumentCondition( 1371 0, WithinRange, Range(0, IntMax)))); 1372 1373 Optional<QualType> Off_tTy = lookupTy("off_t"); 1374 1375 // int truncate(const char *path, off_t length); 1376 addToFunctionSummaryMap( 1377 "truncate", 1378 Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}), 1379 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1380 1381 // int symlink(const char *oldpath, const char *newpath); 1382 addToFunctionSummaryMap( 1383 "symlink", 1384 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}), 1385 Summary(NoEvalCall) 1386 .ArgConstraint(NotNull(ArgNo(0))) 1387 .ArgConstraint(NotNull(ArgNo(1)))); 1388 1389 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath); 1390 addToFunctionSummaryMap( 1391 "symlinkat", 1392 Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, 1393 RetType{IntTy}), 1394 Summary(NoEvalCall) 1395 .ArgConstraint(NotNull(ArgNo(0))) 1396 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax))) 1397 .ArgConstraint(NotNull(ArgNo(2)))); 1398 1399 // int lockf(int fd, int cmd, off_t len); 1400 addToFunctionSummaryMap( 1401 "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}), 1402 Summary(NoEvalCall) 1403 .ArgConstraint( 1404 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1405 1406 Optional<QualType> Mode_tTy = lookupTy("mode_t"); 1407 1408 // int creat(const char *pathname, mode_t mode); 1409 addToFunctionSummaryMap( 1410 "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1411 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1412 1413 // unsigned int sleep(unsigned int seconds); 1414 addToFunctionSummaryMap( 1415 "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}), 1416 Summary(NoEvalCall) 1417 .ArgConstraint( 1418 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1419 1420 Optional<QualType> DirTy = lookupTy("DIR"); 1421 Optional<QualType> DirPtrTy = getPointerTy(DirTy); 1422 1423 // int dirfd(DIR *dirp); 1424 addToFunctionSummaryMap( 1425 "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}), 1426 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1427 1428 // unsigned int alarm(unsigned int seconds); 1429 addToFunctionSummaryMap( 1430 "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}), 1431 Summary(NoEvalCall) 1432 .ArgConstraint( 1433 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1434 1435 // int closedir(DIR *dir); 1436 addToFunctionSummaryMap( 1437 "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}), 1438 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1439 1440 // char *strdup(const char *s); 1441 addToFunctionSummaryMap( 1442 "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}), 1443 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1444 1445 // char *strndup(const char *s, size_t n); 1446 addToFunctionSummaryMap( 1447 "strndup", 1448 Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}), 1449 Summary(NoEvalCall) 1450 .ArgConstraint(NotNull(ArgNo(0))) 1451 .ArgConstraint( 1452 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 1453 1454 // wchar_t *wcsdup(const wchar_t *s); 1455 addToFunctionSummaryMap( 1456 "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}), 1457 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1458 1459 // int mkstemp(char *template); 1460 addToFunctionSummaryMap( 1461 "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}), 1462 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1463 1464 // char *mkdtemp(char *template); 1465 addToFunctionSummaryMap( 1466 "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}), 1467 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1468 1469 // char *getcwd(char *buf, size_t size); 1470 addToFunctionSummaryMap( 1471 "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}), 1472 Summary(NoEvalCall) 1473 .ArgConstraint( 1474 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 1475 1476 // int mkdir(const char *pathname, mode_t mode); 1477 addToFunctionSummaryMap( 1478 "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1479 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1480 1481 // int mkdirat(int dirfd, const char *pathname, mode_t mode); 1482 addToFunctionSummaryMap( 1483 "mkdirat", 1484 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1485 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 1486 1487 Optional<QualType> Dev_tTy = lookupTy("dev_t"); 1488 1489 // int mknod(const char *pathname, mode_t mode, dev_t dev); 1490 addToFunctionSummaryMap( 1491 "mknod", 1492 Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}), 1493 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1494 1495 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); 1496 addToFunctionSummaryMap( 1497 "mknodat", 1498 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy}, 1499 RetType{IntTy}), 1500 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 1501 1502 // int chmod(const char *path, mode_t mode); 1503 addToFunctionSummaryMap( 1504 "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}), 1505 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1506 1507 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); 1508 addToFunctionSummaryMap( 1509 "fchmodat", 1510 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy}, 1511 RetType{IntTy}), 1512 Summary(NoEvalCall) 1513 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1514 .ArgConstraint(NotNull(ArgNo(1)))); 1515 1516 // int fchmod(int fildes, mode_t mode); 1517 addToFunctionSummaryMap( 1518 "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}), 1519 Summary(NoEvalCall) 1520 .ArgConstraint( 1521 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1522 1523 Optional<QualType> Uid_tTy = lookupTy("uid_t"); 1524 Optional<QualType> Gid_tTy = lookupTy("gid_t"); 1525 1526 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, 1527 // int flags); 1528 addToFunctionSummaryMap( 1529 "fchownat", 1530 Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy}, 1531 RetType{IntTy}), 1532 Summary(NoEvalCall) 1533 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1534 .ArgConstraint(NotNull(ArgNo(1)))); 1535 1536 // int chown(const char *path, uid_t owner, gid_t group); 1537 addToFunctionSummaryMap( 1538 "chown", 1539 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1540 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1541 1542 // int lchown(const char *path, uid_t owner, gid_t group); 1543 addToFunctionSummaryMap( 1544 "lchown", 1545 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1546 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1547 1548 // int fchown(int fildes, uid_t owner, gid_t group); 1549 addToFunctionSummaryMap( 1550 "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}), 1551 Summary(NoEvalCall) 1552 .ArgConstraint( 1553 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1554 1555 // int rmdir(const char *pathname); 1556 addToFunctionSummaryMap( 1557 "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1558 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1559 1560 // int chdir(const char *path); 1561 addToFunctionSummaryMap( 1562 "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1563 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1564 1565 // int link(const char *oldpath, const char *newpath); 1566 addToFunctionSummaryMap( 1567 "link", 1568 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}), 1569 Summary(NoEvalCall) 1570 .ArgConstraint(NotNull(ArgNo(0))) 1571 .ArgConstraint(NotNull(ArgNo(1)))); 1572 1573 // int linkat(int fd1, const char *path1, int fd2, const char *path2, 1574 // int flag); 1575 addToFunctionSummaryMap( 1576 "linkat", 1577 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy}, 1578 RetType{IntTy}), 1579 Summary(NoEvalCall) 1580 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1581 .ArgConstraint(NotNull(ArgNo(1))) 1582 .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax))) 1583 .ArgConstraint(NotNull(ArgNo(3)))); 1584 1585 // int unlink(const char *pathname); 1586 addToFunctionSummaryMap( 1587 "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}), 1588 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1589 1590 // int unlinkat(int fd, const char *path, int flag); 1591 addToFunctionSummaryMap( 1592 "unlinkat", 1593 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}), 1594 Summary(NoEvalCall) 1595 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1596 .ArgConstraint(NotNull(ArgNo(1)))); 1597 1598 Optional<QualType> StructStatTy = lookupTy("stat"); 1599 Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy); 1600 Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy); 1601 1602 // int fstat(int fd, struct stat *statbuf); 1603 addToFunctionSummaryMap( 1604 "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}), 1605 Summary(NoEvalCall) 1606 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1607 .ArgConstraint(NotNull(ArgNo(1)))); 1608 1609 // int stat(const char *restrict path, struct stat *restrict buf); 1610 addToFunctionSummaryMap( 1611 "stat", 1612 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy}, 1613 RetType{IntTy}), 1614 Summary(NoEvalCall) 1615 .ArgConstraint(NotNull(ArgNo(0))) 1616 .ArgConstraint(NotNull(ArgNo(1)))); 1617 1618 // int lstat(const char *restrict path, struct stat *restrict buf); 1619 addToFunctionSummaryMap( 1620 "lstat", 1621 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy}, 1622 RetType{IntTy}), 1623 Summary(NoEvalCall) 1624 .ArgConstraint(NotNull(ArgNo(0))) 1625 .ArgConstraint(NotNull(ArgNo(1)))); 1626 1627 // int fstatat(int fd, const char *restrict path, 1628 // struct stat *restrict buf, int flag); 1629 addToFunctionSummaryMap( 1630 "fstatat", 1631 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy, 1632 StructStatPtrRestrictTy, IntTy}, 1633 RetType{IntTy}), 1634 Summary(NoEvalCall) 1635 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1636 .ArgConstraint(NotNull(ArgNo(1))) 1637 .ArgConstraint(NotNull(ArgNo(2)))); 1638 1639 // DIR *opendir(const char *name); 1640 addToFunctionSummaryMap( 1641 "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}), 1642 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1643 1644 // DIR *fdopendir(int fd); 1645 addToFunctionSummaryMap("fdopendir", 1646 Signature(ArgTypes{IntTy}, RetType{DirPtrTy}), 1647 Summary(NoEvalCall) 1648 .ArgConstraint(ArgumentCondition( 1649 0, WithinRange, Range(0, IntMax)))); 1650 1651 // int isatty(int fildes); 1652 addToFunctionSummaryMap("isatty", 1653 Signature(ArgTypes{IntTy}, RetType{IntTy}), 1654 Summary(NoEvalCall) 1655 .ArgConstraint(ArgumentCondition( 1656 0, WithinRange, Range(0, IntMax)))); 1657 1658 // FILE *popen(const char *command, const char *type); 1659 addToFunctionSummaryMap( 1660 "popen", 1661 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}), 1662 Summary(NoEvalCall) 1663 .ArgConstraint(NotNull(ArgNo(0))) 1664 .ArgConstraint(NotNull(ArgNo(1)))); 1665 1666 // int pclose(FILE *stream); 1667 addToFunctionSummaryMap( 1668 "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1669 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1670 1671 // int close(int fildes); 1672 addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}), 1673 Summary(NoEvalCall) 1674 .ArgConstraint(ArgumentCondition( 1675 0, WithinRange, Range(0, IntMax)))); 1676 1677 // long fpathconf(int fildes, int name); 1678 addToFunctionSummaryMap("fpathconf", 1679 Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}), 1680 Summary(NoEvalCall) 1681 .ArgConstraint(ArgumentCondition( 1682 0, WithinRange, Range(0, IntMax)))); 1683 1684 // long pathconf(const char *path, int name); 1685 addToFunctionSummaryMap( 1686 "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}), 1687 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1688 1689 // FILE *fdopen(int fd, const char *mode); 1690 addToFunctionSummaryMap( 1691 "fdopen", 1692 Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}), 1693 Summary(NoEvalCall) 1694 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1695 .ArgConstraint(NotNull(ArgNo(1)))); 1696 1697 // void rewinddir(DIR *dir); 1698 addToFunctionSummaryMap( 1699 "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}), 1700 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1701 1702 // void seekdir(DIR *dirp, long loc); 1703 addToFunctionSummaryMap( 1704 "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}), 1705 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1706 1707 // int rand_r(unsigned int *seedp); 1708 addToFunctionSummaryMap( 1709 "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}), 1710 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1711 1712 // int fileno(FILE *stream); 1713 addToFunctionSummaryMap( 1714 "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), 1715 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1716 1717 // int fseeko(FILE *stream, off_t offset, int whence); 1718 addToFunctionSummaryMap( 1719 "fseeko", 1720 Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}), 1721 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1722 1723 // off_t ftello(FILE *stream); 1724 addToFunctionSummaryMap( 1725 "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}), 1726 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1727 1728 // void *mmap(void *addr, size_t length, int prot, int flags, int fd, 1729 // off_t offset); 1730 addToFunctionSummaryMap( 1731 "mmap", 1732 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy}, 1733 RetType{VoidPtrTy}), 1734 Summary(NoEvalCall) 1735 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1736 .ArgConstraint( 1737 ArgumentCondition(4, WithinRange, Range(0, IntMax)))); 1738 1739 Optional<QualType> Off64_tTy = lookupTy("off64_t"); 1740 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, 1741 // off64_t offset); 1742 addToFunctionSummaryMap( 1743 "mmap64", 1744 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy}, 1745 RetType{VoidPtrTy}), 1746 Summary(NoEvalCall) 1747 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1748 .ArgConstraint( 1749 ArgumentCondition(4, WithinRange, Range(0, IntMax)))); 1750 1751 // int pipe(int fildes[2]); 1752 addToFunctionSummaryMap( 1753 "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}), 1754 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1755 1756 // off_t lseek(int fildes, off_t offset, int whence); 1757 addToFunctionSummaryMap( 1758 "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}), 1759 Summary(NoEvalCall) 1760 .ArgConstraint( 1761 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1762 1763 // ssize_t readlink(const char *restrict path, char *restrict buf, 1764 // size_t bufsize); 1765 addToFunctionSummaryMap( 1766 "readlink", 1767 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1768 RetType{Ssize_tTy}), 1769 Summary(NoEvalCall) 1770 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1771 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 1772 .ArgConstraint(NotNull(ArgNo(0))) 1773 .ArgConstraint(NotNull(ArgNo(1))) 1774 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1775 /*BufSize=*/ArgNo(2))) 1776 .ArgConstraint( 1777 ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); 1778 1779 // ssize_t readlinkat(int fd, const char *restrict path, 1780 // char *restrict buf, size_t bufsize); 1781 addToFunctionSummaryMap( 1782 "readlinkat", 1783 Signature( 1784 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1785 RetType{Ssize_tTy}), 1786 Summary(NoEvalCall) 1787 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)), 1788 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 1789 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1790 .ArgConstraint(NotNull(ArgNo(1))) 1791 .ArgConstraint(NotNull(ArgNo(2))) 1792 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), 1793 /*BufSize=*/ArgNo(3))) 1794 .ArgConstraint( 1795 ArgumentCondition(3, WithinRange, Range(0, SizeMax)))); 1796 1797 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char 1798 // *newpath); 1799 addToFunctionSummaryMap( 1800 "renameat", 1801 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy}, 1802 RetType{IntTy}), 1803 Summary(NoEvalCall) 1804 .ArgConstraint(NotNull(ArgNo(1))) 1805 .ArgConstraint(NotNull(ArgNo(3)))); 1806 1807 // char *realpath(const char *restrict file_name, 1808 // char *restrict resolved_name); 1809 addToFunctionSummaryMap( 1810 "realpath", 1811 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy}, 1812 RetType{CharPtrTy}), 1813 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1814 1815 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy)); 1816 1817 // int execv(const char *path, char *const argv[]); 1818 addToFunctionSummaryMap( 1819 "execv", 1820 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 1821 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1822 1823 // int execvp(const char *file, char *const argv[]); 1824 addToFunctionSummaryMap( 1825 "execvp", 1826 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}), 1827 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 1828 1829 // int getopt(int argc, char * const argv[], const char *optstring); 1830 addToFunctionSummaryMap( 1831 "getopt", 1832 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy}, 1833 RetType{IntTy}), 1834 Summary(NoEvalCall) 1835 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1836 .ArgConstraint(NotNull(ArgNo(1))) 1837 .ArgConstraint(NotNull(ArgNo(2)))); 1838 1839 Optional<QualType> StructSockaddrTy = lookupTy("sockaddr"); 1840 Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy); 1841 Optional<QualType> ConstStructSockaddrPtrTy = 1842 getPointerTy(getConstTy(StructSockaddrTy)); 1843 Optional<QualType> StructSockaddrPtrRestrictTy = 1844 getRestrictTy(StructSockaddrPtrTy); 1845 Optional<QualType> ConstStructSockaddrPtrRestrictTy = 1846 getRestrictTy(ConstStructSockaddrPtrTy); 1847 Optional<QualType> Socklen_tTy = lookupTy("socklen_t"); 1848 Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy); 1849 Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy); 1850 Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy); 1851 1852 const auto ReturnsZeroOrMinusOne = 1853 ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))}; 1854 1855 // In 'socket.h' of some libc implementations with C99, sockaddr parameter 1856 // is a transparent union of the underlying sockaddr_ family of pointers 1857 // instead of being a pointer to struct sockaddr. In these cases, the 1858 // standardized signature will not match, thus we try to match with another 1859 // signature that has the joker Irrelevant type. We also remove those 1860 // constraints which require pointer types for the sockaddr param. 1861 auto Accept = 1862 Summary(NoEvalCall) 1863 .Case({ReturnValueCondition(WithinRange, Range(-1, IntMax))}) 1864 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))); 1865 if (!addToFunctionSummaryMap( 1866 "accept", 1867 // int accept(int socket, struct sockaddr *restrict address, 1868 // socklen_t *restrict address_len); 1869 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1870 Socklen_tPtrRestrictTy}, 1871 RetType{IntTy}), 1872 Accept)) 1873 addToFunctionSummaryMap( 1874 "accept", 1875 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1876 RetType{IntTy}), 1877 Accept); 1878 1879 // int bind(int socket, const struct sockaddr *address, socklen_t 1880 // address_len); 1881 if (!addToFunctionSummaryMap( 1882 "bind", 1883 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 1884 RetType{IntTy}), 1885 Summary(NoEvalCall) 1886 .Case(ReturnsZeroOrMinusOne) 1887 .ArgConstraint( 1888 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1889 .ArgConstraint(NotNull(ArgNo(1))) 1890 .ArgConstraint( 1891 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2))) 1892 .ArgConstraint( 1893 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))))) 1894 // Do not add constraints on sockaddr. 1895 addToFunctionSummaryMap( 1896 "bind", 1897 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 1898 Summary(NoEvalCall) 1899 .Case(ReturnsZeroOrMinusOne) 1900 .ArgConstraint( 1901 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1902 .ArgConstraint( 1903 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))); 1904 1905 // int getpeername(int socket, struct sockaddr *restrict address, 1906 // socklen_t *restrict address_len); 1907 if (!addToFunctionSummaryMap( 1908 "getpeername", 1909 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1910 Socklen_tPtrRestrictTy}, 1911 RetType{IntTy}), 1912 Summary(NoEvalCall) 1913 .Case(ReturnsZeroOrMinusOne) 1914 .ArgConstraint( 1915 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1916 .ArgConstraint(NotNull(ArgNo(1))) 1917 .ArgConstraint(NotNull(ArgNo(2))))) 1918 addToFunctionSummaryMap( 1919 "getpeername", 1920 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1921 RetType{IntTy}), 1922 Summary(NoEvalCall) 1923 .Case(ReturnsZeroOrMinusOne) 1924 .ArgConstraint( 1925 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1926 1927 // int getsockname(int socket, struct sockaddr *restrict address, 1928 // socklen_t *restrict address_len); 1929 if (!addToFunctionSummaryMap( 1930 "getsockname", 1931 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1932 Socklen_tPtrRestrictTy}, 1933 RetType{IntTy}), 1934 Summary(NoEvalCall) 1935 .Case(ReturnsZeroOrMinusOne) 1936 .ArgConstraint( 1937 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1938 .ArgConstraint(NotNull(ArgNo(1))) 1939 .ArgConstraint(NotNull(ArgNo(2))))) 1940 addToFunctionSummaryMap( 1941 "getsockname", 1942 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1943 RetType{IntTy}), 1944 Summary(NoEvalCall) 1945 .Case(ReturnsZeroOrMinusOne) 1946 .ArgConstraint( 1947 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1948 1949 // int connect(int socket, const struct sockaddr *address, socklen_t 1950 // address_len); 1951 if (!addToFunctionSummaryMap( 1952 "connect", 1953 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 1954 RetType{IntTy}), 1955 Summary(NoEvalCall) 1956 .Case(ReturnsZeroOrMinusOne) 1957 .ArgConstraint( 1958 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1959 .ArgConstraint(NotNull(ArgNo(1))))) 1960 addToFunctionSummaryMap( 1961 "connect", 1962 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}), 1963 Summary(NoEvalCall) 1964 .Case(ReturnsZeroOrMinusOne) 1965 .ArgConstraint( 1966 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1967 1968 auto Recvfrom = 1969 Summary(NoEvalCall) 1970 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1971 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 1972 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1973 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1974 /*BufSize=*/ArgNo(2))); 1975 if (!addToFunctionSummaryMap( 1976 "recvfrom", 1977 // ssize_t recvfrom(int socket, void *restrict buffer, 1978 // size_t length, 1979 // int flags, struct sockaddr *restrict address, 1980 // socklen_t *restrict address_len); 1981 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 1982 StructSockaddrPtrRestrictTy, 1983 Socklen_tPtrRestrictTy}, 1984 RetType{Ssize_tTy}), 1985 Recvfrom)) 1986 addToFunctionSummaryMap( 1987 "recvfrom", 1988 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 1989 Irrelevant, Socklen_tPtrRestrictTy}, 1990 RetType{Ssize_tTy}), 1991 Recvfrom); 1992 1993 auto Sendto = 1994 Summary(NoEvalCall) 1995 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1996 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 1997 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1998 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1999 /*BufSize=*/ArgNo(2))); 2000 if (!addToFunctionSummaryMap( 2001 "sendto", 2002 // ssize_t sendto(int socket, const void *message, size_t length, 2003 // int flags, const struct sockaddr *dest_addr, 2004 // socklen_t dest_len); 2005 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, 2006 ConstStructSockaddrPtrTy, Socklen_tTy}, 2007 RetType{Ssize_tTy}), 2008 Sendto)) 2009 addToFunctionSummaryMap( 2010 "sendto", 2011 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant, 2012 Socklen_tTy}, 2013 RetType{Ssize_tTy}), 2014 Sendto); 2015 2016 // int listen(int sockfd, int backlog); 2017 addToFunctionSummaryMap("listen", 2018 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 2019 Summary(NoEvalCall) 2020 .Case(ReturnsZeroOrMinusOne) 2021 .ArgConstraint(ArgumentCondition( 2022 0, WithinRange, Range(0, IntMax)))); 2023 2024 // ssize_t recv(int sockfd, void *buf, size_t len, int flags); 2025 addToFunctionSummaryMap( 2026 "recv", 2027 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, 2028 RetType{Ssize_tTy}), 2029 Summary(NoEvalCall) 2030 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2031 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2032 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2033 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2034 /*BufSize=*/ArgNo(2)))); 2035 2036 Optional<QualType> StructMsghdrTy = lookupTy("msghdr"); 2037 Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy); 2038 Optional<QualType> ConstStructMsghdrPtrTy = 2039 getPointerTy(getConstTy(StructMsghdrTy)); 2040 2041 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 2042 addToFunctionSummaryMap( 2043 "recvmsg", 2044 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy}, 2045 RetType{Ssize_tTy}), 2046 Summary(NoEvalCall) 2047 .Case({ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2048 .ArgConstraint( 2049 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2050 2051 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 2052 addToFunctionSummaryMap( 2053 "sendmsg", 2054 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy}, 2055 RetType{Ssize_tTy}), 2056 Summary(NoEvalCall) 2057 .Case({ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2058 .ArgConstraint( 2059 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2060 2061 // int setsockopt(int socket, int level, int option_name, 2062 // const void *option_value, socklen_t option_len); 2063 addToFunctionSummaryMap( 2064 "setsockopt", 2065 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy}, 2066 RetType{IntTy}), 2067 Summary(NoEvalCall) 2068 .Case(ReturnsZeroOrMinusOne) 2069 .ArgConstraint(NotNull(ArgNo(3))) 2070 .ArgConstraint( 2071 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4))) 2072 .ArgConstraint( 2073 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax)))); 2074 2075 // int getsockopt(int socket, int level, int option_name, 2076 // void *restrict option_value, 2077 // socklen_t *restrict option_len); 2078 addToFunctionSummaryMap( 2079 "getsockopt", 2080 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy, 2081 Socklen_tPtrRestrictTy}, 2082 RetType{IntTy}), 2083 Summary(NoEvalCall) 2084 .Case(ReturnsZeroOrMinusOne) 2085 .ArgConstraint(NotNull(ArgNo(3))) 2086 .ArgConstraint(NotNull(ArgNo(4)))); 2087 2088 // ssize_t send(int sockfd, const void *buf, size_t len, int flags); 2089 addToFunctionSummaryMap( 2090 "send", 2091 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy}, 2092 RetType{Ssize_tTy}), 2093 Summary(NoEvalCall) 2094 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 2095 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}) 2096 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2097 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2098 /*BufSize=*/ArgNo(2)))); 2099 2100 // int socketpair(int domain, int type, int protocol, int sv[2]); 2101 addToFunctionSummaryMap( 2102 "socketpair", 2103 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}), 2104 Summary(NoEvalCall) 2105 .Case(ReturnsZeroOrMinusOne) 2106 .ArgConstraint(NotNull(ArgNo(3)))); 2107 2108 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, 2109 // char *restrict node, socklen_t nodelen, 2110 // char *restrict service, 2111 // socklen_t servicelen, int flags); 2112 // 2113 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr 2114 // parameter is never handled as a transparent union in netdb.h 2115 addToFunctionSummaryMap( 2116 "getnameinfo", 2117 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy, 2118 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy, 2119 Socklen_tTy, IntTy}, 2120 RetType{IntTy}), 2121 Summary(NoEvalCall) 2122 .ArgConstraint( 2123 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))) 2124 .ArgConstraint( 2125 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax))) 2126 .ArgConstraint( 2127 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3))) 2128 .ArgConstraint( 2129 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax))) 2130 .ArgConstraint( 2131 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5))) 2132 .ArgConstraint( 2133 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax)))); 2134 2135 Optional<QualType> StructUtimbufTy = lookupTy("utimbuf"); 2136 Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy); 2137 2138 // int utime(const char *filename, struct utimbuf *buf); 2139 addToFunctionSummaryMap( 2140 "utime", 2141 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}), 2142 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2143 2144 Optional<QualType> StructTimespecTy = lookupTy("timespec"); 2145 Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy); 2146 Optional<QualType> ConstStructTimespecPtrTy = 2147 getPointerTy(getConstTy(StructTimespecTy)); 2148 2149 // int futimens(int fd, const struct timespec times[2]); 2150 addToFunctionSummaryMap( 2151 "futimens", 2152 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}), 2153 Summary(NoEvalCall) 2154 .ArgConstraint( 2155 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 2156 2157 // int utimensat(int dirfd, const char *pathname, 2158 // const struct timespec times[2], int flags); 2159 addToFunctionSummaryMap( 2160 "utimensat", 2161 Signature( 2162 ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy}, 2163 RetType{IntTy}), 2164 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 2165 2166 Optional<QualType> StructTimevalTy = lookupTy("timeval"); 2167 Optional<QualType> ConstStructTimevalPtrTy = 2168 getPointerTy(getConstTy(StructTimevalTy)); 2169 2170 // int utimes(const char *filename, const struct timeval times[2]); 2171 addToFunctionSummaryMap( 2172 "utimes", 2173 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy}, 2174 RetType{IntTy}), 2175 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2176 2177 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); 2178 addToFunctionSummaryMap( 2179 "nanosleep", 2180 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy}, 2181 RetType{IntTy}), 2182 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2183 2184 Optional<QualType> Time_tTy = lookupTy("time_t"); 2185 Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy)); 2186 Optional<QualType> ConstTime_tPtrRestrictTy = 2187 getRestrictTy(ConstTime_tPtrTy); 2188 2189 Optional<QualType> StructTmTy = lookupTy("tm"); 2190 Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy); 2191 Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy); 2192 Optional<QualType> ConstStructTmPtrTy = 2193 getPointerTy(getConstTy(StructTmTy)); 2194 Optional<QualType> ConstStructTmPtrRestrictTy = 2195 getRestrictTy(ConstStructTmPtrTy); 2196 2197 // struct tm * localtime(const time_t *tp); 2198 addToFunctionSummaryMap( 2199 "localtime", 2200 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 2201 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2202 2203 // struct tm *localtime_r(const time_t *restrict timer, 2204 // struct tm *restrict result); 2205 addToFunctionSummaryMap( 2206 "localtime_r", 2207 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 2208 RetType{StructTmPtrTy}), 2209 Summary(NoEvalCall) 2210 .ArgConstraint(NotNull(ArgNo(0))) 2211 .ArgConstraint(NotNull(ArgNo(1)))); 2212 2213 // char *asctime_r(const struct tm *restrict tm, char *restrict buf); 2214 addToFunctionSummaryMap( 2215 "asctime_r", 2216 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy}, 2217 RetType{CharPtrTy}), 2218 Summary(NoEvalCall) 2219 .ArgConstraint(NotNull(ArgNo(0))) 2220 .ArgConstraint(NotNull(ArgNo(1))) 2221 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2222 /*MinBufSize=*/BVF.getValue(26, IntTy)))); 2223 2224 // char *ctime_r(const time_t *timep, char *buf); 2225 addToFunctionSummaryMap( 2226 "ctime_r", 2227 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}), 2228 Summary(NoEvalCall) 2229 .ArgConstraint(NotNull(ArgNo(0))) 2230 .ArgConstraint(NotNull(ArgNo(1))) 2231 .ArgConstraint(BufferSize( 2232 /*Buffer=*/ArgNo(1), 2233 /*MinBufSize=*/BVF.getValue(26, IntTy)))); 2234 2235 // struct tm *gmtime_r(const time_t *restrict timer, 2236 // struct tm *restrict result); 2237 addToFunctionSummaryMap( 2238 "gmtime_r", 2239 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy}, 2240 RetType{StructTmPtrTy}), 2241 Summary(NoEvalCall) 2242 .ArgConstraint(NotNull(ArgNo(0))) 2243 .ArgConstraint(NotNull(ArgNo(1)))); 2244 2245 // struct tm * gmtime(const time_t *tp); 2246 addToFunctionSummaryMap( 2247 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}), 2248 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2249 2250 Optional<QualType> Clockid_tTy = lookupTy("clockid_t"); 2251 2252 // int clock_gettime(clockid_t clock_id, struct timespec *tp); 2253 addToFunctionSummaryMap( 2254 "clock_gettime", 2255 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}), 2256 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 2257 2258 Optional<QualType> StructItimervalTy = lookupTy("itimerval"); 2259 Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy); 2260 2261 // int getitimer(int which, struct itimerval *curr_value); 2262 addToFunctionSummaryMap( 2263 "getitimer", 2264 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}), 2265 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1)))); 2266 2267 Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t"); 2268 Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy); 2269 Optional<QualType> Pthread_tTy = lookupTy("pthread_t"); 2270 Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy); 2271 Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy); 2272 Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t"); 2273 Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy); 2274 Optional<QualType> Pthread_mutex_tPtrRestrictTy = 2275 getRestrictTy(Pthread_mutex_tPtrTy); 2276 Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t"); 2277 Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy); 2278 Optional<QualType> ConstPthread_attr_tPtrTy = 2279 getPointerTy(getConstTy(Pthread_attr_tTy)); 2280 Optional<QualType> ConstPthread_attr_tPtrRestrictTy = 2281 getRestrictTy(ConstPthread_attr_tPtrTy); 2282 Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t"); 2283 Optional<QualType> ConstPthread_mutexattr_tPtrTy = 2284 getPointerTy(getConstTy(Pthread_mutexattr_tTy)); 2285 Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy = 2286 getRestrictTy(ConstPthread_mutexattr_tPtrTy); 2287 2288 QualType PthreadStartRoutineTy = getPointerTy( 2289 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy, 2290 FunctionProtoType::ExtProtoInfo())); 2291 2292 // int pthread_cond_signal(pthread_cond_t *cond); 2293 // int pthread_cond_broadcast(pthread_cond_t *cond); 2294 addToFunctionSummaryMap( 2295 {"pthread_cond_signal", "pthread_cond_broadcast"}, 2296 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}), 2297 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2298 2299 // int pthread_create(pthread_t *restrict thread, 2300 // const pthread_attr_t *restrict attr, 2301 // void *(*start_routine)(void*), void *restrict arg); 2302 addToFunctionSummaryMap( 2303 "pthread_create", 2304 Signature(ArgTypes{Pthread_tPtrRestrictTy, 2305 ConstPthread_attr_tPtrRestrictTy, 2306 PthreadStartRoutineTy, VoidPtrRestrictTy}, 2307 RetType{IntTy}), 2308 Summary(NoEvalCall) 2309 .ArgConstraint(NotNull(ArgNo(0))) 2310 .ArgConstraint(NotNull(ArgNo(2)))); 2311 2312 // int pthread_attr_destroy(pthread_attr_t *attr); 2313 // int pthread_attr_init(pthread_attr_t *attr); 2314 addToFunctionSummaryMap( 2315 {"pthread_attr_destroy", "pthread_attr_init"}, 2316 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}), 2317 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2318 2319 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, 2320 // size_t *restrict stacksize); 2321 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, 2322 // size_t *restrict guardsize); 2323 addToFunctionSummaryMap( 2324 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"}, 2325 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy}, 2326 RetType{IntTy}), 2327 Summary(NoEvalCall) 2328 .ArgConstraint(NotNull(ArgNo(0))) 2329 .ArgConstraint(NotNull(ArgNo(1)))); 2330 2331 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); 2332 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); 2333 addToFunctionSummaryMap( 2334 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"}, 2335 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}), 2336 Summary(NoEvalCall) 2337 .ArgConstraint(NotNull(ArgNo(0))) 2338 .ArgConstraint( 2339 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 2340 2341 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const 2342 // pthread_mutexattr_t *restrict attr); 2343 addToFunctionSummaryMap( 2344 "pthread_mutex_init", 2345 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy, 2346 ConstPthread_mutexattr_tPtrRestrictTy}, 2347 RetType{IntTy}), 2348 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2349 2350 // int pthread_mutex_destroy(pthread_mutex_t *mutex); 2351 // int pthread_mutex_lock(pthread_mutex_t *mutex); 2352 // int pthread_mutex_trylock(pthread_mutex_t *mutex); 2353 // int pthread_mutex_unlock(pthread_mutex_t *mutex); 2354 addToFunctionSummaryMap( 2355 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock", 2356 "pthread_mutex_unlock"}, 2357 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}), 2358 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); 2359 } 2360 2361 // Functions for testing. 2362 if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) { 2363 addToFunctionSummaryMap( 2364 "__two_constrained_args", 2365 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}), 2366 Summary(EvalCallAsPure) 2367 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))) 2368 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1)))); 2369 addToFunctionSummaryMap( 2370 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}), 2371 Summary(EvalCallAsPure) 2372 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))) 2373 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2)))); 2374 addToFunctionSummaryMap( 2375 "__defaultparam", 2376 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}), 2377 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0)))); 2378 addToFunctionSummaryMap( 2379 "__variadic", 2380 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}), 2381 Summary(EvalCallAsPure) 2382 .ArgConstraint(NotNull(ArgNo(0))) 2383 .ArgConstraint(NotNull(ArgNo(1)))); 2384 addToFunctionSummaryMap( 2385 "__buf_size_arg_constraint", 2386 Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}), 2387 Summary(EvalCallAsPure) 2388 .ArgConstraint( 2389 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))); 2390 addToFunctionSummaryMap( 2391 "__buf_size_arg_constraint_mul", 2392 Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}), 2393 Summary(EvalCallAsPure) 2394 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 2395 /*BufSizeMultiplier=*/ArgNo(2)))); 2396 addToFunctionSummaryMap( 2397 "__buf_size_arg_constraint_concrete", 2398 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}), 2399 Summary(EvalCallAsPure) 2400 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), 2401 /*BufSize=*/BVF.getValue(10, IntTy)))); 2402 addToFunctionSummaryMap( 2403 {"__test_restrict_param_0", "__test_restrict_param_1", 2404 "__test_restrict_param_2"}, 2405 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}), 2406 Summary(EvalCallAsPure)); 2407 } 2408 } 2409 2410 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 2411 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>(); 2412 Checker->DisplayLoadedSummaries = 2413 mgr.getAnalyzerOptions().getCheckerBooleanOption( 2414 Checker, "DisplayLoadedSummaries"); 2415 Checker->ModelPOSIX = 2416 mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX"); 2417 } 2418 2419 bool ento::shouldRegisterStdCLibraryFunctionsChecker( 2420 const CheckerManager &mgr) { 2421 return true; 2422 } 2423 2424 #define REGISTER_CHECKER(name) \ 2425 void ento::register##name(CheckerManager &mgr) { \ 2426 StdLibraryFunctionsChecker *checker = \ 2427 mgr.getChecker<StdLibraryFunctionsChecker>(); \ 2428 checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \ 2429 checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \ 2430 mgr.getCurrentCheckerName(); \ 2431 } \ 2432 \ 2433 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 2434 2435 REGISTER_CHECKER(StdCLibraryFunctionArgsChecker) 2436 REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker) 2437