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 the number of arguments. 748 if (FD->param_size() != ArgTys.size()) 749 return false; 750 751 // The "restrict" keyword is illegal in C++, however, many libc 752 // implementations use the "__restrict" compiler intrinsic in functions 753 // prototypes. The "__restrict" keyword qualifies a type as a restricted type 754 // even in C++. 755 // In case of any non-C99 languages, we don't want to match based on the 756 // restrict qualifier because we cannot know if the given libc implementation 757 // qualifies the paramter type or not. 758 auto RemoveRestrict = [&FD](QualType T) { 759 if (!FD->getASTContext().getLangOpts().C99) 760 T.removeLocalRestrict(); 761 return T; 762 }; 763 764 // Check the return type. 765 if (!isIrrelevant(RetTy)) { 766 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType()); 767 if (RetTy != FDRetTy) 768 return false; 769 } 770 771 // Check the argument types. 772 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) { 773 QualType ArgTy = ArgTys[I]; 774 if (isIrrelevant(ArgTy)) 775 continue; 776 QualType FDArgTy = 777 RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType()); 778 if (ArgTy != FDArgTy) 779 return false; 780 } 781 782 return true; 783 } 784 785 Optional<StdLibraryFunctionsChecker::Summary> 786 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, 787 CheckerContext &C) const { 788 if (!FD) 789 return None; 790 791 initFunctionSummaries(C); 792 793 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl()); 794 if (FSMI == FunctionSummaryMap.end()) 795 return None; 796 return FSMI->second; 797 } 798 799 Optional<StdLibraryFunctionsChecker::Summary> 800 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call, 801 CheckerContext &C) const { 802 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 803 if (!FD) 804 return None; 805 return findFunctionSummary(FD, C); 806 } 807 808 void StdLibraryFunctionsChecker::initFunctionSummaries( 809 CheckerContext &C) const { 810 if (!FunctionSummaryMap.empty()) 811 return; 812 813 SValBuilder &SVB = C.getSValBuilder(); 814 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 815 const ASTContext &ACtx = BVF.getContext(); 816 817 // Helper class to lookup a type by its name. 818 class LookupType { 819 const ASTContext &ACtx; 820 821 public: 822 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {} 823 824 // Find the type. If not found then the optional is not set. 825 llvm::Optional<QualType> operator()(StringRef Name) { 826 IdentifierInfo &II = ACtx.Idents.get(Name); 827 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 828 if (LookupRes.size() == 0) 829 return None; 830 831 // Prioritze typedef declarations. 832 // This is needed in case of C struct typedefs. E.g.: 833 // typedef struct FILE FILE; 834 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' 835 // and we have a TypedefDecl with the name 'FILE'. 836 for (Decl *D : LookupRes) 837 if (auto *TD = dyn_cast<TypedefNameDecl>(D)) 838 return ACtx.getTypeDeclType(TD).getCanonicalType(); 839 840 // Find the first TypeDecl. 841 // There maybe cases when a function has the same name as a struct. 842 // E.g. in POSIX: `struct stat` and the function `stat()`: 843 // int stat(const char *restrict path, struct stat *restrict buf); 844 for (Decl *D : LookupRes) 845 if (auto *TD = dyn_cast<TypeDecl>(D)) 846 return ACtx.getTypeDeclType(TD).getCanonicalType(); 847 return None; 848 } 849 } lookupTy(ACtx); 850 851 // Below are auxiliary classes to handle optional types that we get as a 852 // result of the lookup. 853 class GetRestrictTy { 854 const ASTContext &ACtx; 855 856 public: 857 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {} 858 QualType operator()(QualType Ty) { 859 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty; 860 } 861 Optional<QualType> operator()(Optional<QualType> Ty) { 862 if (Ty) 863 return operator()(*Ty); 864 return None; 865 } 866 } getRestrictTy(ACtx); 867 class GetPointerTy { 868 const ASTContext &ACtx; 869 870 public: 871 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {} 872 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); } 873 Optional<QualType> operator()(Optional<QualType> Ty) { 874 if (Ty) 875 return operator()(*Ty); 876 return None; 877 } 878 } getPointerTy(ACtx); 879 class { 880 public: 881 Optional<QualType> operator()(Optional<QualType> Ty) { 882 return Ty ? Optional<QualType>(Ty->withConst()) : None; 883 } 884 QualType operator()(QualType Ty) { return Ty.withConst(); } 885 } getConstTy; 886 class GetMaxValue { 887 BasicValueFactory &BVF; 888 889 public: 890 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {} 891 Optional<RangeInt> operator()(QualType Ty) { 892 return BVF.getMaxValue(Ty).getLimitedValue(); 893 } 894 Optional<RangeInt> operator()(Optional<QualType> Ty) { 895 if (Ty) { 896 return operator()(*Ty); 897 } 898 return None; 899 } 900 } getMaxValue(BVF); 901 902 // These types are useful for writing specifications quickly, 903 // New specifications should probably introduce more types. 904 // Some types are hard to obtain from the AST, eg. "ssize_t". 905 // In such cases it should be possible to provide multiple variants 906 // of function summary for common cases (eg. ssize_t could be int or long 907 // or long long, so three summary variants would be enough). 908 // Of course, function variants are also useful for C++ overloads. 909 const QualType VoidTy = ACtx.VoidTy; 910 const QualType CharTy = ACtx.CharTy; 911 const QualType WCharTy = ACtx.WCharTy; 912 const QualType IntTy = ACtx.IntTy; 913 const QualType UnsignedIntTy = ACtx.UnsignedIntTy; 914 const QualType LongTy = ACtx.LongTy; 915 const QualType LongLongTy = ACtx.LongLongTy; 916 const QualType SizeTy = ACtx.getSizeType(); 917 918 const QualType VoidPtrTy = getPointerTy(VoidTy); // void * 919 const QualType IntPtrTy = getPointerTy(IntTy); // int * 920 const QualType UnsignedIntPtrTy = 921 getPointerTy(UnsignedIntTy); // unsigned int * 922 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy); 923 const QualType ConstVoidPtrTy = 924 getPointerTy(getConstTy(VoidTy)); // const void * 925 const QualType CharPtrTy = getPointerTy(CharTy); // char * 926 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy); 927 const QualType ConstCharPtrTy = 928 getPointerTy(getConstTy(CharTy)); // const char * 929 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy); 930 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t * 931 const QualType ConstWchar_tPtrTy = 932 getPointerTy(getConstTy(WCharTy)); // const wchar_t * 933 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy); 934 935 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 936 const RangeInt UnsignedIntMax = 937 BVF.getMaxValue(UnsignedIntTy).getLimitedValue(); 938 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 939 const RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue(); 940 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue(); 941 942 // Set UCharRangeMax to min of int or uchar maximum value. 943 // The C standard states that the arguments of functions like isalpha must 944 // be representable as an unsigned char. Their type is 'int', so the max 945 // value of the argument should be min(UCharMax, IntMax). This just happen 946 // to be true for commonly used and well tested instruction set 947 // architectures, but not for others. 948 const RangeInt UCharRangeMax = 949 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax); 950 951 // The platform dependent value of EOF. 952 // Try our best to parse this from the Preprocessor, otherwise fallback to -1. 953 const auto EOFv = [&C]() -> RangeInt { 954 if (const llvm::Optional<int> OptInt = 955 tryExpandAsInteger("EOF", C.getPreprocessor())) 956 return *OptInt; 957 return -1; 958 }(); 959 960 // Auxiliary class to aid adding summaries to the summary map. 961 struct AddToFunctionSummaryMap { 962 const ASTContext &ACtx; 963 FunctionSummaryMapType ⤅ 964 bool DisplayLoadedSummaries; 965 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM, 966 bool DisplayLoadedSummaries) 967 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) { 968 } 969 970 // Add a summary to a FunctionDecl found by lookup. The lookup is performed 971 // by the given Name, and in the global scope. The summary will be attached 972 // to the found FunctionDecl only if the signatures match. 973 // 974 // Returns true if the summary has been added, false otherwise. 975 // FIXME remove all overloads without the explicit Signature parameter. 976 bool operator()(StringRef Name, Summary S) { 977 if (S.hasInvalidSignature()) 978 return false; 979 IdentifierInfo &II = ACtx.Idents.get(Name); 980 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 981 if (LookupRes.size() == 0) 982 return false; 983 for (Decl *D : LookupRes) { 984 if (auto *FD = dyn_cast<FunctionDecl>(D)) { 985 if (S.matchesAndSet(FD)) { 986 auto Res = Map.insert({FD->getCanonicalDecl(), S}); 987 assert(Res.second && "Function already has a summary set!"); 988 (void)Res; 989 if (DisplayLoadedSummaries) { 990 llvm::errs() << "Loaded summary for: "; 991 FD->print(llvm::errs()); 992 llvm::errs() << "\n"; 993 } 994 return true; 995 } 996 } 997 } 998 return false; 999 } 1000 // Add the summary with the Signature explicitly given. 1001 bool operator()(StringRef Name, Signature Sign, Summary Sum) { 1002 return operator()(Name, Sum.setSignature(Sign)); 1003 } 1004 // Add several summaries for the given name. 1005 void operator()(StringRef Name, const std::vector<Summary> &Summaries) { 1006 for (const Summary &S : Summaries) 1007 operator()(Name, S); 1008 } 1009 // Add the same summary for different names with the Signature explicitly 1010 // given. 1011 void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) { 1012 for (StringRef Name : Names) 1013 operator()(Name, Sign, Sum); 1014 } 1015 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries); 1016 1017 // Below are helpers functions to create the summaries. 1018 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, 1019 IntRangeVector Ranges) { 1020 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges); 1021 }; 1022 auto BufferSize = [](auto... Args) { 1023 return std::make_shared<BufferSizeConstraint>(Args...); 1024 }; 1025 struct { 1026 auto operator()(RangeKind Kind, IntRangeVector Ranges) { 1027 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges); 1028 } 1029 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) { 1030 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN); 1031 } 1032 } ReturnValueCondition; 1033 struct { 1034 auto operator()(RangeInt b, RangeInt e) { 1035 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}}; 1036 } 1037 auto operator()(RangeInt b, Optional<RangeInt> e) { 1038 if (e) 1039 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}}; 1040 return IntRangeVector{}; 1041 } 1042 } Range; 1043 auto SingleValue = [](RangeInt v) { 1044 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}}; 1045 }; 1046 auto LessThanOrEq = BO_LE; 1047 auto NotNull = [&](ArgNo ArgN) { 1048 return std::make_shared<NotNullConstraint>(ArgN); 1049 }; 1050 1051 Optional<QualType> FileTy = lookupTy("FILE"); 1052 Optional<QualType> FilePtrTy = getPointerTy(FileTy); 1053 Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy); 1054 1055 // Templates for summaries that are reused by many functions. 1056 auto Getc = [&]() { 1057 return Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall) 1058 .Case({ReturnValueCondition(WithinRange, 1059 {{EOFv, EOFv}, {0, UCharRangeMax}})}); 1060 }; 1061 auto Read = [&](RetType R, RangeInt Max) { 1062 return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R}, 1063 NoEvalCall) 1064 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1065 ReturnValueCondition(WithinRange, Range(-1, Max))}); 1066 }; 1067 auto Fread = [&]() { 1068 return Summary( 1069 ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy}, 1070 RetType{SizeTy}, NoEvalCall) 1071 .Case({ 1072 ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1073 }) 1074 .ArgConstraint(NotNull(ArgNo(0))); 1075 }; 1076 auto Fwrite = [&]() { 1077 return Summary(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, SizeTy, 1078 FilePtrRestrictTy}, 1079 RetType{SizeTy}, NoEvalCall) 1080 .Case({ 1081 ReturnValueCondition(LessThanOrEq, ArgNo(2)), 1082 }) 1083 .ArgConstraint(NotNull(ArgNo(0))); 1084 }; 1085 auto Getline = [&](RetType R, RangeInt Max) { 1086 return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R}, 1087 NoEvalCall) 1088 .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})}); 1089 }; 1090 1091 // We are finally ready to define specifications for all supported functions. 1092 // 1093 // Argument ranges should always cover all variants. If return value 1094 // is completely unknown, omit it from the respective range set. 1095 // 1096 // Every item in the list of range sets represents a particular 1097 // execution path the analyzer would need to explore once 1098 // the call is modeled - a new program state is constructed 1099 // for every range set, and each range line in the range set 1100 // corresponds to a specific constraint within this state. 1101 1102 // The isascii() family of functions. 1103 // The behavior is undefined if the value of the argument is not 1104 // representable as unsigned char or is not equal to EOF. See e.g. C99 1105 // 7.4.1.2 The isalpha function (p: 181-182). 1106 addToFunctionSummaryMap( 1107 "isalnum", 1108 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1109 // Boils down to isupper() or islower() or isdigit(). 1110 .Case({ArgumentCondition(0U, WithinRange, 1111 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}), 1112 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1113 // The locale-specific range. 1114 // No post-condition. We are completely unaware of 1115 // locale-specific return values. 1116 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1117 .Case( 1118 {ArgumentCondition( 1119 0U, OutOfRange, 1120 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1121 ReturnValueCondition(WithinRange, SingleValue(0))}) 1122 .ArgConstraint(ArgumentCondition( 1123 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1124 addToFunctionSummaryMap( 1125 "isalpha", 1126 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1127 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}), 1128 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1129 // The locale-specific range. 1130 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1131 .Case({ArgumentCondition( 1132 0U, OutOfRange, 1133 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}), 1134 ReturnValueCondition(WithinRange, SingleValue(0))})); 1135 addToFunctionSummaryMap( 1136 "isascii", 1137 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1138 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1139 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1140 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)), 1141 ReturnValueCondition(WithinRange, SingleValue(0))})); 1142 addToFunctionSummaryMap( 1143 "isblank", 1144 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1145 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}), 1146 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1147 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}), 1148 ReturnValueCondition(WithinRange, SingleValue(0))})); 1149 addToFunctionSummaryMap( 1150 "iscntrl", 1151 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1152 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}), 1153 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1154 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}), 1155 ReturnValueCondition(WithinRange, SingleValue(0))})); 1156 addToFunctionSummaryMap( 1157 "isdigit", 1158 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1159 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')), 1160 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1161 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')), 1162 ReturnValueCondition(WithinRange, SingleValue(0))})); 1163 addToFunctionSummaryMap( 1164 "isgraph", 1165 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1166 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)), 1167 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1168 .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)), 1169 ReturnValueCondition(WithinRange, SingleValue(0))})); 1170 addToFunctionSummaryMap( 1171 "islower", 1172 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1173 // Is certainly lowercase. 1174 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')), 1175 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1176 // Is ascii but not lowercase. 1177 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 1178 ArgumentCondition(0U, OutOfRange, Range('a', 'z')), 1179 ReturnValueCondition(WithinRange, SingleValue(0))}) 1180 // The locale-specific range. 1181 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1182 // Is not an unsigned char. 1183 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)), 1184 ReturnValueCondition(WithinRange, SingleValue(0))})); 1185 addToFunctionSummaryMap( 1186 "isprint", 1187 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1188 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)), 1189 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1190 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)), 1191 ReturnValueCondition(WithinRange, SingleValue(0))})); 1192 addToFunctionSummaryMap( 1193 "ispunct", 1194 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1195 .Case({ArgumentCondition( 1196 0U, WithinRange, 1197 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1198 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1199 .Case({ArgumentCondition( 1200 0U, OutOfRange, 1201 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 1202 ReturnValueCondition(WithinRange, SingleValue(0))})); 1203 addToFunctionSummaryMap( 1204 "isspace", 1205 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1206 // Space, '\f', '\n', '\r', '\t', '\v'. 1207 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}), 1208 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1209 // The locale-specific range. 1210 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1211 .Case({ArgumentCondition(0U, OutOfRange, 1212 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}), 1213 ReturnValueCondition(WithinRange, SingleValue(0))})); 1214 addToFunctionSummaryMap( 1215 "isupper", 1216 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1217 // Is certainly uppercase. 1218 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')), 1219 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1220 // The locale-specific range. 1221 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})}) 1222 // Other. 1223 .Case({ArgumentCondition(0U, OutOfRange, 1224 {{'A', 'Z'}, {128, UCharRangeMax}}), 1225 ReturnValueCondition(WithinRange, SingleValue(0))})); 1226 addToFunctionSummaryMap( 1227 "isxdigit", 1228 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1229 .Case({ArgumentCondition(0U, WithinRange, 1230 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1231 ReturnValueCondition(OutOfRange, SingleValue(0))}) 1232 .Case({ArgumentCondition(0U, OutOfRange, 1233 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 1234 ReturnValueCondition(WithinRange, SingleValue(0))})); 1235 addToFunctionSummaryMap( 1236 "toupper", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1237 .ArgConstraint(ArgumentCondition( 1238 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1239 addToFunctionSummaryMap( 1240 "tolower", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1241 .ArgConstraint(ArgumentCondition( 1242 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1243 addToFunctionSummaryMap( 1244 "toascii", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 1245 .ArgConstraint(ArgumentCondition( 1246 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))); 1247 1248 // The getc() family of functions that returns either a char or an EOF. 1249 addToFunctionSummaryMap("getc", Getc()); 1250 addToFunctionSummaryMap("fgetc", Getc()); 1251 addToFunctionSummaryMap( 1252 "getchar", Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall) 1253 .Case({ReturnValueCondition( 1254 WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})})); 1255 1256 // read()-like functions that never return more than buffer size. 1257 addToFunctionSummaryMap("fread", Fread()); 1258 addToFunctionSummaryMap("fwrite", Fwrite()); 1259 1260 // We are not sure how ssize_t is defined on every platform, so we 1261 // provide three variants that should cover common cases. 1262 // FIXME these are actually defined by POSIX and not by the C standard, we 1263 // should handle them together with the rest of the POSIX functions. 1264 addToFunctionSummaryMap("read", {Read(IntTy, IntMax), Read(LongTy, LongMax), 1265 Read(LongLongTy, LongLongMax)}); 1266 addToFunctionSummaryMap("write", {Read(IntTy, IntMax), Read(LongTy, LongMax), 1267 Read(LongLongTy, LongLongMax)}); 1268 1269 // getline()-like functions either fail or read at least the delimiter. 1270 // FIXME these are actually defined by POSIX and not by the C standard, we 1271 // should handle them together with the rest of the POSIX functions. 1272 addToFunctionSummaryMap("getline", 1273 {Getline(IntTy, IntMax), Getline(LongTy, LongMax), 1274 Getline(LongLongTy, LongLongMax)}); 1275 addToFunctionSummaryMap("getdelim", 1276 {Getline(IntTy, IntMax), Getline(LongTy, LongMax), 1277 Getline(LongLongTy, LongLongMax)}); 1278 1279 if (ModelPOSIX) { 1280 1281 // long a64l(const char *str64); 1282 addToFunctionSummaryMap( 1283 "a64l", Summary(ArgTypes{ConstCharPtrTy}, RetType{LongTy}, NoEvalCall) 1284 .ArgConstraint(NotNull(ArgNo(0)))); 1285 1286 // char *l64a(long value); 1287 addToFunctionSummaryMap( 1288 "l64a", Summary(ArgTypes{LongTy}, RetType{CharPtrTy}, NoEvalCall) 1289 .ArgConstraint( 1290 ArgumentCondition(0, WithinRange, Range(0, LongMax)))); 1291 1292 // int access(const char *pathname, int amode); 1293 addToFunctionSummaryMap("access", Summary(ArgTypes{ConstCharPtrTy, IntTy}, 1294 RetType{IntTy}, NoEvalCall) 1295 .ArgConstraint(NotNull(ArgNo(0)))); 1296 1297 // int faccessat(int dirfd, const char *pathname, int mode, int flags); 1298 addToFunctionSummaryMap( 1299 "faccessat", Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy}, 1300 RetType{IntTy}, NoEvalCall) 1301 .ArgConstraint(NotNull(ArgNo(1)))); 1302 1303 // int dup(int fildes); 1304 addToFunctionSummaryMap( 1305 "dup", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1306 .ArgConstraint( 1307 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1308 1309 // int dup2(int fildes1, int filedes2); 1310 addToFunctionSummaryMap( 1311 "dup2", 1312 Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall) 1313 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1314 .ArgConstraint( 1315 ArgumentCondition(1, WithinRange, Range(0, IntMax)))); 1316 1317 // int fdatasync(int fildes); 1318 addToFunctionSummaryMap( 1319 "fdatasync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1320 .ArgConstraint(ArgumentCondition(0, WithinRange, 1321 Range(0, IntMax)))); 1322 1323 // int fnmatch(const char *pattern, const char *string, int flags); 1324 addToFunctionSummaryMap( 1325 "fnmatch", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy}, 1326 RetType{IntTy}, EvalCallAsPure) 1327 .ArgConstraint(NotNull(ArgNo(0))) 1328 .ArgConstraint(NotNull(ArgNo(1)))); 1329 1330 // int fsync(int fildes); 1331 addToFunctionSummaryMap( 1332 "fsync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1333 .ArgConstraint( 1334 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1335 1336 Optional<QualType> Off_tTy = lookupTy("off_t"); 1337 1338 // int truncate(const char *path, off_t length); 1339 addToFunctionSummaryMap( 1340 "truncate", 1341 Summary(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}, NoEvalCall) 1342 .ArgConstraint(NotNull(ArgNo(0)))); 1343 1344 // int symlink(const char *oldpath, const char *newpath); 1345 addToFunctionSummaryMap("symlink", 1346 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, 1347 RetType{IntTy}, NoEvalCall) 1348 .ArgConstraint(NotNull(ArgNo(0))) 1349 .ArgConstraint(NotNull(ArgNo(1)))); 1350 1351 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath); 1352 addToFunctionSummaryMap( 1353 "symlinkat", 1354 Summary(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, RetType{IntTy}, 1355 NoEvalCall) 1356 .ArgConstraint(NotNull(ArgNo(0))) 1357 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax))) 1358 .ArgConstraint(NotNull(ArgNo(2)))); 1359 1360 // int lockf(int fd, int cmd, off_t len); 1361 addToFunctionSummaryMap( 1362 "lockf", 1363 Summary(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}, NoEvalCall) 1364 .ArgConstraint( 1365 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1366 1367 Optional<QualType> Mode_tTy = lookupTy("mode_t"); 1368 1369 // int creat(const char *pathname, mode_t mode); 1370 addToFunctionSummaryMap("creat", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy}, 1371 RetType{IntTy}, NoEvalCall) 1372 .ArgConstraint(NotNull(ArgNo(0)))); 1373 1374 // unsigned int sleep(unsigned int seconds); 1375 addToFunctionSummaryMap( 1376 "sleep", 1377 Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall) 1378 .ArgConstraint( 1379 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1380 1381 Optional<QualType> DirTy = lookupTy("DIR"); 1382 Optional<QualType> DirPtrTy = getPointerTy(DirTy); 1383 1384 // int dirfd(DIR *dirp); 1385 addToFunctionSummaryMap( 1386 "dirfd", Summary(ArgTypes{DirPtrTy}, RetType{IntTy}, NoEvalCall) 1387 .ArgConstraint(NotNull(ArgNo(0)))); 1388 1389 // unsigned int alarm(unsigned int seconds); 1390 addToFunctionSummaryMap( 1391 "alarm", 1392 Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall) 1393 .ArgConstraint( 1394 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); 1395 1396 // int closedir(DIR *dir); 1397 addToFunctionSummaryMap( 1398 "closedir", Summary(ArgTypes{DirPtrTy}, RetType{IntTy}, NoEvalCall) 1399 .ArgConstraint(NotNull(ArgNo(0)))); 1400 1401 // char *strdup(const char *s); 1402 addToFunctionSummaryMap("strdup", Summary(ArgTypes{ConstCharPtrTy}, 1403 RetType{CharPtrTy}, NoEvalCall) 1404 .ArgConstraint(NotNull(ArgNo(0)))); 1405 1406 // char *strndup(const char *s, size_t n); 1407 addToFunctionSummaryMap( 1408 "strndup", Summary(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}, 1409 NoEvalCall) 1410 .ArgConstraint(NotNull(ArgNo(0))) 1411 .ArgConstraint(ArgumentCondition(1, WithinRange, 1412 Range(0, SizeMax)))); 1413 1414 // wchar_t *wcsdup(const wchar_t *s); 1415 addToFunctionSummaryMap("wcsdup", Summary(ArgTypes{ConstWchar_tPtrTy}, 1416 RetType{Wchar_tPtrTy}, NoEvalCall) 1417 .ArgConstraint(NotNull(ArgNo(0)))); 1418 1419 // int mkstemp(char *template); 1420 addToFunctionSummaryMap( 1421 "mkstemp", Summary(ArgTypes{CharPtrTy}, RetType{IntTy}, NoEvalCall) 1422 .ArgConstraint(NotNull(ArgNo(0)))); 1423 1424 // char *mkdtemp(char *template); 1425 addToFunctionSummaryMap( 1426 "mkdtemp", Summary(ArgTypes{CharPtrTy}, RetType{CharPtrTy}, NoEvalCall) 1427 .ArgConstraint(NotNull(ArgNo(0)))); 1428 1429 // char *getcwd(char *buf, size_t size); 1430 addToFunctionSummaryMap( 1431 "getcwd", 1432 Summary(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}, NoEvalCall) 1433 .ArgConstraint( 1434 ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); 1435 1436 // int mkdir(const char *pathname, mode_t mode); 1437 addToFunctionSummaryMap("mkdir", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy}, 1438 RetType{IntTy}, NoEvalCall) 1439 .ArgConstraint(NotNull(ArgNo(0)))); 1440 1441 // int mkdirat(int dirfd, const char *pathname, mode_t mode); 1442 addToFunctionSummaryMap("mkdirat", 1443 Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, 1444 RetType{IntTy}, NoEvalCall) 1445 .ArgConstraint(NotNull(ArgNo(1)))); 1446 1447 Optional<QualType> Dev_tTy = lookupTy("dev_t"); 1448 1449 // int mknod(const char *pathname, mode_t mode, dev_t dev); 1450 addToFunctionSummaryMap("mknod", 1451 Summary(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, 1452 RetType{IntTy}, NoEvalCall) 1453 .ArgConstraint(NotNull(ArgNo(0)))); 1454 1455 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); 1456 addToFunctionSummaryMap( 1457 "mknodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy}, 1458 RetType{IntTy}, NoEvalCall) 1459 .ArgConstraint(NotNull(ArgNo(1)))); 1460 1461 // int chmod(const char *path, mode_t mode); 1462 addToFunctionSummaryMap("chmod", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy}, 1463 RetType{IntTy}, NoEvalCall) 1464 .ArgConstraint(NotNull(ArgNo(0)))); 1465 1466 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); 1467 addToFunctionSummaryMap( 1468 "fchmodat", 1469 Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy}, 1470 RetType{IntTy}, NoEvalCall) 1471 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1472 .ArgConstraint(NotNull(ArgNo(1)))); 1473 1474 // int fchmod(int fildes, mode_t mode); 1475 addToFunctionSummaryMap( 1476 "fchmod", Summary(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}, NoEvalCall) 1477 .ArgConstraint( 1478 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1479 1480 Optional<QualType> Uid_tTy = lookupTy("uid_t"); 1481 Optional<QualType> Gid_tTy = lookupTy("gid_t"); 1482 1483 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, 1484 // int flags); 1485 addToFunctionSummaryMap( 1486 "fchownat", 1487 Summary(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy}, 1488 RetType{IntTy}, NoEvalCall) 1489 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1490 .ArgConstraint(NotNull(ArgNo(1)))); 1491 1492 // int chown(const char *path, uid_t owner, gid_t group); 1493 addToFunctionSummaryMap("chown", 1494 Summary(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, 1495 RetType{IntTy}, NoEvalCall) 1496 .ArgConstraint(NotNull(ArgNo(0)))); 1497 1498 // int lchown(const char *path, uid_t owner, gid_t group); 1499 addToFunctionSummaryMap("lchown", 1500 Summary(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, 1501 RetType{IntTy}, NoEvalCall) 1502 .ArgConstraint(NotNull(ArgNo(0)))); 1503 1504 // int fchown(int fildes, uid_t owner, gid_t group); 1505 addToFunctionSummaryMap( 1506 "fchown", 1507 Summary(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}, NoEvalCall) 1508 .ArgConstraint( 1509 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1510 1511 // int rmdir(const char *pathname); 1512 addToFunctionSummaryMap( 1513 "rmdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall) 1514 .ArgConstraint(NotNull(ArgNo(0)))); 1515 1516 // int chdir(const char *path); 1517 addToFunctionSummaryMap( 1518 "chdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall) 1519 .ArgConstraint(NotNull(ArgNo(0)))); 1520 1521 // int link(const char *oldpath, const char *newpath); 1522 addToFunctionSummaryMap("link", 1523 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, 1524 RetType{IntTy}, NoEvalCall) 1525 .ArgConstraint(NotNull(ArgNo(0))) 1526 .ArgConstraint(NotNull(ArgNo(1)))); 1527 1528 // int linkat(int fd1, const char *path1, int fd2, const char *path2, 1529 // int flag); 1530 addToFunctionSummaryMap( 1531 "linkat", 1532 Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy}, 1533 RetType{IntTy}, NoEvalCall) 1534 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1535 .ArgConstraint(NotNull(ArgNo(1))) 1536 .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax))) 1537 .ArgConstraint(NotNull(ArgNo(3)))); 1538 1539 // int unlink(const char *pathname); 1540 addToFunctionSummaryMap( 1541 "unlink", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall) 1542 .ArgConstraint(NotNull(ArgNo(0)))); 1543 1544 // int unlinkat(int fd, const char *path, int flag); 1545 addToFunctionSummaryMap( 1546 "unlinkat", 1547 Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}, 1548 NoEvalCall) 1549 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1550 .ArgConstraint(NotNull(ArgNo(1)))); 1551 1552 Optional<QualType> StructStatTy = lookupTy("stat"); 1553 Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy); 1554 Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy); 1555 1556 // int fstat(int fd, struct stat *statbuf); 1557 addToFunctionSummaryMap( 1558 "fstat", 1559 Summary(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}, NoEvalCall) 1560 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1561 .ArgConstraint(NotNull(ArgNo(1)))); 1562 1563 // int stat(const char *restrict path, struct stat *restrict buf); 1564 addToFunctionSummaryMap("stat", Summary(ArgTypes{ConstCharPtrRestrictTy, 1565 StructStatPtrRestrictTy}, 1566 RetType{IntTy}, NoEvalCall) 1567 .ArgConstraint(NotNull(ArgNo(0))) 1568 .ArgConstraint(NotNull(ArgNo(1)))); 1569 1570 // int lstat(const char *restrict path, struct stat *restrict buf); 1571 addToFunctionSummaryMap("lstat", Summary(ArgTypes{ConstCharPtrRestrictTy, 1572 StructStatPtrRestrictTy}, 1573 RetType{IntTy}, NoEvalCall) 1574 .ArgConstraint(NotNull(ArgNo(0))) 1575 .ArgConstraint(NotNull(ArgNo(1)))); 1576 1577 // int fstatat(int fd, const char *restrict path, 1578 // struct stat *restrict buf, int flag); 1579 addToFunctionSummaryMap( 1580 "fstatat", 1581 Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy, StructStatPtrRestrictTy, 1582 IntTy}, 1583 RetType{IntTy}, NoEvalCall) 1584 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1585 .ArgConstraint(NotNull(ArgNo(1))) 1586 .ArgConstraint(NotNull(ArgNo(2)))); 1587 1588 // DIR *opendir(const char *name); 1589 addToFunctionSummaryMap("opendir", Summary(ArgTypes{ConstCharPtrTy}, 1590 RetType{DirPtrTy}, NoEvalCall) 1591 .ArgConstraint(NotNull(ArgNo(0)))); 1592 1593 // DIR *fdopendir(int fd); 1594 addToFunctionSummaryMap( 1595 "fdopendir", Summary(ArgTypes{IntTy}, RetType{DirPtrTy}, NoEvalCall) 1596 .ArgConstraint(ArgumentCondition(0, WithinRange, 1597 Range(0, IntMax)))); 1598 1599 // int isatty(int fildes); 1600 addToFunctionSummaryMap( 1601 "isatty", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1602 .ArgConstraint( 1603 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1604 1605 // FILE *popen(const char *command, const char *type); 1606 addToFunctionSummaryMap("popen", 1607 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, 1608 RetType{FilePtrTy}, NoEvalCall) 1609 .ArgConstraint(NotNull(ArgNo(0))) 1610 .ArgConstraint(NotNull(ArgNo(1)))); 1611 1612 // int pclose(FILE *stream); 1613 addToFunctionSummaryMap( 1614 "pclose", Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall) 1615 .ArgConstraint(NotNull(ArgNo(0)))); 1616 1617 // int close(int fildes); 1618 addToFunctionSummaryMap( 1619 "close", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall) 1620 .ArgConstraint( 1621 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1622 1623 // long fpathconf(int fildes, int name); 1624 addToFunctionSummaryMap( 1625 "fpathconf", 1626 Summary(ArgTypes{IntTy, IntTy}, RetType{LongTy}, NoEvalCall) 1627 .ArgConstraint( 1628 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1629 1630 // long pathconf(const char *path, int name); 1631 addToFunctionSummaryMap("pathconf", Summary(ArgTypes{ConstCharPtrTy, IntTy}, 1632 RetType{LongTy}, NoEvalCall) 1633 .ArgConstraint(NotNull(ArgNo(0)))); 1634 1635 // FILE *fdopen(int fd, const char *mode); 1636 addToFunctionSummaryMap( 1637 "fdopen", 1638 Summary(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}, NoEvalCall) 1639 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1640 .ArgConstraint(NotNull(ArgNo(1)))); 1641 1642 // void rewinddir(DIR *dir); 1643 addToFunctionSummaryMap( 1644 "rewinddir", Summary(ArgTypes{DirPtrTy}, RetType{VoidTy}, NoEvalCall) 1645 .ArgConstraint(NotNull(ArgNo(0)))); 1646 1647 // void seekdir(DIR *dirp, long loc); 1648 addToFunctionSummaryMap("seekdir", Summary(ArgTypes{DirPtrTy, LongTy}, 1649 RetType{VoidTy}, NoEvalCall) 1650 .ArgConstraint(NotNull(ArgNo(0)))); 1651 1652 // int rand_r(unsigned int *seedp); 1653 addToFunctionSummaryMap("rand_r", Summary(ArgTypes{UnsignedIntPtrTy}, 1654 RetType{IntTy}, NoEvalCall) 1655 .ArgConstraint(NotNull(ArgNo(0)))); 1656 1657 // int strcasecmp(const char *s1, const char *s2); 1658 addToFunctionSummaryMap("strcasecmp", 1659 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, 1660 RetType{IntTy}, EvalCallAsPure) 1661 .ArgConstraint(NotNull(ArgNo(0))) 1662 .ArgConstraint(NotNull(ArgNo(1)))); 1663 1664 // int strncasecmp(const char *s1, const char *s2, size_t n); 1665 addToFunctionSummaryMap( 1666 "strncasecmp", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, SizeTy}, 1667 RetType{IntTy}, EvalCallAsPure) 1668 .ArgConstraint(NotNull(ArgNo(0))) 1669 .ArgConstraint(NotNull(ArgNo(1))) 1670 .ArgConstraint(ArgumentCondition( 1671 2, WithinRange, Range(0, SizeMax)))); 1672 1673 // int fileno(FILE *stream); 1674 addToFunctionSummaryMap( 1675 "fileno", Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall) 1676 .ArgConstraint(NotNull(ArgNo(0)))); 1677 1678 // int fseeko(FILE *stream, off_t offset, int whence); 1679 addToFunctionSummaryMap( 1680 "fseeko", 1681 Summary(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}, NoEvalCall) 1682 .ArgConstraint(NotNull(ArgNo(0)))); 1683 1684 // off_t ftello(FILE *stream); 1685 addToFunctionSummaryMap( 1686 "ftello", Summary(ArgTypes{FilePtrTy}, RetType{Off_tTy}, NoEvalCall) 1687 .ArgConstraint(NotNull(ArgNo(0)))); 1688 1689 Optional<RangeInt> Off_tMax = getMaxValue(Off_tTy); 1690 // void *mmap(void *addr, size_t length, int prot, int flags, int fd, 1691 // off_t offset); 1692 addToFunctionSummaryMap( 1693 "mmap", 1694 Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy}, 1695 RetType{VoidPtrTy}, NoEvalCall) 1696 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1697 .ArgConstraint( 1698 ArgumentCondition(4, WithinRange, Range(0, Off_tMax)))); 1699 1700 Optional<QualType> Off64_tTy = lookupTy("off64_t"); 1701 Optional<RangeInt> Off64_tMax = getMaxValue(Off_tTy); 1702 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, 1703 // off64_t offset); 1704 addToFunctionSummaryMap( 1705 "mmap64", 1706 Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy}, 1707 RetType{VoidPtrTy}, NoEvalCall) 1708 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) 1709 .ArgConstraint( 1710 ArgumentCondition(4, WithinRange, Range(0, Off64_tMax)))); 1711 1712 // int pipe(int fildes[2]); 1713 addToFunctionSummaryMap( 1714 "pipe", Summary(ArgTypes{IntPtrTy}, RetType{IntTy}, NoEvalCall) 1715 .ArgConstraint(NotNull(ArgNo(0)))); 1716 1717 // off_t lseek(int fildes, off_t offset, int whence); 1718 addToFunctionSummaryMap( 1719 "lseek", 1720 Summary(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}, NoEvalCall) 1721 .ArgConstraint( 1722 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1723 1724 Optional<QualType> Ssize_tTy = lookupTy("ssize_t"); 1725 1726 // ssize_t readlink(const char *restrict path, char *restrict buf, 1727 // size_t bufsize); 1728 addToFunctionSummaryMap( 1729 "readlink", 1730 Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1731 RetType{Ssize_tTy}, NoEvalCall) 1732 .ArgConstraint(NotNull(ArgNo(0))) 1733 .ArgConstraint(NotNull(ArgNo(1))) 1734 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1735 /*BufSize=*/ArgNo(2))) 1736 .ArgConstraint( 1737 ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); 1738 1739 // ssize_t readlinkat(int fd, const char *restrict path, 1740 // char *restrict buf, size_t bufsize); 1741 addToFunctionSummaryMap( 1742 "readlinkat", 1743 Summary( 1744 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, 1745 RetType{Ssize_tTy}, NoEvalCall) 1746 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1747 .ArgConstraint(NotNull(ArgNo(1))) 1748 .ArgConstraint(NotNull(ArgNo(2))) 1749 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), 1750 /*BufSize=*/ArgNo(3))) 1751 .ArgConstraint( 1752 ArgumentCondition(3, WithinRange, Range(0, SizeMax)))); 1753 1754 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char 1755 // *newpath); 1756 addToFunctionSummaryMap("renameat", Summary(ArgTypes{IntTy, ConstCharPtrTy, 1757 IntTy, ConstCharPtrTy}, 1758 RetType{IntTy}, NoEvalCall) 1759 .ArgConstraint(NotNull(ArgNo(1))) 1760 .ArgConstraint(NotNull(ArgNo(3)))); 1761 1762 // char *realpath(const char *restrict file_name, 1763 // char *restrict resolved_name); 1764 addToFunctionSummaryMap( 1765 "realpath", Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy}, 1766 RetType{CharPtrTy}, NoEvalCall) 1767 .ArgConstraint(NotNull(ArgNo(0)))); 1768 1769 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy)); 1770 1771 // int execv(const char *path, char *const argv[]); 1772 addToFunctionSummaryMap("execv", 1773 Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, 1774 RetType{IntTy}, NoEvalCall) 1775 .ArgConstraint(NotNull(ArgNo(0)))); 1776 1777 // int execvp(const char *file, char *const argv[]); 1778 addToFunctionSummaryMap("execvp", 1779 Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, 1780 RetType{IntTy}, NoEvalCall) 1781 .ArgConstraint(NotNull(ArgNo(0)))); 1782 1783 // int getopt(int argc, char * const argv[], const char *optstring); 1784 addToFunctionSummaryMap( 1785 "getopt", 1786 Summary(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy}, 1787 RetType{IntTy}, NoEvalCall) 1788 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1789 .ArgConstraint(NotNull(ArgNo(1))) 1790 .ArgConstraint(NotNull(ArgNo(2)))); 1791 1792 Optional<QualType> StructSockaddrTy = lookupTy("sockaddr"); 1793 Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy); 1794 Optional<QualType> ConstStructSockaddrPtrTy = 1795 getPointerTy(getConstTy(StructSockaddrTy)); 1796 Optional<QualType> StructSockaddrPtrRestrictTy = 1797 getRestrictTy(StructSockaddrPtrTy); 1798 Optional<QualType> ConstStructSockaddrPtrRestrictTy = 1799 getRestrictTy(ConstStructSockaddrPtrTy); 1800 Optional<QualType> Socklen_tTy = lookupTy("socklen_t"); 1801 Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy); 1802 Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy); 1803 Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy); 1804 1805 // In 'socket.h' of some libc implementations with C99, sockaddr parameter 1806 // is a transparent union of the underlying sockaddr_ family of pointers 1807 // instead of being a pointer to struct sockaddr. In these cases, the 1808 // standardized signature will not match, thus we try to match with another 1809 // signature that has the joker Irrelevant type. We also remove those 1810 // constraints which require pointer types for the sockaddr param. 1811 auto Accept = 1812 Summary(NoEvalCall) 1813 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))); 1814 if (!addToFunctionSummaryMap( 1815 "accept", 1816 // int accept(int socket, struct sockaddr *restrict address, 1817 // socklen_t *restrict address_len); 1818 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1819 Socklen_tPtrRestrictTy}, 1820 RetType{IntTy}), 1821 Accept)) 1822 addToFunctionSummaryMap( 1823 "accept", 1824 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1825 RetType{IntTy}), 1826 Accept); 1827 1828 // int bind(int socket, const struct sockaddr *address, socklen_t 1829 // address_len); 1830 if (!addToFunctionSummaryMap( 1831 "bind", 1832 Summary(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 1833 RetType{IntTy}, NoEvalCall) 1834 .ArgConstraint( 1835 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1836 .ArgConstraint(NotNull(ArgNo(1))) 1837 .ArgConstraint( 1838 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2))) 1839 .ArgConstraint( 1840 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))))) 1841 // Do not add constraints on sockaddr. 1842 addToFunctionSummaryMap( 1843 "bind", Summary(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, 1844 RetType{IntTy}, NoEvalCall) 1845 .ArgConstraint( 1846 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1847 .ArgConstraint(ArgumentCondition( 1848 2, WithinRange, Range(0, Socklen_tMax)))); 1849 1850 // int getpeername(int socket, struct sockaddr *restrict address, 1851 // socklen_t *restrict address_len); 1852 if (!addToFunctionSummaryMap( 1853 "getpeername", Summary(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1854 Socklen_tPtrRestrictTy}, 1855 RetType{IntTy}, NoEvalCall) 1856 .ArgConstraint(ArgumentCondition( 1857 0, WithinRange, Range(0, IntMax))) 1858 .ArgConstraint(NotNull(ArgNo(1))) 1859 .ArgConstraint(NotNull(ArgNo(2))))) 1860 addToFunctionSummaryMap( 1861 "getpeername", 1862 Summary(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1863 RetType{IntTy}, NoEvalCall) 1864 .ArgConstraint( 1865 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1866 1867 // int getsockname(int socket, struct sockaddr *restrict address, 1868 // socklen_t *restrict address_len); 1869 if (!addToFunctionSummaryMap( 1870 "getsockname", Summary(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, 1871 Socklen_tPtrRestrictTy}, 1872 RetType{IntTy}, NoEvalCall) 1873 .ArgConstraint(ArgumentCondition( 1874 0, WithinRange, Range(0, IntMax))) 1875 .ArgConstraint(NotNull(ArgNo(1))) 1876 .ArgConstraint(NotNull(ArgNo(2))))) 1877 addToFunctionSummaryMap( 1878 "getsockname", 1879 Summary(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy}, 1880 RetType{IntTy}, NoEvalCall) 1881 .ArgConstraint( 1882 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1883 1884 // int connect(int socket, const struct sockaddr *address, socklen_t 1885 // address_len); 1886 if (!addToFunctionSummaryMap( 1887 "connect", 1888 Summary(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy}, 1889 RetType{IntTy}, NoEvalCall) 1890 .ArgConstraint( 1891 ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1892 .ArgConstraint(NotNull(ArgNo(1))))) 1893 addToFunctionSummaryMap( 1894 "connect", Summary(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, 1895 RetType{IntTy}, NoEvalCall) 1896 .ArgConstraint(ArgumentCondition(0, WithinRange, 1897 Range(0, IntMax)))); 1898 1899 auto Recvfrom = 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 "recvfrom", 1906 // ssize_t recvfrom(int socket, void *restrict buffer, 1907 // size_t length, 1908 // int flags, struct sockaddr *restrict address, 1909 // socklen_t *restrict address_len); 1910 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 1911 StructSockaddrPtrRestrictTy, 1912 Socklen_tPtrRestrictTy}, 1913 RetType{Ssize_tTy}), 1914 Recvfrom)) 1915 addToFunctionSummaryMap( 1916 "recvfrom", 1917 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, 1918 Irrelevant, Socklen_tPtrRestrictTy}, 1919 RetType{Ssize_tTy}), 1920 Recvfrom); 1921 1922 auto Sendto = 1923 Summary(NoEvalCall) 1924 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1925 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1926 /*BufSize=*/ArgNo(2))); 1927 if (!addToFunctionSummaryMap( 1928 "sendto", 1929 // ssize_t sendto(int socket, const void *message, size_t length, 1930 // int flags, const struct sockaddr *dest_addr, 1931 // socklen_t dest_len); 1932 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, 1933 ConstStructSockaddrPtrTy, Socklen_tTy}, 1934 RetType{Ssize_tTy}), 1935 Sendto)) 1936 addToFunctionSummaryMap( 1937 "sendto", 1938 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant, 1939 Socklen_tTy}, 1940 RetType{Ssize_tTy}), 1941 Sendto); 1942 1943 // int listen(int sockfd, int backlog); 1944 addToFunctionSummaryMap( 1945 "listen", Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall) 1946 .ArgConstraint( 1947 ArgumentCondition(0, WithinRange, Range(0, IntMax)))); 1948 1949 // ssize_t recv(int sockfd, void *buf, size_t len, int flags); 1950 addToFunctionSummaryMap( 1951 "recv", 1952 Summary(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, RetType{Ssize_tTy}, 1953 NoEvalCall) 1954 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 1955 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 1956 /*BufSize=*/ArgNo(2)))); 1957 1958 Optional<QualType> StructMsghdrTy = lookupTy("msghdr"); 1959 Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy); 1960 Optional<QualType> ConstStructMsghdrPtrTy = 1961 getPointerTy(getConstTy(StructMsghdrTy)); 1962 1963 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 1964 addToFunctionSummaryMap( 1965 "recvmsg", Summary(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy}, 1966 RetType{Ssize_tTy}, NoEvalCall) 1967 .ArgConstraint(ArgumentCondition(0, WithinRange, 1968 Range(0, IntMax)))); 1969 1970 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 1971 addToFunctionSummaryMap( 1972 "sendmsg", Summary(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy}, 1973 RetType{Ssize_tTy}, NoEvalCall) 1974 .ArgConstraint(ArgumentCondition(0, WithinRange, 1975 Range(0, IntMax)))); 1976 1977 // int setsockopt(int socket, int level, int option_name, 1978 // const void *option_value, socklen_t option_len); 1979 addToFunctionSummaryMap( 1980 "setsockopt", 1981 Summary(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy}, 1982 RetType{IntTy}, NoEvalCall) 1983 .ArgConstraint(NotNull(ArgNo(3))) 1984 .ArgConstraint( 1985 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4))) 1986 .ArgConstraint( 1987 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax)))); 1988 1989 // int getsockopt(int socket, int level, int option_name, 1990 // void *restrict option_value, 1991 // socklen_t *restrict option_len); 1992 addToFunctionSummaryMap( 1993 "getsockopt", Summary(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy, 1994 Socklen_tPtrRestrictTy}, 1995 RetType{IntTy}, NoEvalCall) 1996 .ArgConstraint(NotNull(ArgNo(3))) 1997 .ArgConstraint(NotNull(ArgNo(4)))); 1998 1999 // ssize_t send(int sockfd, const void *buf, size_t len, int flags); 2000 addToFunctionSummaryMap( 2001 "send", 2002 Summary(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy}, 2003 RetType{Ssize_tTy}, NoEvalCall) 2004 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) 2005 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), 2006 /*BufSize=*/ArgNo(2)))); 2007 2008 // int socketpair(int domain, int type, int protocol, int sv[2]); 2009 addToFunctionSummaryMap("socketpair", 2010 Summary(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, 2011 RetType{IntTy}, NoEvalCall) 2012 .ArgConstraint(NotNull(ArgNo(3)))); 2013 2014 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, 2015 // char *restrict node, socklen_t nodelen, 2016 // char *restrict service, 2017 // socklen_t servicelen, int flags); 2018 // 2019 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr 2020 // parameter is never handled as a transparent union in netdb.h 2021 addToFunctionSummaryMap( 2022 "getnameinfo", 2023 Summary(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy, 2024 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy, 2025 Socklen_tTy, IntTy}, 2026 RetType{IntTy}, NoEvalCall) 2027 .ArgConstraint( 2028 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))) 2029 .ArgConstraint( 2030 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax))) 2031 .ArgConstraint( 2032 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3))) 2033 .ArgConstraint( 2034 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax))) 2035 .ArgConstraint( 2036 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5))) 2037 .ArgConstraint( 2038 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax)))); 2039 } 2040 2041 // Functions for testing. 2042 if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) { 2043 addToFunctionSummaryMap( 2044 "__two_constrained_args", 2045 Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure) 2046 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))) 2047 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1)))); 2048 addToFunctionSummaryMap( 2049 "__arg_constrained_twice", 2050 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 2051 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))) 2052 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2)))); 2053 addToFunctionSummaryMap( 2054 "__defaultparam", 2055 Summary(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}, EvalCallAsPure) 2056 .ArgConstraint(NotNull(ArgNo(0)))); 2057 addToFunctionSummaryMap("__variadic", 2058 Summary(ArgTypes{VoidPtrTy, ConstCharPtrTy}, 2059 RetType{IntTy}, EvalCallAsPure) 2060 .ArgConstraint(NotNull(ArgNo(0))) 2061 .ArgConstraint(NotNull(ArgNo(1)))); 2062 addToFunctionSummaryMap( 2063 "__buf_size_arg_constraint", 2064 Summary(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}, 2065 EvalCallAsPure) 2066 .ArgConstraint( 2067 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))); 2068 addToFunctionSummaryMap( 2069 "__buf_size_arg_constraint_mul", 2070 Summary(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}, 2071 EvalCallAsPure) 2072 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), 2073 /*BufSizeMultiplier=*/ArgNo(2)))); 2074 addToFunctionSummaryMap( 2075 {"__test_restrict_param_0", "__test_restrict_param_1", 2076 "__test_restrict_param_2"}, 2077 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}), 2078 Summary(EvalCallAsPure)); 2079 } 2080 } 2081 2082 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 2083 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>(); 2084 Checker->DisplayLoadedSummaries = 2085 mgr.getAnalyzerOptions().getCheckerBooleanOption( 2086 Checker, "DisplayLoadedSummaries"); 2087 Checker->ModelPOSIX = 2088 mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX"); 2089 } 2090 2091 bool ento::shouldRegisterStdCLibraryFunctionsChecker( 2092 const CheckerManager &mgr) { 2093 return true; 2094 } 2095 2096 #define REGISTER_CHECKER(name) \ 2097 void ento::register##name(CheckerManager &mgr) { \ 2098 StdLibraryFunctionsChecker *checker = \ 2099 mgr.getChecker<StdLibraryFunctionsChecker>(); \ 2100 checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \ 2101 checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \ 2102 mgr.getCurrentCheckerName(); \ 2103 } \ 2104 \ 2105 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 2106 2107 REGISTER_CHECKER(StdCLibraryFunctionArgsChecker) 2108 REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker) 2109