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