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