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