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