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 protected: 130 ArgNo ArgN; // Argument to which we apply the constraint. 131 132 /// Do polymorphic sanity check on the constraint. 133 virtual bool checkSpecificValidity(const FunctionDecl *FD) const { 134 return true; 135 } 136 }; 137 138 /// Given a range, should the argument stay inside or outside this range? 139 enum RangeKind { OutOfRange, WithinRange }; 140 141 /// Encapsulates a single range on a single symbol within a branch. 142 class RangeConstraint : public ValueConstraint { 143 RangeKind Kind; // Kind of range definition. 144 IntRangeVector Args; // Polymorphic arguments. 145 146 public: 147 RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Args) 148 : ValueConstraint(ArgN), Kind(Kind), Args(Args) {} 149 150 const IntRangeVector &getRanges() const { return Args; } 151 152 private: 153 ProgramStateRef applyAsOutOfRange(ProgramStateRef State, 154 const CallEvent &Call, 155 const Summary &Summary) const; 156 ProgramStateRef applyAsWithinRange(ProgramStateRef State, 157 const CallEvent &Call, 158 const Summary &Summary) const; 159 160 public: 161 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 162 const Summary &Summary, 163 CheckerContext &C) const override { 164 switch (Kind) { 165 case OutOfRange: 166 return applyAsOutOfRange(State, Call, Summary); 167 case WithinRange: 168 return applyAsWithinRange(State, Call, Summary); 169 } 170 llvm_unreachable("Unknown range kind!"); 171 } 172 173 ValueConstraintPtr negate() const override { 174 RangeConstraint Tmp(*this); 175 switch (Kind) { 176 case OutOfRange: 177 Tmp.Kind = WithinRange; 178 break; 179 case WithinRange: 180 Tmp.Kind = OutOfRange; 181 break; 182 } 183 return std::make_shared<RangeConstraint>(Tmp); 184 } 185 186 bool checkSpecificValidity(const FunctionDecl *FD) const override { 187 const bool ValidArg = 188 getArgType(FD, ArgN)->isIntegralType(FD->getASTContext()); 189 assert(ValidArg && 190 "This constraint should be applied on an integral type"); 191 return ValidArg; 192 } 193 }; 194 195 class ComparisonConstraint : public ValueConstraint { 196 BinaryOperator::Opcode Opcode; 197 ArgNo OtherArgN; 198 199 public: 200 ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode, 201 ArgNo OtherArgN) 202 : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {} 203 ArgNo getOtherArgNo() const { return OtherArgN; } 204 BinaryOperator::Opcode getOpcode() const { return Opcode; } 205 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 206 const Summary &Summary, 207 CheckerContext &C) const override; 208 }; 209 210 class NotNullConstraint : public ValueConstraint { 211 using ValueConstraint::ValueConstraint; 212 // This variable has a role when we negate the constraint. 213 bool CannotBeNull = true; 214 215 public: 216 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 217 const Summary &Summary, 218 CheckerContext &C) const override { 219 SVal V = getArgSVal(Call, getArgNo()); 220 if (V.isUndef()) 221 return State; 222 223 DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>(); 224 if (!L.getAs<Loc>()) 225 return State; 226 227 return State->assume(L, CannotBeNull); 228 } 229 230 ValueConstraintPtr negate() const override { 231 NotNullConstraint Tmp(*this); 232 Tmp.CannotBeNull = !this->CannotBeNull; 233 return std::make_shared<NotNullConstraint>(Tmp); 234 } 235 236 bool checkSpecificValidity(const FunctionDecl *FD) const override { 237 const bool ValidArg = getArgType(FD, ArgN)->isPointerType(); 238 assert(ValidArg && 239 "This constraint should be applied only on a pointer type"); 240 return ValidArg; 241 } 242 }; 243 244 // Represents a buffer argument with an additional size argument. 245 // E.g. the first two arguments here: 246 // ctime_s(char *buffer, rsize_t bufsz, const time_t *time); 247 // Another example: 248 // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 249 // // Here, ptr is the buffer, and its minimum size is `size * nmemb`. 250 class BufferSizeConstraint : public ValueConstraint { 251 // The argument which holds the size of the buffer. 252 ArgNo SizeArgN; 253 // The argument which is a multiplier to size. This is set in case of 254 // `fread` like functions where the size is computed as a multiplication of 255 // two arguments. 256 llvm::Optional<ArgNo> SizeMultiplierArgN; 257 // The operator we use in apply. This is negated in negate(). 258 BinaryOperator::Opcode Op = BO_LE; 259 260 public: 261 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize) 262 : ValueConstraint(Buffer), SizeArgN(BufSize) {} 263 264 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier) 265 : ValueConstraint(Buffer), SizeArgN(BufSize), 266 SizeMultiplierArgN(BufSizeMultiplier) {} 267 268 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 269 const Summary &Summary, 270 CheckerContext &C) const override { 271 SValBuilder &SvalBuilder = C.getSValBuilder(); 272 // The buffer argument. 273 SVal BufV = getArgSVal(Call, getArgNo()); 274 // The size argument. 275 SVal SizeV = getArgSVal(Call, SizeArgN); 276 // Multiply with another argument if given. 277 if (SizeMultiplierArgN) { 278 SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN); 279 SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV, 280 Summary.getArgType(SizeArgN)); 281 } 282 // The dynamic size of the buffer argument, got from the analyzer engine. 283 SVal BufDynSize = getDynamicSizeWithOffset(State, BufV); 284 285 SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize, 286 SvalBuilder.getContext().BoolTy); 287 if (auto F = Feasible.getAs<DefinedOrUnknownSVal>()) 288 return State->assume(*F, true); 289 290 // We can get here only if the size argument or the dynamic size is 291 // undefined. But the dynamic size should never be undefined, only 292 // unknown. So, here, the size of the argument is undefined, i.e. we 293 // cannot apply the constraint. Actually, other checkers like 294 // CallAndMessage should catch this situation earlier, because we call a 295 // function with an uninitialized argument. 296 llvm_unreachable("Size argument or the dynamic size is Undefined"); 297 } 298 299 ValueConstraintPtr negate() const override { 300 BufferSizeConstraint Tmp(*this); 301 Tmp.Op = BinaryOperator::negateComparisonOp(Op); 302 return std::make_shared<BufferSizeConstraint>(Tmp); 303 } 304 305 bool checkSpecificValidity(const FunctionDecl *FD) const override { 306 const bool ValidArg = getArgType(FD, ArgN)->isPointerType(); 307 assert(ValidArg && 308 "This constraint should be applied only on a pointer type"); 309 return ValidArg; 310 } 311 }; 312 313 /// The complete list of constraints that defines a single branch. 314 typedef std::vector<ValueConstraintPtr> ConstraintSet; 315 316 using ArgTypes = std::vector<QualType>; 317 318 // A placeholder type, we use it whenever we do not care about the concrete 319 // type in a Signature. 320 const QualType Irrelevant{}; 321 bool static isIrrelevant(QualType T) { return T.isNull(); } 322 323 // The signature of a function we want to describe with a summary. This is a 324 // concessive signature, meaning there may be irrelevant types in the 325 // signature which we do not check against a function with concrete types. 326 struct Signature { 327 ArgTypes ArgTys; 328 QualType RetTy; 329 Signature(ArgTypes ArgTys, QualType RetTy) : ArgTys(ArgTys), RetTy(RetTy) { 330 assertRetTypeSuitableForSignature(RetTy); 331 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) { 332 QualType ArgTy = ArgTys[I]; 333 assertArgTypeSuitableForSignature(ArgTy); 334 } 335 } 336 337 bool matches(const FunctionDecl *FD) const; 338 339 private: 340 static void assertArgTypeSuitableForSignature(QualType T) { 341 assert((T.isNull() || !T->isVoidType()) && 342 "We should have no void types in the spec"); 343 assert((T.isNull() || T.isCanonical()) && 344 "We should only have canonical types in the spec"); 345 } 346 static void assertRetTypeSuitableForSignature(QualType T) { 347 assert((T.isNull() || T.isCanonical()) && 348 "We should only have canonical types in the spec"); 349 } 350 }; 351 352 static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) { 353 assert(FD && "Function must be set"); 354 QualType T = (ArgN == Ret) 355 ? FD->getReturnType().getCanonicalType() 356 : FD->getParamDecl(ArgN)->getType().getCanonicalType(); 357 return T; 358 } 359 360 using Cases = std::vector<ConstraintSet>; 361 362 /// A summary includes information about 363 /// * function prototype (signature) 364 /// * approach to invalidation, 365 /// * a list of branches - a list of list of ranges - 366 /// A branch represents a path in the exploded graph of a function (which 367 /// is a tree). So, a branch is a series of assumptions. In other words, 368 /// branches represent split states and additional assumptions on top of 369 /// the splitting assumption. 370 /// For example, consider the branches in `isalpha(x)` 371 /// Branch 1) 372 /// x is in range ['A', 'Z'] or in ['a', 'z'] 373 /// then the return value is not 0. (I.e. out-of-range [0, 0]) 374 /// Branch 2) 375 /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z'] 376 /// then the return value is 0. 377 /// * a list of argument constraints, that must be true on every branch. 378 /// If these constraints are not satisfied that means a fatal error 379 /// usually resulting in undefined behaviour. 380 /// 381 /// Application of a summary: 382 /// The signature and argument constraints together contain information 383 /// about which functions are handled by the summary. The signature can use 384 /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in 385 /// a signature means that type is not compared to the type of the parameter 386 /// in the found FunctionDecl. Argument constraints may specify additional 387 /// rules for the given parameter's type, those rules are checked once the 388 /// signature is matched. 389 class Summary { 390 Optional<Signature> Sign; 391 const InvalidationKind InvalidationKd; 392 Cases CaseConstraints; 393 ConstraintSet ArgConstraints; 394 395 // The function to which the summary applies. This is set after lookup and 396 // match to the signature. 397 const FunctionDecl *FD = nullptr; 398 399 public: 400 Summary(ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd) 401 : Sign(Signature(ArgTys, RetTy)), InvalidationKd(InvalidationKd) {} 402 403 Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {} 404 405 Summary &setSignature(const Signature &S) { 406 Sign = S; 407 return *this; 408 } 409 410 Summary &Case(ConstraintSet &&CS) { 411 CaseConstraints.push_back(std::move(CS)); 412 return *this; 413 } 414 Summary &ArgConstraint(ValueConstraintPtr VC) { 415 ArgConstraints.push_back(VC); 416 return *this; 417 } 418 419 InvalidationKind getInvalidationKd() const { return InvalidationKd; } 420 const Cases &getCaseConstraints() const { return CaseConstraints; } 421 const ConstraintSet &getArgConstraints() const { return ArgConstraints; } 422 423 QualType getArgType(ArgNo ArgN) const { 424 return StdLibraryFunctionsChecker::getArgType(FD, ArgN); 425 } 426 427 // Returns true if the summary should be applied to the given function. 428 // And if yes then store the function declaration. 429 bool matchesAndSet(const FunctionDecl *FD) { 430 assert(Sign && 431 "Signature must be set before comparing to a FunctionDecl"); 432 bool Result = Sign->matches(FD) && validateByConstraints(FD); 433 if (Result) { 434 assert(!this->FD && "FD must not be set more than once"); 435 this->FD = FD; 436 } 437 return Result; 438 } 439 440 private: 441 // Once we know the exact type of the function then do sanity check on all 442 // the given constraints. 443 bool validateByConstraints(const FunctionDecl *FD) const { 444 for (const ConstraintSet &Case : CaseConstraints) 445 for (const ValueConstraintPtr &Constraint : Case) 446 if (!Constraint->checkValidity(FD)) 447 return false; 448 for (const ValueConstraintPtr &Constraint : ArgConstraints) 449 if (!Constraint->checkValidity(FD)) 450 return false; 451 return true; 452 } 453 }; 454 455 // The map of all functions supported by the checker. It is initialized 456 // lazily, and it doesn't change after initialization. 457 using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>; 458 mutable FunctionSummaryMapType FunctionSummaryMap; 459 460 mutable std::unique_ptr<BugType> BT_InvalidArg; 461 462 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) { 463 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN); 464 } 465 466 public: 467 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 468 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 469 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 470 471 enum CheckKind { 472 CK_StdCLibraryFunctionArgsChecker, 473 CK_StdCLibraryFunctionsTesterChecker, 474 CK_NumCheckKinds 475 }; 476 DefaultBool ChecksEnabled[CK_NumCheckKinds]; 477 CheckerNameRef CheckNames[CK_NumCheckKinds]; 478 479 bool DisplayLoadedSummaries = false; 480 bool ModelPOSIX = false; 481 482 private: 483 Optional<Summary> findFunctionSummary(const FunctionDecl *FD, 484 CheckerContext &C) const; 485 Optional<Summary> findFunctionSummary(const CallEvent &Call, 486 CheckerContext &C) const; 487 488 void initFunctionSummaries(CheckerContext &C) const; 489 490 void reportBug(const CallEvent &Call, ExplodedNode *N, 491 CheckerContext &C) const { 492 if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker]) 493 return; 494 // TODO Add detailed diagnostic. 495 StringRef Msg = "Function argument constraint is not satisfied"; 496 if (!BT_InvalidArg) 497 BT_InvalidArg = std::make_unique<BugType>( 498 CheckNames[CK_StdCLibraryFunctionArgsChecker], 499 "Unsatisfied argument constraints", categories::LogicError); 500 auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N); 501 bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R); 502 C.emitReport(std::move(R)); 503 } 504 }; 505 506 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret = 507 std::numeric_limits<ArgNo>::max(); 508 509 } // end of anonymous namespace 510 511 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange( 512 ProgramStateRef State, const CallEvent &Call, 513 const Summary &Summary) const { 514 515 ProgramStateManager &Mgr = State->getStateManager(); 516 SValBuilder &SVB = Mgr.getSValBuilder(); 517 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 518 ConstraintManager &CM = Mgr.getConstraintManager(); 519 QualType T = Summary.getArgType(getArgNo()); 520 SVal V = getArgSVal(Call, getArgNo()); 521 522 if (auto N = V.getAs<NonLoc>()) { 523 const IntRangeVector &R = getRanges(); 524 size_t E = R.size(); 525 for (size_t I = 0; I != E; ++I) { 526 const llvm::APSInt &Min = BVF.getValue(R[I].first, T); 527 const llvm::APSInt &Max = BVF.getValue(R[I].second, T); 528 assert(Min <= Max); 529 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 530 if (!State) 531 break; 532 } 533 } 534 535 return State; 536 } 537 538 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange( 539 ProgramStateRef State, const CallEvent &Call, 540 const Summary &Summary) const { 541 542 ProgramStateManager &Mgr = State->getStateManager(); 543 SValBuilder &SVB = Mgr.getSValBuilder(); 544 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 545 ConstraintManager &CM = Mgr.getConstraintManager(); 546 QualType T = Summary.getArgType(getArgNo()); 547 SVal V = getArgSVal(Call, getArgNo()); 548 549 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R". 550 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary, 551 // and then cut away all holes in R one by one. 552 // 553 // E.g. consider a range list R as [A, B] and [C, D] 554 // -------+--------+------------------+------------+-----------> 555 // A B C D 556 // Then we assume that the value is not in [-inf, A - 1], 557 // then not in [D + 1, +inf], then not in [B + 1, C - 1] 558 if (auto N = V.getAs<NonLoc>()) { 559 const IntRangeVector &R = getRanges(); 560 size_t E = R.size(); 561 562 const llvm::APSInt &MinusInf = BVF.getMinValue(T); 563 const llvm::APSInt &PlusInf = BVF.getMaxValue(T); 564 565 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T); 566 if (Left != PlusInf) { 567 assert(MinusInf <= Left); 568 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false); 569 if (!State) 570 return nullptr; 571 } 572 573 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T); 574 if (Right != MinusInf) { 575 assert(Right <= PlusInf); 576 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false); 577 if (!State) 578 return nullptr; 579 } 580 581 for (size_t I = 1; I != E; ++I) { 582 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T); 583 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T); 584 if (Min <= Max) { 585 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 586 if (!State) 587 return nullptr; 588 } 589 } 590 } 591 592 return State; 593 } 594 595 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply( 596 ProgramStateRef State, const CallEvent &Call, const Summary &Summary, 597 CheckerContext &C) const { 598 599 ProgramStateManager &Mgr = State->getStateManager(); 600 SValBuilder &SVB = Mgr.getSValBuilder(); 601 QualType CondT = SVB.getConditionType(); 602 QualType T = Summary.getArgType(getArgNo()); 603 SVal V = getArgSVal(Call, getArgNo()); 604 605 BinaryOperator::Opcode Op = getOpcode(); 606 ArgNo OtherArg = getOtherArgNo(); 607 SVal OtherV = getArgSVal(Call, OtherArg); 608 QualType OtherT = Summary.getArgType(OtherArg); 609 // Note: we avoid integral promotion for comparison. 610 OtherV = SVB.evalCast(OtherV, T, OtherT); 611 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT) 612 .getAs<DefinedOrUnknownSVal>()) 613 State = State->assume(*CompV, true); 614 return State; 615 } 616 617 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call, 618 CheckerContext &C) const { 619 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 620 if (!FoundSummary) 621 return; 622 623 const Summary &Summary = *FoundSummary; 624 ProgramStateRef State = C.getState(); 625 626 ProgramStateRef NewState = State; 627 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) { 628 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C); 629 ProgramStateRef FailureSt = 630 Constraint->negate()->apply(NewState, Call, Summary, C); 631 // The argument constraint is not satisfied. 632 if (FailureSt && !SuccessSt) { 633 if (ExplodedNode *N = C.generateErrorNode(NewState)) 634 reportBug(Call, N, C); 635 break; 636 } else { 637 // We will apply the constraint even if we cannot reason about the 638 // argument. This means both SuccessSt and FailureSt can be true. If we 639 // weren't applying the constraint that would mean that symbolic 640 // execution continues on a code whose behaviour is undefined. 641 assert(SuccessSt); 642 NewState = SuccessSt; 643 } 644 } 645 if (NewState && NewState != State) 646 C.addTransition(NewState); 647 } 648 649 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, 650 CheckerContext &C) const { 651 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 652 if (!FoundSummary) 653 return; 654 655 // Now apply the constraints. 656 const Summary &Summary = *FoundSummary; 657 ProgramStateRef State = C.getState(); 658 659 // Apply case/branch specifications. 660 for (const ConstraintSet &Case : Summary.getCaseConstraints()) { 661 ProgramStateRef NewState = State; 662 for (const ValueConstraintPtr &Constraint : Case) { 663 NewState = Constraint->apply(NewState, Call, Summary, C); 664 if (!NewState) 665 break; 666 } 667 668 if (NewState && NewState != State) 669 C.addTransition(NewState); 670 } 671 } 672 673 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, 674 CheckerContext &C) const { 675 Optional<Summary> FoundSummary = findFunctionSummary(Call, C); 676 if (!FoundSummary) 677 return false; 678 679 const Summary &Summary = *FoundSummary; 680 switch (Summary.getInvalidationKd()) { 681 case EvalCallAsPure: { 682 ProgramStateRef State = C.getState(); 683 const LocationContext *LC = C.getLocationContext(); 684 const auto *CE = cast_or_null<CallExpr>(Call.getOriginExpr()); 685 SVal V = C.getSValBuilder().conjureSymbolVal( 686 CE, LC, CE->getType().getCanonicalType(), C.blockCount()); 687 State = State->BindExpr(CE, LC, V); 688 C.addTransition(State); 689 return true; 690 } 691 case NoEvalCall: 692 // Summary tells us to avoid performing eval::Call. The function is possibly 693 // evaluated by another checker, or evaluated conservatively. 694 return false; 695 } 696 llvm_unreachable("Unknown invalidation kind!"); 697 } 698 699 bool StdLibraryFunctionsChecker::Signature::matches( 700 const FunctionDecl *FD) const { 701 // Check number of arguments: 702 if (FD->param_size() != ArgTys.size()) 703 return false; 704 705 // Check return type. 706 if (!isIrrelevant(RetTy)) 707 if (RetTy != FD->getReturnType().getCanonicalType()) 708 return false; 709 710 // Check argument types. 711 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) { 712 QualType ArgTy = ArgTys[I]; 713 if (isIrrelevant(ArgTy)) 714 continue; 715 if (ArgTy != FD->getParamDecl(I)->getType().getCanonicalType()) 716 return false; 717 } 718 719 return true; 720 } 721 722 Optional<StdLibraryFunctionsChecker::Summary> 723 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, 724 CheckerContext &C) const { 725 if (!FD) 726 return None; 727 728 initFunctionSummaries(C); 729 730 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl()); 731 if (FSMI == FunctionSummaryMap.end()) 732 return None; 733 return FSMI->second; 734 } 735 736 Optional<StdLibraryFunctionsChecker::Summary> 737 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call, 738 CheckerContext &C) const { 739 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 740 if (!FD) 741 return None; 742 return findFunctionSummary(FD, C); 743 } 744 745 static llvm::Optional<QualType> lookupType(StringRef Name, 746 const ASTContext &ACtx) { 747 IdentifierInfo &II = ACtx.Idents.get(Name); 748 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 749 if (LookupRes.size() == 0) 750 return None; 751 752 // Prioritze typedef declarations. 753 // This is needed in case of C struct typedefs. E.g.: 754 // typedef struct FILE FILE; 755 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' and 756 // we have a TypedefDecl with the name 'FILE'. 757 for (Decl *D : LookupRes) 758 if (auto *TD = dyn_cast<TypedefNameDecl>(D)) 759 return ACtx.getTypeDeclType(TD).getCanonicalType(); 760 761 // Find the first TypeDecl. 762 // There maybe cases when a function has the same name as a struct. 763 // E.g. in POSIX: `struct stat` and the function `stat()`: 764 // int stat(const char *restrict path, struct stat *restrict buf); 765 for (Decl *D : LookupRes) 766 if (auto *TD = dyn_cast<TypeDecl>(D)) 767 return ACtx.getTypeDeclType(TD).getCanonicalType(); 768 return None; 769 } 770 771 void StdLibraryFunctionsChecker::initFunctionSummaries( 772 CheckerContext &C) const { 773 if (!FunctionSummaryMap.empty()) 774 return; 775 776 SValBuilder &SVB = C.getSValBuilder(); 777 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 778 const ASTContext &ACtx = BVF.getContext(); 779 780 auto getRestrictTy = [&ACtx](QualType Ty) { 781 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty; 782 }; 783 784 // These types are useful for writing specifications quickly, 785 // New specifications should probably introduce more types. 786 // Some types are hard to obtain from the AST, eg. "ssize_t". 787 // In such cases it should be possible to provide multiple variants 788 // of function summary for common cases (eg. ssize_t could be int or long 789 // or long long, so three summary variants would be enough). 790 // Of course, function variants are also useful for C++ overloads. 791 const QualType VoidTy = ACtx.VoidTy; 792 const QualType IntTy = ACtx.IntTy; 793 const QualType UnsignedIntTy = ACtx.UnsignedIntTy; 794 const QualType LongTy = ACtx.LongTy; 795 const QualType LongLongTy = ACtx.LongLongTy; 796 const QualType SizeTy = ACtx.getSizeType(); 797 798 const QualType VoidPtrTy = ACtx.VoidPtrTy; // void * 799 const QualType IntPtrTy = ACtx.getPointerType(IntTy); // int * 800 const QualType UnsignedIntPtrTy = 801 ACtx.getPointerType(UnsignedIntTy); // unsigned int * 802 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy); 803 const QualType ConstVoidPtrTy = 804 ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void * 805 const QualType CharPtrTy = ACtx.getPointerType(ACtx.CharTy); // char * 806 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy); 807 const QualType ConstCharPtrTy = 808 ACtx.getPointerType(ACtx.CharTy.withConst()); // const char * 809 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy); 810 const QualType Wchar_tPtrTy = ACtx.getPointerType(ACtx.WCharTy); // wchar_t * 811 const QualType ConstWchar_tPtrTy = 812 ACtx.getPointerType(ACtx.WCharTy.withConst()); // const wchar_t * 813 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy); 814 815 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 816 const RangeInt UnsignedIntMax = 817 BVF.getMaxValue(UnsignedIntTy).getLimitedValue(); 818 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 819 const RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue(); 820 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue(); 821 822 // Set UCharRangeMax to min of int or uchar maximum value. 823 // The C standard states that the arguments of functions like isalpha must 824 // be representable as an unsigned char. Their type is 'int', so the max 825 // value of the argument should be min(UCharMax, IntMax). This just happen 826 // to be true for commonly used and well tested instruction set 827 // architectures, but not for others. 828 const RangeInt UCharRangeMax = 829 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax); 830 831 // The platform dependent value of EOF. 832 // Try our best to parse this from the Preprocessor, otherwise fallback to -1. 833 const auto EOFv = [&C]() -> RangeInt { 834 if (const llvm::Optional<int> OptInt = 835 tryExpandAsInteger("EOF", C.getPreprocessor())) 836 return *OptInt; 837 return -1; 838 }(); 839 840 // Auxiliary class to aid adding summaries to the summary map. 841 struct AddToFunctionSummaryMap { 842 const ASTContext &ACtx; 843 FunctionSummaryMapType ⤅ 844 bool DisplayLoadedSummaries; 845 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM, 846 bool DisplayLoadedSummaries) 847 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) { 848 } 849 850 // Add a summary to a FunctionDecl found by lookup. The lookup is performed 851 // by the given Name, and in the global scope. The summary will be attached 852 // to the found FunctionDecl only if the signatures match. 853 // 854 // Returns true if the summary has been added, false otherwise. 855 bool operator()(StringRef Name, Summary S) { 856 IdentifierInfo &II = ACtx.Idents.get(Name); 857 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 858 if (LookupRes.size() == 0) 859 return false; 860 for (Decl *D : LookupRes) { 861 if (auto *FD = dyn_cast<FunctionDecl>(D)) { 862 if (S.matchesAndSet(FD)) { 863 auto Res = Map.insert({FD->getCanonicalDecl(), S}); 864 assert(Res.second && "Function already has a summary set!"); 865 (void)Res; 866 if (DisplayLoadedSummaries) { 867 llvm::errs() << "Loaded summary for: "; 868 FD->print(llvm::errs()); 869 llvm::errs() << "\n"; 870 } 871 return true; 872 } 873 } 874 } 875 return false; 876 } 877 bool operator()(StringRef Name, Signature Sign, Summary Sum) { 878 return operator()(Name, Sum.setSignature(Sign)); 879 } 880 // Add several summaries for the given name. 881 void operator()(StringRef Name, const std::vector<Summary> &Summaries) { 882 for (const Summary &S : Summaries) 883 operator()(Name, S); 884 } 885 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries); 886 887 // We are finally ready to define specifications for all supported functions. 888 // 889 // The signature needs to have the correct number of arguments. 890 // However, we insert `Irrelevant' when the type is insignificant. 891 // 892 // Argument ranges should always cover all variants. If return value 893 // is completely unknown, omit it from the respective range set. 894 // 895 // All types in the spec need to be canonical. 896 // 897 // Every item in the list of range sets represents a particular 898 // execution path the analyzer would need to explore once 899 // the call is modeled - a new program state is constructed 900 // for every range set, and each range line in the range set 901 // corresponds to a specific constraint within this state. 902 // 903 // Upon comparing to another argument, the other argument is casted 904 // to the current argument's type. This avoids proper promotion but 905 // seems useful. For example, read() receives size_t argument, 906 // and its return value, which is of type ssize_t, cannot be greater 907 // than this argument. If we made a promotion, and the size argument 908 // is equal to, say, 10, then we'd impose a range of [0, 10] on the 909 // return value, however the correct range is [-1, 10]. 910 // 911 // Please update the list of functions in the header after editing! 912 913 // Below are helpers functions to create the summaries. 914 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, 915 IntRangeVector Ranges) { 916 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges); 917 }; 918 auto BufferSize = [](auto... Args) { 919 return std::make_shared<BufferSizeConstraint>(Args...); 920 }; 921 struct { 922 auto operator()(RangeKind Kind, IntRangeVector Ranges) { 923 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges); 924 } 925 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) { 926 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN); 927 } 928 } ReturnValueCondition; 929 auto Range = [](RangeInt b, RangeInt e) { 930 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}}; 931 }; 932 auto SingleValue = [](RangeInt v) { 933 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}}; 934 }; 935 auto LessThanOrEq = BO_LE; 936 auto NotNull = [&](ArgNo ArgN) { 937 return std::make_shared<NotNullConstraint>(ArgN); 938 }; 939 940 Optional<QualType> FileTy = lookupType("FILE", ACtx); 941 Optional<QualType> FilePtrTy, FilePtrRestrictTy; 942 if (FileTy) { 943 // FILE * 944 FilePtrTy = ACtx.getPointerType(*FileTy); 945 // FILE *restrict 946 FilePtrRestrictTy = getRestrictTy(*FilePtrTy); 947 } 948 949 using RetType = QualType; 950 // Templates for summaries that are reused by many functions. 951 auto Getc = [&]() { 952 return Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall) 953 .Case({ReturnValueCondition(WithinRange, 954 {{EOFv, EOFv}, {0, UCharRangeMax}})}); 955 }; 956 auto Read = [&](RetType R, RangeInt Max) { 957 return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R}, 958 NoEvalCall) 959 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 960 ReturnValueCondition(WithinRange, Range(-1, Max))}); 961 }; 962 auto Fread = [&]() { 963 return Summary( 964 ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, *FilePtrRestrictTy}, 965 RetType{SizeTy}, NoEvalCall) 966 .Case({ 967 ReturnValueCondition(LessThanOrEq, ArgNo(2)), 968 }) 969 .ArgConstraint(NotNull(ArgNo(0))); 970 }; 971 auto Fwrite = [&]() { 972 return Summary(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, SizeTy, 973 *FilePtrRestrictTy}, 974 RetType{SizeTy}, NoEvalCall) 975 .Case({ 976 ReturnValueCondition(LessThanOrEq, ArgNo(2)), 977 }) 978 .ArgConstraint(NotNull(ArgNo(0))); 979 }; 980 auto Getline = [&](RetType R, RangeInt Max) { 981 return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R}, 982 NoEvalCall) 983 .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})}); 984 }; 985 986 // The isascii() family of functions. 987 // The behavior is undefined if the value of the argument is not 988 // representable as unsigned char or is not equal to EOF. See e.g. C99 989 // 7.4.1.2 The isalpha function (p: 181-182). 990 addToFunctionSummaryMap( 991 "isalnum", 992 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 993 // Boils down to isupper() or islower() or isdigit(). 994 .Case({ArgumentCondition(0U, WithinRange, 995 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}), 996 ReturnValueCondition(OutOfRange, SingleValue(0))}) 997 // The locale-specific range. 998 // No post-condition. We are completely unaware of 999 // locale-specific return values. 1000 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1001 .Case( 1002 {ArgumentCondition( 1003 0U, OutOfRange, 1004 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1005 ReturnValueCondition(WithinRange, SingleValue(0))}) 1006 .ArgConstraint(ArgumentCondition( 1007 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1008 addToFunctionSummaryMap( 1009 "isalpha", 1010 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1011 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}), 1012 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1013 // The locale-specific range. 1014 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1015 .Case({ArgumentCondition( 1016 0U, OutOfRange, 1017 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1018 ReturnValueCondition(WithinRange, SingleValue(0))})); 1019 addToFunctionSummaryMap( 1020 "isascii", 1021 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1022 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1023 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1024 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)), 1025 ReturnValueCondition(WithinRange, SingleValue(0))})); 1026 addToFunctionSummaryMap( 1027 "isblank", 1028 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1029 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}), 1030 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1031 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}), 1032 ReturnValueCondition(WithinRange, SingleValue(0))})); 1033 addToFunctionSummaryMap( 1034 "iscntrl", 1035 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1036 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}), 1037 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1038 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}), 1039 ReturnValueCondition(WithinRange, SingleValue(0))})); 1040 addToFunctionSummaryMap( 1041 "isdigit", 1042 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1043 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')), 1044 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1045 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')), 1046 ReturnValueCondition(WithinRange, SingleValue(0))})); 1047 addToFunctionSummaryMap( 1048 "isgraph", 1049 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1050 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)), 1051 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1052 .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)), 1053 ReturnValueCondition(WithinRange, SingleValue(0))})); 1054 addToFunctionSummaryMap( 1055 "islower", 1056 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1057 // Is certainly lowercase. 1058 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')), 1059 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1060 // Is ascii but not lowercase. 1061 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1062 ArgumentCondition(0U, OutOfRange, Range('a', 'z')), 1063 ReturnValueCondition(WithinRange, SingleValue(0))}) 1064 // The locale-specific range. 1065 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1066 // Is not an unsigned char. 1067 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)), 1068 ReturnValueCondition(WithinRange, SingleValue(0))})); 1069 addToFunctionSummaryMap( 1070 "isprint", 1071 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1072 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)), 1073 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1074 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)), 1075 ReturnValueCondition(WithinRange, SingleValue(0))})); 1076 addToFunctionSummaryMap( 1077 "ispunct", 1078 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1079 .Case({ArgumentCondition( 1080 0U, WithinRange, 1081 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1082 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1083 .Case({ArgumentCondition( 1084 0U, OutOfRange, 1085 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1086 ReturnValueCondition(WithinRange, SingleValue(0))})); 1087 addToFunctionSummaryMap( 1088 "isspace", 1089 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1090 // Space, '\f', '\n', '\r', '\t', '\v'. 1091 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}), 1092 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1093 // The locale-specific range. 1094 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1095 .Case({ArgumentCondition(0U, OutOfRange, 1096 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}), 1097 ReturnValueCondition(WithinRange, SingleValue(0))})); 1098 addToFunctionSummaryMap( 1099 "isupper", 1100 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1101 // Is certainly uppercase. 1102 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')), 1103 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1104 // The locale-specific range. 1105 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1106 // Other. 1107 .Case({ArgumentCondition(0U, OutOfRange, 1108 {{'A', 'Z'}, {128, UCharRangeMax}}), 1109 ReturnValueCondition(WithinRange, SingleValue(0))})); 1110 addToFunctionSummaryMap( 1111 "isxdigit", 1112 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1113 .Case({ArgumentCondition(0U, WithinRange, 1114 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1115 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1116 .Case({ArgumentCondition(0U, OutOfRange, 1117 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1118 ReturnValueCondition(WithinRange, SingleValue(0))})); 1119 addToFunctionSummaryMap( 1120 "toupper", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1121 .ArgConstraint(ArgumentCondition( 1122 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1123 addToFunctionSummaryMap( 1124 "tolower", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1125 .ArgConstraint(ArgumentCondition( 1126 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1127 addToFunctionSummaryMap( 1128 "toascii", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1129 .ArgConstraint(ArgumentCondition( 1130 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1131 1132 // The getc() family of functions that returns either a char or an EOF. 1133 if (FilePtrTy) { 1134 addToFunctionSummaryMap("getc", Getc()); 1135 addToFunctionSummaryMap("fgetc", Getc()); 1136 } 1137 addToFunctionSummaryMap( 1138 "getchar", Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall) 1139 .Case({ReturnValueCondition( 1140 WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})})); 1141 1142 // read()-like functions that never return more than buffer size. 1143 if (FilePtrRestrictTy) { 1144 addToFunctionSummaryMap("fread", Fread()); 1145 addToFunctionSummaryMap("fwrite", Fwrite()); 1146 } 1147 1148 // We are not sure how ssize_t is defined on every platform, so we 1149 // provide three variants that should cover common cases. 1150 // FIXME these are actually defined by POSIX and not by the C standard, we 1151 // should handle them together with the rest of the POSIX functions. 1152 addToFunctionSummaryMap("read", {Read(IntTy, IntMax), Read(LongTy, LongMax), 1153 Read(LongLongTy, LongLongMax)}); 1154 addToFunctionSummaryMap("write", {Read(IntTy, IntMax), Read(LongTy, LongMax), 1155 Read(LongLongTy, LongLongMax)}); 1156 1157 // getline()-like functions either fail or read at least the delimiter. 1158 // FIXME these are actually defined by POSIX and not by the C standard, we 1159 // should handle them together with the rest of the POSIX functions. 1160 addToFunctionSummaryMap("getline", 1161 {Getline(IntTy, IntMax), Getline(LongTy, LongMax), 1162 Getline(LongLongTy, LongLongMax)}); 1163 addToFunctionSummaryMap("getdelim", 1164 {Getline(IntTy, IntMax), Getline(LongTy, LongMax), 1165 Getline(LongLongTy, LongLongMax)}); 1166 1167 if (ModelPOSIX) { 1168 1169 // long a64l(const char *str64); 1170 addToFunctionSummaryMap( 1171 "a64l", Summary(ArgTypes{ConstCharPtrTy}, RetType{LongTy}, NoEvalCall) 1172 .ArgConstraint(NotNull(ArgNo(0)))); 1173 1174 // char *l64a(long value); 1175 addToFunctionSummaryMap( 1176 "l64a", Summary(ArgTypes{LongTy}, RetType{CharPtrTy}, NoEvalCall) 1177 .ArgConstraint( 1178 ArgumentCondition(0, WithinRange, Range(0, LongMax)))); 1179 1180 // int access(const char *pathname, int amode); 1181 addToFunctionSummaryMap("access", Summary(ArgTypes{ConstCharPtrTy, IntTy}, 1182 RetType{IntTy}, NoEvalCall) 1183 .ArgConstraint(NotNull(ArgNo(0)))); 1184 1185 // int faccessat(int dirfd, const char *pathname, int mode, int flags); 1186 addToFunctionSummaryMap( 1187 "faccessat", Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy}, 1188 RetType{IntTy}, NoEvalCall) 1189 .ArgConstraint(NotNull(ArgNo(1)))); 1190 1191 // int dup(int fildes); 1192 addToFunctionSummaryMap( 1193 "dup", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1194 .ArgConstraint( 1195 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1196 1197 // int dup2(int fildes1, int filedes2); 1198 addToFunctionSummaryMap( 1199 "dup2", 1200 Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall) 1201 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1202 .ArgConstraint( 1203 ArgumentCondition(1, WithinRange, Range(0, IntMax)))); 1204 1205 // int fdatasync(int fildes); 1206 addToFunctionSummaryMap( 1207 "fdatasync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1208 .ArgConstraint(ArgumentCondition(0, WithinRange, 1209 Range(0, IntMax)))); 1210 1211 // int fnmatch(const char *pattern, const char *string, int flags); 1212 addToFunctionSummaryMap( 1213 "fnmatch", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy}, 1214 RetType{IntTy}, EvalCallAsPure) 1215 .ArgConstraint(NotNull(ArgNo(0))) 1216 .ArgConstraint(NotNull(ArgNo(1)))); 1217 1218 // int fsync(int fildes); 1219 addToFunctionSummaryMap( 1220 "fsync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1221 .ArgConstraint( 1222 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1223 1224 Optional<QualType> Off_tTy = lookupType("off_t", ACtx); 1225 1226 if (Off_tTy) 1227 // int truncate(const char *path, off_t length); 1228 addToFunctionSummaryMap("truncate", 1229 Summary(ArgTypes{ConstCharPtrTy, *Off_tTy}, 1230 RetType{IntTy}, NoEvalCall) 1231 .ArgConstraint(NotNull(ArgNo(0)))); 1232 1233 // int symlink(const char *oldpath, const char *newpath); 1234 addToFunctionSummaryMap("symlink", 1235 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, 1236 RetType{IntTy}, NoEvalCall) 1237 .ArgConstraint(NotNull(ArgNo(0))) 1238 .ArgConstraint(NotNull(ArgNo(1)))); 1239 1240 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath); 1241 addToFunctionSummaryMap( 1242 "symlinkat", 1243 Summary(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, RetType{IntTy}, 1244 NoEvalCall) 1245 .ArgConstraint(NotNull(ArgNo(0))) 1246 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax))) 1247 .ArgConstraint(NotNull(ArgNo(2)))); 1248 1249 if (Off_tTy) 1250 // int lockf(int fd, int cmd, off_t len); 1251 addToFunctionSummaryMap( 1252 "lockf", 1253 Summary(ArgTypes{IntTy, IntTy, *Off_tTy}, RetType{IntTy}, NoEvalCall) 1254 .ArgConstraint( 1255 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1256 1257 Optional<QualType> Mode_tTy = lookupType("mode_t", ACtx); 1258 1259 if (Mode_tTy) 1260 // int creat(const char *pathname, mode_t mode); 1261 addToFunctionSummaryMap("creat", 1262 Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy}, 1263 RetType{IntTy}, NoEvalCall) 1264 .ArgConstraint(NotNull(ArgNo(0)))); 1265 1266 // unsigned int sleep(unsigned int seconds); 1267 addToFunctionSummaryMap( 1268 "sleep", 1269 Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall) 1270 .ArgConstraint( 1271 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1272 1273 Optional<QualType> DirTy = lookupType("DIR", ACtx); 1274 Optional<QualType> DirPtrTy; 1275 if (DirTy) 1276 DirPtrTy = ACtx.getPointerType(*DirTy); 1277 1278 if (DirPtrTy) 1279 // int dirfd(DIR *dirp); 1280 addToFunctionSummaryMap( 1281 "dirfd", Summary(ArgTypes{*DirPtrTy}, RetType{IntTy}, NoEvalCall) 1282 .ArgConstraint(NotNull(ArgNo(0)))); 1283 1284 // unsigned int alarm(unsigned int seconds); 1285 addToFunctionSummaryMap( 1286 "alarm", 1287 Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall) 1288 .ArgConstraint( 1289 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1290 1291 if (DirPtrTy) 1292 // int closedir(DIR *dir); 1293 addToFunctionSummaryMap( 1294 "closedir", Summary(ArgTypes{*DirPtrTy}, RetType{IntTy}, NoEvalCall) 1295 .ArgConstraint(NotNull(ArgNo(0)))); 1296 1297 // char *strdup(const char *s); 1298 addToFunctionSummaryMap("strdup", Summary(ArgTypes{ConstCharPtrTy}, 1299 RetType{CharPtrTy}, NoEvalCall) 1300 .ArgConstraint(NotNull(ArgNo(0)))); 1301 1302 // char *strndup(const char *s, size_t n); 1303 addToFunctionSummaryMap( 1304 "strndup", Summary(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}, 1305 NoEvalCall) 1306 .ArgConstraint(NotNull(ArgNo(0))) 1307 .ArgConstraint(ArgumentCondition(1, WithinRange, 1308 Range(0, SizeMax)))); 1309 1310 // wchar_t *wcsdup(const wchar_t *s); 1311 addToFunctionSummaryMap("wcsdup", Summary(ArgTypes{ConstWchar_tPtrTy}, 1312 RetType{Wchar_tPtrTy}, NoEvalCall) 1313 .ArgConstraint(NotNull(ArgNo(0)))); 1314 1315 // int mkstemp(char *template); 1316 addToFunctionSummaryMap( 1317 "mkstemp", Summary(ArgTypes{CharPtrTy}, RetType{IntTy}, NoEvalCall) 1318 .ArgConstraint(NotNull(ArgNo(0)))); 1319 1320 // char *mkdtemp(char *template); 1321 addToFunctionSummaryMap( 1322 "mkdtemp", Summary(ArgTypes{CharPtrTy}, RetType{CharPtrTy}, NoEvalCall) 1323 .ArgConstraint(NotNull(ArgNo(0)))); 1324 1325 // char *getcwd(char *buf, size_t size); 1326 addToFunctionSummaryMap( 1327 "getcwd", 1328 Summary(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}, NoEvalCall) 1329 .ArgConstraint( 1330 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 1331 1332 if (Mode_tTy) { 1333 // int mkdir(const char *pathname, mode_t mode); 1334 addToFunctionSummaryMap("mkdir", 1335 Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy}, 1336 RetType{IntTy}, NoEvalCall) 1337 .ArgConstraint(NotNull(ArgNo(0)))); 1338 1339 // int mkdirat(int dirfd, const char *pathname, mode_t mode); 1340 addToFunctionSummaryMap( 1341 "mkdirat", Summary(ArgTypes{IntTy, ConstCharPtrTy, *Mode_tTy}, 1342 RetType{IntTy}, NoEvalCall) 1343 .ArgConstraint(NotNull(ArgNo(1)))); 1344 } 1345 1346 Optional<QualType> Dev_tTy = lookupType("dev_t", ACtx); 1347 1348 if (Mode_tTy && Dev_tTy) { 1349 // int mknod(const char *pathname, mode_t mode, dev_t dev); 1350 addToFunctionSummaryMap( 1351 "mknod", Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy, *Dev_tTy}, 1352 RetType{IntTy}, NoEvalCall) 1353 .ArgConstraint(NotNull(ArgNo(0)))); 1354 1355 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); 1356 addToFunctionSummaryMap("mknodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, 1357 *Mode_tTy, *Dev_tTy}, 1358 RetType{IntTy}, NoEvalCall) 1359 .ArgConstraint(NotNull(ArgNo(1)))); 1360 } 1361 1362 if (Mode_tTy) { 1363 // int chmod(const char *path, mode_t mode); 1364 addToFunctionSummaryMap("chmod", 1365 Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy}, 1366 RetType{IntTy}, NoEvalCall) 1367 .ArgConstraint(NotNull(ArgNo(0)))); 1368 1369 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); 1370 addToFunctionSummaryMap( 1371 "fchmodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, *Mode_tTy, IntTy}, 1372 RetType{IntTy}, NoEvalCall) 1373 .ArgConstraint(ArgumentCondition(0, WithinRange, 1374 Range(0, IntMax))) 1375 .ArgConstraint(NotNull(ArgNo(1)))); 1376 1377 // int fchmod(int fildes, mode_t mode); 1378 addToFunctionSummaryMap( 1379 "fchmod", 1380 Summary(ArgTypes{IntTy, *Mode_tTy}, RetType{IntTy}, NoEvalCall) 1381 .ArgConstraint( 1382 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1383 } 1384 1385 Optional<QualType> Uid_tTy = lookupType("uid_t", ACtx); 1386 Optional<QualType> Gid_tTy = lookupType("gid_t", ACtx); 1387 1388 if (Uid_tTy && Gid_tTy) { 1389 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, 1390 // int flags); 1391 addToFunctionSummaryMap( 1392 "fchownat", 1393 Summary(ArgTypes{IntTy, ConstCharPtrTy, *Uid_tTy, *Gid_tTy, IntTy}, 1394 RetType{IntTy}, NoEvalCall) 1395 .ArgConstraint( 1396 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1397 .ArgConstraint(NotNull(ArgNo(1)))); 1398 1399 // int chown(const char *path, uid_t owner, gid_t group); 1400 addToFunctionSummaryMap( 1401 "chown", Summary(ArgTypes{ConstCharPtrTy, *Uid_tTy, *Gid_tTy}, 1402 RetType{IntTy}, NoEvalCall) 1403 .ArgConstraint(NotNull(ArgNo(0)))); 1404 1405 // int lchown(const char *path, uid_t owner, gid_t group); 1406 addToFunctionSummaryMap( 1407 "lchown", Summary(ArgTypes{ConstCharPtrTy, *Uid_tTy, *Gid_tTy}, 1408 RetType{IntTy}, NoEvalCall) 1409 .ArgConstraint(NotNull(ArgNo(0)))); 1410 1411 // int fchown(int fildes, uid_t owner, gid_t group); 1412 addToFunctionSummaryMap( 1413 "fchown", Summary(ArgTypes{IntTy, *Uid_tTy, *Gid_tTy}, RetType{IntTy}, 1414 NoEvalCall) 1415 .ArgConstraint(ArgumentCondition(0, WithinRange, 1416 Range(0, IntMax)))); 1417 } 1418 1419 // int rmdir(const char *pathname); 1420 addToFunctionSummaryMap( 1421 "rmdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall) 1422 .ArgConstraint(NotNull(ArgNo(0)))); 1423 1424 // int chdir(const char *path); 1425 addToFunctionSummaryMap( 1426 "chdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall) 1427 .ArgConstraint(NotNull(ArgNo(0)))); 1428 1429 // int link(const char *oldpath, const char *newpath); 1430 addToFunctionSummaryMap("link", 1431 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, 1432 RetType{IntTy}, NoEvalCall) 1433 .ArgConstraint(NotNull(ArgNo(0))) 1434 .ArgConstraint(NotNull(ArgNo(1)))); 1435 1436 // int linkat(int fd1, const char *path1, int fd2, const char *path2, 1437 // int flag); 1438 addToFunctionSummaryMap( 1439 "linkat", 1440 Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy}, 1441 RetType{IntTy}, NoEvalCall) 1442 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1443 .ArgConstraint(NotNull(ArgNo(1))) 1444 .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax))) 1445 .ArgConstraint(NotNull(ArgNo(3)))); 1446 1447 // int unlink(const char *pathname); 1448 addToFunctionSummaryMap( 1449 "unlink", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall) 1450 .ArgConstraint(NotNull(ArgNo(0)))); 1451 1452 // int unlinkat(int fd, const char *path, int flag); 1453 addToFunctionSummaryMap( 1454 "unlinkat", 1455 Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}, 1456 NoEvalCall) 1457 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1458 .ArgConstraint(NotNull(ArgNo(1)))); 1459 1460 Optional<QualType> StructStatTy = lookupType("stat", ACtx); 1461 Optional<QualType> StructStatPtrTy, StructStatPtrRestrictTy; 1462 if (StructStatTy) { 1463 StructStatPtrTy = ACtx.getPointerType(*StructStatTy); 1464 StructStatPtrRestrictTy = getRestrictTy(*StructStatPtrTy); 1465 } 1466 1467 if (StructStatPtrTy) 1468 // int fstat(int fd, struct stat *statbuf); 1469 addToFunctionSummaryMap( 1470 "fstat", 1471 Summary(ArgTypes{IntTy, *StructStatPtrTy}, RetType{IntTy}, NoEvalCall) 1472 .ArgConstraint( 1473 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1474 .ArgConstraint(NotNull(ArgNo(1)))); 1475 1476 if (StructStatPtrRestrictTy) { 1477 // int stat(const char *restrict path, struct stat *restrict buf); 1478 addToFunctionSummaryMap( 1479 "stat", 1480 Summary(ArgTypes{ConstCharPtrRestrictTy, *StructStatPtrRestrictTy}, 1481 RetType{IntTy}, NoEvalCall) 1482 .ArgConstraint(NotNull(ArgNo(0))) 1483 .ArgConstraint(NotNull(ArgNo(1)))); 1484 1485 // int lstat(const char *restrict path, struct stat *restrict buf); 1486 addToFunctionSummaryMap( 1487 "lstat", 1488 Summary(ArgTypes{ConstCharPtrRestrictTy, *StructStatPtrRestrictTy}, 1489 RetType{IntTy}, NoEvalCall) 1490 .ArgConstraint(NotNull(ArgNo(0))) 1491 .ArgConstraint(NotNull(ArgNo(1)))); 1492 1493 // int fstatat(int fd, const char *restrict path, 1494 // struct stat *restrict buf, int flag); 1495 addToFunctionSummaryMap( 1496 "fstatat", Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy, 1497 *StructStatPtrRestrictTy, IntTy}, 1498 RetType{IntTy}, NoEvalCall) 1499 .ArgConstraint(ArgumentCondition(0, WithinRange, 1500 Range(0, IntMax))) 1501 .ArgConstraint(NotNull(ArgNo(1))) 1502 .ArgConstraint(NotNull(ArgNo(2)))); 1503 } 1504 1505 if (DirPtrTy) { 1506 // DIR *opendir(const char *name); 1507 addToFunctionSummaryMap("opendir", Summary(ArgTypes{ConstCharPtrTy}, 1508 RetType{*DirPtrTy}, NoEvalCall) 1509 .ArgConstraint(NotNull(ArgNo(0)))); 1510 1511 // DIR *fdopendir(int fd); 1512 addToFunctionSummaryMap( 1513 "fdopendir", Summary(ArgTypes{IntTy}, RetType{*DirPtrTy}, NoEvalCall) 1514 .ArgConstraint(ArgumentCondition(0, WithinRange, 1515 Range(0, IntMax)))); 1516 } 1517 1518 // int isatty(int fildes); 1519 addToFunctionSummaryMap( 1520 "isatty", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1521 .ArgConstraint( 1522 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1523 1524 if (FilePtrTy) { 1525 // FILE *popen(const char *command, const char *type); 1526 addToFunctionSummaryMap("popen", 1527 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, 1528 RetType{*FilePtrTy}, NoEvalCall) 1529 .ArgConstraint(NotNull(ArgNo(0))) 1530 .ArgConstraint(NotNull(ArgNo(1)))); 1531 1532 // int pclose(FILE *stream); 1533 addToFunctionSummaryMap( 1534 "pclose", Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall) 1535 .ArgConstraint(NotNull(ArgNo(0)))); 1536 } 1537 1538 // int close(int fildes); 1539 addToFunctionSummaryMap( 1540 "close", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1541 .ArgConstraint( 1542 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1543 1544 // long fpathconf(int fildes, int name); 1545 addToFunctionSummaryMap( 1546 "fpathconf", 1547 Summary(ArgTypes{IntTy, IntTy}, RetType{LongTy}, NoEvalCall) 1548 .ArgConstraint( 1549 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1550 1551 // long pathconf(const char *path, int name); 1552 addToFunctionSummaryMap("pathconf", Summary(ArgTypes{ConstCharPtrTy, IntTy}, 1553 RetType{LongTy}, NoEvalCall) 1554 .ArgConstraint(NotNull(ArgNo(0)))); 1555 1556 if (FilePtrTy) 1557 // FILE *fdopen(int fd, const char *mode); 1558 addToFunctionSummaryMap( 1559 "fdopen", Summary(ArgTypes{IntTy, ConstCharPtrTy}, 1560 RetType{*FilePtrTy}, NoEvalCall) 1561 .ArgConstraint( 1562 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1563 .ArgConstraint(NotNull(ArgNo(1)))); 1564 1565 if (DirPtrTy) { 1566 // void rewinddir(DIR *dir); 1567 addToFunctionSummaryMap( 1568 "rewinddir", Summary(ArgTypes{*DirPtrTy}, RetType{VoidTy}, NoEvalCall) 1569 .ArgConstraint(NotNull(ArgNo(0)))); 1570 1571 // void seekdir(DIR *dirp, long loc); 1572 addToFunctionSummaryMap("seekdir", Summary(ArgTypes{*DirPtrTy, LongTy}, 1573 RetType{VoidTy}, NoEvalCall) 1574 .ArgConstraint(NotNull(ArgNo(0)))); 1575 } 1576 1577 // int rand_r(unsigned int *seedp); 1578 addToFunctionSummaryMap("rand_r", Summary(ArgTypes{UnsignedIntPtrTy}, 1579 RetType{IntTy}, NoEvalCall) 1580 .ArgConstraint(NotNull(ArgNo(0)))); 1581 1582 // int strcasecmp(const char *s1, const char *s2); 1583 addToFunctionSummaryMap("strcasecmp", 1584 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, 1585 RetType{IntTy}, EvalCallAsPure) 1586 .ArgConstraint(NotNull(ArgNo(0))) 1587 .ArgConstraint(NotNull(ArgNo(1)))); 1588 1589 // int strncasecmp(const char *s1, const char *s2, size_t n); 1590 addToFunctionSummaryMap( 1591 "strncasecmp", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, SizeTy}, 1592 RetType{IntTy}, EvalCallAsPure) 1593 .ArgConstraint(NotNull(ArgNo(0))) 1594 .ArgConstraint(NotNull(ArgNo(1))) 1595 .ArgConstraint(ArgumentCondition( 1596 2, WithinRange, Range(0, SizeMax)))); 1597 1598 if (FilePtrTy && Off_tTy) { 1599 1600 // int fileno(FILE *stream); 1601 addToFunctionSummaryMap( 1602 "fileno", Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall) 1603 .ArgConstraint(NotNull(ArgNo(0)))); 1604 1605 // int fseeko(FILE *stream, off_t offset, int whence); 1606 addToFunctionSummaryMap("fseeko", 1607 Summary(ArgTypes{*FilePtrTy, *Off_tTy, IntTy}, 1608 RetType{IntTy}, NoEvalCall) 1609 .ArgConstraint(NotNull(ArgNo(0)))); 1610 1611 // off_t ftello(FILE *stream); 1612 addToFunctionSummaryMap( 1613 "ftello", Summary(ArgTypes{*FilePtrTy}, RetType{*Off_tTy}, NoEvalCall) 1614 .ArgConstraint(NotNull(ArgNo(0)))); 1615 } 1616 1617 if (Off_tTy) { 1618 Optional<RangeInt> Off_tMax = BVF.getMaxValue(*Off_tTy).getLimitedValue(); 1619 1620 // void *mmap(void *addr, size_t length, int prot, int flags, int fd, 1621 // off_t offset); 1622 addToFunctionSummaryMap( 1623 "mmap", 1624 Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, *Off_tTy}, 1625 RetType{VoidPtrTy}, NoEvalCall) 1626 .ArgConstraint( 1627 ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1628 .ArgConstraint( 1629 ArgumentCondition(4, WithinRange, Range(0, *Off_tMax)))); 1630 } 1631 1632 Optional<QualType> Off64_tTy = lookupType("off64_t", ACtx); 1633 Optional<RangeInt> Off64_tMax; 1634 if (Off64_tTy) { 1635 Off64_tMax = BVF.getMaxValue(*Off_tTy).getLimitedValue(); 1636 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, 1637 // off64_t offset); 1638 addToFunctionSummaryMap( 1639 "mmap64", 1640 Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, *Off64_tTy}, 1641 RetType{VoidPtrTy}, NoEvalCall) 1642 .ArgConstraint( 1643 ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1644 .ArgConstraint( 1645 ArgumentCondition(4, WithinRange, Range(0, *Off64_tMax)))); 1646 } 1647 1648 // int pipe(int fildes[2]); 1649 addToFunctionSummaryMap( 1650 "pipe", Summary(ArgTypes{IntPtrTy}, RetType{IntTy}, NoEvalCall) 1651 .ArgConstraint(NotNull(ArgNo(0)))); 1652 1653 if (Off_tTy) 1654 // off_t lseek(int fildes, off_t offset, int whence); 1655 addToFunctionSummaryMap( 1656 "lseek", Summary(ArgTypes{IntTy, *Off_tTy, IntTy}, RetType{*Off_tTy}, 1657 NoEvalCall) 1658 .ArgConstraint(ArgumentCondition(0, WithinRange, 1659 Range(0, IntMax)))); 1660 1661 Optional<QualType> Ssize_tTy = lookupType("ssize_t", ACtx); 1662 1663 if (Ssize_tTy) { 1664 // ssize_t readlink(const char *restrict path, char *restrict buf, 1665 // size_t bufsize); 1666 addToFunctionSummaryMap( 1667 "readlink", 1668 Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1669 RetType{*Ssize_tTy}, NoEvalCall) 1670 .ArgConstraint(NotNull(ArgNo(0))) 1671 .ArgConstraint(NotNull(ArgNo(1))) 1672 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1673 /*BufSize=*/ArgNo(2))) 1674 .ArgConstraint( 1675 ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); 1676 1677 // ssize_t readlinkat(int fd, const char *restrict path, 1678 // char *restrict buf, size_t bufsize); 1679 addToFunctionSummaryMap( 1680 "readlinkat", Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy, 1681 CharPtrRestrictTy, SizeTy}, 1682 RetType{*Ssize_tTy}, NoEvalCall) 1683 .ArgConstraint(ArgumentCondition(0, WithinRange, 1684 Range(0, IntMax))) 1685 .ArgConstraint(NotNull(ArgNo(1))) 1686 .ArgConstraint(NotNull(ArgNo(2))) 1687 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), 1688 /*BufSize=*/ArgNo(3))) 1689 .ArgConstraint(ArgumentCondition( 1690 3, WithinRange, Range(0, SizeMax)))); 1691 } 1692 1693 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char 1694 // *newpath); 1695 addToFunctionSummaryMap("renameat", Summary(ArgTypes{IntTy, ConstCharPtrTy, 1696 IntTy, ConstCharPtrTy}, 1697 RetType{IntTy}, NoEvalCall) 1698 .ArgConstraint(NotNull(ArgNo(1))) 1699 .ArgConstraint(NotNull(ArgNo(3)))); 1700 1701 // char *realpath(const char *restrict file_name, 1702 // char *restrict resolved_name); 1703 addToFunctionSummaryMap( 1704 "realpath", Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy}, 1705 RetType{CharPtrTy}, NoEvalCall) 1706 .ArgConstraint(NotNull(ArgNo(0)))); 1707 1708 QualType CharPtrConstPtr = ACtx.getPointerType(CharPtrTy.withConst()); 1709 1710 // int execv(const char *path, char *const argv[]); 1711 addToFunctionSummaryMap("execv", 1712 Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, 1713 RetType{IntTy}, NoEvalCall) 1714 .ArgConstraint(NotNull(ArgNo(0)))); 1715 1716 // int execvp(const char *file, char *const argv[]); 1717 addToFunctionSummaryMap("execvp", 1718 Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, 1719 RetType{IntTy}, NoEvalCall) 1720 .ArgConstraint(NotNull(ArgNo(0)))); 1721 1722 // int getopt(int argc, char * const argv[], const char *optstring); 1723 addToFunctionSummaryMap( 1724 "getopt", 1725 Summary(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy}, 1726 RetType{IntTy}, NoEvalCall) 1727 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1728 .ArgConstraint(NotNull(ArgNo(1))) 1729 .ArgConstraint(NotNull(ArgNo(2)))); 1730 1731 Optional<QualType> StructSockaddrTy = lookupType("sockaddr", ACtx); 1732 Optional<QualType> StructSockaddrPtrTy, ConstStructSockaddrPtrTy, 1733 StructSockaddrPtrRestrictTy, ConstStructSockaddrPtrRestrictTy; 1734 if (StructSockaddrTy) { 1735 StructSockaddrPtrTy = ACtx.getPointerType(*StructSockaddrTy); 1736 ConstStructSockaddrPtrTy = 1737 ACtx.getPointerType(StructSockaddrTy->withConst()); 1738 StructSockaddrPtrRestrictTy = getRestrictTy(*StructSockaddrPtrTy); 1739 ConstStructSockaddrPtrRestrictTy = 1740 getRestrictTy(*ConstStructSockaddrPtrTy); 1741 } 1742 Optional<QualType> Socklen_tTy = lookupType("socklen_t", ACtx); 1743 Optional<QualType> Socklen_tPtrTy, Socklen_tPtrRestrictTy; 1744 Optional<RangeInt> Socklen_tMax; 1745 if (Socklen_tTy) { 1746 Socklen_tMax = BVF.getMaxValue(*Socklen_tTy).getLimitedValue(); 1747 Socklen_tPtrTy = ACtx.getPointerType(*Socklen_tTy); 1748 Socklen_tPtrRestrictTy = getRestrictTy(*Socklen_tPtrTy); 1749 } 1750 1751 // In 'socket.h' of some libc implementations with C99, sockaddr parameter 1752 // is a transparent union of the underlying sockaddr_ family of pointers 1753 // instead of being a pointer to struct sockaddr. In these cases, the 1754 // standardized signature will not match, thus we try to match with another 1755 // signature that has the joker Irrelevant type. We also remove those 1756 // constraints which require pointer types for the sockaddr param. 1757 if (StructSockaddrPtrRestrictTy && Socklen_tPtrRestrictTy) { 1758 auto Accept = Summary(NoEvalCall) 1759 .ArgConstraint(ArgumentCondition(0, WithinRange, 1760 Range(0, IntMax))); 1761 if (!addToFunctionSummaryMap( 1762 "accept", 1763 // int accept(int socket, struct sockaddr *restrict address, 1764 // socklen_t *restrict address_len); 1765 Signature(ArgTypes{IntTy, *StructSockaddrPtrRestrictTy, 1766 *Socklen_tPtrRestrictTy}, 1767 RetType{IntTy}), 1768 Accept)) 1769 addToFunctionSummaryMap( 1770 "accept", 1771 Signature(ArgTypes{IntTy, Irrelevant, *Socklen_tPtrRestrictTy}, 1772 RetType{IntTy}), 1773 Accept); 1774 1775 // int bind(int socket, const struct sockaddr *address, socklen_t 1776 // address_len); 1777 if (!addToFunctionSummaryMap( 1778 "bind", 1779 Summary(ArgTypes{IntTy, *ConstStructSockaddrPtrTy, *Socklen_tTy}, 1780 RetType{IntTy}, NoEvalCall) 1781 .ArgConstraint( 1782 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1783 .ArgConstraint(NotNull(ArgNo(1))) 1784 .ArgConstraint( 1785 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2))) 1786 .ArgConstraint(ArgumentCondition(2, WithinRange, 1787 Range(0, *Socklen_tMax))))) 1788 // Do not add constraints on sockaddr. 1789 addToFunctionSummaryMap( 1790 "bind", Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tTy}, 1791 RetType{IntTy}, NoEvalCall) 1792 .ArgConstraint( 1793 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1794 .ArgConstraint(ArgumentCondition( 1795 2, WithinRange, Range(0, *Socklen_tMax)))); 1796 1797 // int getpeername(int socket, struct sockaddr *restrict address, 1798 // socklen_t *restrict address_len); 1799 if (!addToFunctionSummaryMap( 1800 "getpeername", 1801 Summary(ArgTypes{IntTy, *StructSockaddrPtrRestrictTy, 1802 *Socklen_tPtrRestrictTy}, 1803 RetType{IntTy}, NoEvalCall) 1804 .ArgConstraint( 1805 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1806 .ArgConstraint(NotNull(ArgNo(1))) 1807 .ArgConstraint(NotNull(ArgNo(2))))) 1808 addToFunctionSummaryMap( 1809 "getpeername", 1810 Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tPtrRestrictTy}, 1811 RetType{IntTy}, NoEvalCall) 1812 .ArgConstraint( 1813 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1814 1815 // int getsockname(int socket, struct sockaddr *restrict address, 1816 // socklen_t *restrict address_len); 1817 if (!addToFunctionSummaryMap( 1818 "getsockname", 1819 Summary(ArgTypes{IntTy, *StructSockaddrPtrRestrictTy, 1820 *Socklen_tPtrRestrictTy}, 1821 RetType{IntTy}, NoEvalCall) 1822 .ArgConstraint( 1823 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1824 .ArgConstraint(NotNull(ArgNo(1))) 1825 .ArgConstraint(NotNull(ArgNo(2))))) 1826 addToFunctionSummaryMap( 1827 "getsockname", 1828 Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tPtrRestrictTy}, 1829 RetType{IntTy}, NoEvalCall) 1830 .ArgConstraint( 1831 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1832 1833 // int connect(int socket, const struct sockaddr *address, socklen_t 1834 // address_len); 1835 if (!addToFunctionSummaryMap( 1836 "connect", 1837 Summary(ArgTypes{IntTy, *ConstStructSockaddrPtrTy, *Socklen_tTy}, 1838 RetType{IntTy}, NoEvalCall) 1839 .ArgConstraint( 1840 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1841 .ArgConstraint(NotNull(ArgNo(1))))) 1842 addToFunctionSummaryMap( 1843 "connect", Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tTy}, 1844 RetType{IntTy}, NoEvalCall) 1845 .ArgConstraint(ArgumentCondition(0, WithinRange, 1846 Range(0, IntMax)))); 1847 1848 auto Recvfrom = Summary(NoEvalCall) 1849 .ArgConstraint(ArgumentCondition(0, WithinRange, 1850 Range(0, IntMax))) 1851 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1852 /*BufSize=*/ArgNo(2))); 1853 if (Ssize_tTy && 1854 !addToFunctionSummaryMap( 1855 "recvfrom", 1856 // ssize_t recvfrom(int socket, void *restrict buffer, 1857 // size_t length, 1858 // int flags, struct sockaddr *restrict address, 1859 // socklen_t *restrict address_len); 1860 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 1861 *StructSockaddrPtrRestrictTy, 1862 *Socklen_tPtrRestrictTy}, 1863 RetType{*Ssize_tTy}), 1864 Recvfrom)) 1865 addToFunctionSummaryMap( 1866 "recvfrom", 1867 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 1868 Irrelevant, *Socklen_tPtrRestrictTy}, 1869 RetType{*Ssize_tTy}), 1870 Recvfrom); 1871 1872 auto Sendto = Summary(NoEvalCall) 1873 .ArgConstraint( 1874 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1875 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1876 /*BufSize=*/ArgNo(2))); 1877 if (Ssize_tTy && 1878 !addToFunctionSummaryMap( 1879 "sendto", 1880 // ssize_t sendto(int socket, const void *message, size_t length, 1881 // int flags, const struct sockaddr *dest_addr, 1882 // socklen_t dest_len); 1883 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, 1884 *ConstStructSockaddrPtrTy, *Socklen_tTy}, 1885 RetType{*Ssize_tTy}), 1886 Sendto)) 1887 addToFunctionSummaryMap( 1888 "sendto", 1889 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant, 1890 *Socklen_tTy}, 1891 RetType{*Ssize_tTy}), 1892 Sendto); 1893 } 1894 1895 // int listen(int sockfd, int backlog); 1896 addToFunctionSummaryMap( 1897 "listen", Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall) 1898 .ArgConstraint( 1899 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1900 1901 if (Ssize_tTy) 1902 // ssize_t recv(int sockfd, void *buf, size_t len, int flags); 1903 addToFunctionSummaryMap( 1904 "recv", Summary(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, 1905 RetType{*Ssize_tTy}, NoEvalCall) 1906 .ArgConstraint( 1907 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1908 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1909 /*BufSize=*/ArgNo(2)))); 1910 1911 Optional<QualType> StructMsghdrTy = lookupType("msghdr", ACtx); 1912 Optional<QualType> StructMsghdrPtrTy, ConstStructMsghdrPtrTy; 1913 if (StructMsghdrTy) { 1914 StructMsghdrPtrTy = ACtx.getPointerType(*StructMsghdrTy); 1915 ConstStructMsghdrPtrTy = ACtx.getPointerType(StructMsghdrTy->withConst()); 1916 } 1917 1918 if (Ssize_tTy && StructMsghdrPtrTy) 1919 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 1920 addToFunctionSummaryMap( 1921 "recvmsg", Summary(ArgTypes{IntTy, *StructMsghdrPtrTy, IntTy}, 1922 RetType{*Ssize_tTy}, NoEvalCall) 1923 .ArgConstraint(ArgumentCondition(0, WithinRange, 1924 Range(0, IntMax)))); 1925 1926 if (Ssize_tTy && ConstStructMsghdrPtrTy) 1927 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 1928 addToFunctionSummaryMap( 1929 "sendmsg", Summary(ArgTypes{IntTy, *ConstStructMsghdrPtrTy, IntTy}, 1930 RetType{*Ssize_tTy}, NoEvalCall) 1931 .ArgConstraint(ArgumentCondition(0, WithinRange, 1932 Range(0, IntMax)))); 1933 1934 if (Socklen_tTy) 1935 // int setsockopt(int socket, int level, int option_name, 1936 // const void *option_value, socklen_t option_len); 1937 addToFunctionSummaryMap( 1938 "setsockopt", 1939 Summary(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, *Socklen_tTy}, 1940 RetType{IntTy}, NoEvalCall) 1941 .ArgConstraint(NotNull(ArgNo(3))) 1942 .ArgConstraint( 1943 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4))) 1944 .ArgConstraint( 1945 ArgumentCondition(4, WithinRange, Range(0, *Socklen_tMax)))); 1946 1947 if (Socklen_tPtrRestrictTy) 1948 // int getsockopt(int socket, int level, int option_name, 1949 // void *restrict option_value, 1950 // socklen_t *restrict option_len); 1951 addToFunctionSummaryMap( 1952 "getsockopt", Summary(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy, 1953 *Socklen_tPtrRestrictTy}, 1954 RetType{IntTy}, NoEvalCall) 1955 .ArgConstraint(NotNull(ArgNo(3))) 1956 .ArgConstraint(NotNull(ArgNo(4)))); 1957 1958 if (Ssize_tTy) 1959 // ssize_t send(int sockfd, const void *buf, size_t len, int flags); 1960 addToFunctionSummaryMap( 1961 "send", Summary(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy}, 1962 RetType{*Ssize_tTy}, NoEvalCall) 1963 .ArgConstraint( 1964 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1965 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1966 /*BufSize=*/ArgNo(2)))); 1967 1968 // int socketpair(int domain, int type, int protocol, int sv[2]); 1969 addToFunctionSummaryMap("socketpair", 1970 Summary(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, 1971 RetType{IntTy}, NoEvalCall) 1972 .ArgConstraint(NotNull(ArgNo(3)))); 1973 1974 if (ConstStructSockaddrPtrRestrictTy && Socklen_tTy) 1975 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, 1976 // char *restrict node, socklen_t nodelen, 1977 // char *restrict service, 1978 // socklen_t servicelen, int flags); 1979 // 1980 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr 1981 // parameter is never handled as a transparent union in netdb.h 1982 addToFunctionSummaryMap( 1983 "getnameinfo", 1984 Summary(ArgTypes{*ConstStructSockaddrPtrRestrictTy, *Socklen_tTy, 1985 CharPtrRestrictTy, *Socklen_tTy, CharPtrRestrictTy, 1986 *Socklen_tTy, IntTy}, 1987 RetType{IntTy}, NoEvalCall) 1988 .ArgConstraint( 1989 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))) 1990 .ArgConstraint( 1991 ArgumentCondition(1, WithinRange, Range(0, *Socklen_tMax))) 1992 .ArgConstraint( 1993 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3))) 1994 .ArgConstraint( 1995 ArgumentCondition(3, WithinRange, Range(0, *Socklen_tMax))) 1996 .ArgConstraint( 1997 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5))) 1998 .ArgConstraint( 1999 ArgumentCondition(5, WithinRange, Range(0, *Socklen_tMax)))); 2000 } 2001 2002 // Functions for testing. 2003 if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) { 2004 addToFunctionSummaryMap( 2005 "__two_constrained_args", 2006 Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure) 2007 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))) 2008 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1)))); 2009 addToFunctionSummaryMap( 2010 "__arg_constrained_twice", 2011 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 2012 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))) 2013 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2)))); 2014 addToFunctionSummaryMap( 2015 "__defaultparam", 2016 Summary(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}, EvalCallAsPure) 2017 .ArgConstraint(NotNull(ArgNo(0)))); 2018 addToFunctionSummaryMap("__variadic", 2019 Summary(ArgTypes{VoidPtrTy, ConstCharPtrTy}, 2020 RetType{IntTy}, EvalCallAsPure) 2021 .ArgConstraint(NotNull(ArgNo(0))) 2022 .ArgConstraint(NotNull(ArgNo(1)))); 2023 addToFunctionSummaryMap( 2024 "__buf_size_arg_constraint", 2025 Summary(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}, 2026 EvalCallAsPure) 2027 .ArgConstraint( 2028 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))); 2029 addToFunctionSummaryMap( 2030 "__buf_size_arg_constraint_mul", 2031 Summary(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}, 2032 EvalCallAsPure) 2033 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 2034 /*BufSizeMultiplier=*/ArgNo(2)))); 2035 } 2036 } 2037 2038 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 2039 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>(); 2040 Checker->DisplayLoadedSummaries = 2041 mgr.getAnalyzerOptions().getCheckerBooleanOption( 2042 Checker, "DisplayLoadedSummaries"); 2043 Checker->ModelPOSIX = 2044 mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX"); 2045 } 2046 2047 bool ento::shouldRegisterStdCLibraryFunctionsChecker( 2048 const CheckerManager &mgr) { 2049 return true; 2050 } 2051 2052 #define REGISTER_CHECKER(name) \ 2053 void ento::register##name(CheckerManager &mgr) { \ 2054 StdLibraryFunctionsChecker *checker = \ 2055 mgr.getChecker<StdLibraryFunctionsChecker>(); \ 2056 checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \ 2057 checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \ 2058 mgr.getCurrentCheckerName(); \ 2059 } \ 2060 \ 2061 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 2062 2063 REGISTER_CHECKER(StdCLibraryFunctionArgsChecker) 2064 REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker) 2065