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 // It does not generate warnings. 11 // 12 // This checker provides a specification format - `Summary' - and 13 // contains descriptions of some library functions in this format. Each 14 // specification contains a list of branches for splitting the program state 15 // upon call, and range constraints on argument and return-value symbols that 16 // are satisfied on each branch. This spec can be expanded to include more 17 // items, like external effects of the function. 18 // 19 // The main difference between this approach and the body farms technique is 20 // in more explicit control over how many branches are produced. For example, 21 // consider standard C function `ispunct(int x)', which returns a non-zero value 22 // iff `x' is a punctuation character, that is, when `x' is in range 23 // ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~']. 24 // `Summary' provides only two branches for this function. However, 25 // any attempt to describe this range with if-statements in the body farm 26 // would result in many more branches. Because each branch needs to be analyzed 27 // independently, this significantly reduces performance. Additionally, 28 // once we consider a branch on which `x' is in range, say, ['!', '/'], 29 // we assume that such branch is an important separate path through the program, 30 // which may lead to false positives because considering this particular path 31 // was not consciously intended, and therefore it might have been unreachable. 32 // 33 // This checker uses eval::Call for modeling pure functions (functions without 34 // side effets), for which their `Summary' is a precise model. This avoids 35 // unnecessary invalidation passes. Conflicts with other checkers are unlikely 36 // because if the function has no other effects, other checkers would probably 37 // never want to improve upon the modeling done by this checker. 38 // 39 // Non-pure functions, for which only partial improvement over the default 40 // behavior is expected, are modeled via check::PostCall, non-intrusively. 41 // 42 // The following standard C functions are currently supported: 43 // 44 // fgetc getline isdigit isupper 45 // fread isalnum isgraph isxdigit 46 // fwrite isalpha islower read 47 // getc isascii isprint write 48 // getchar isblank ispunct 49 // getdelim iscntrl isspace 50 // 51 //===----------------------------------------------------------------------===// 52 53 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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 59 using namespace clang; 60 using namespace clang::ento; 61 62 namespace { 63 class StdLibraryFunctionsChecker : public Checker<check::PostCall, eval::Call> { 64 /// Below is a series of typedefs necessary to define function specs. 65 /// We avoid nesting types here because each additional qualifier 66 /// would need to be repeated in every function spec. 67 struct Summary; 68 69 /// Specify how much the analyzer engine should entrust modeling this function 70 /// to us. If he doesn't, he performs additional invalidations. 71 enum InvalidationKind { NoEvalCall, EvalCallAsPure }; 72 73 /// A pair of ValueRangeKind and IntRangeVector would describe a range 74 /// imposed on a particular argument or return value symbol. 75 /// 76 /// Given a range, should the argument stay inside or outside this range? 77 /// The special `ComparesToArgument' value indicates that we should 78 /// impose a constraint that involves other argument or return value symbols. 79 enum ValueRangeKind { OutOfRange, WithinRange, ComparesToArgument }; 80 81 // The universal integral type to use in value range descriptions. 82 // Unsigned to make sure overflows are well-defined. 83 typedef uint64_t RangeInt; 84 85 /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is 86 /// a non-negative integer, which less than 5 and not equal to 2. For 87 /// `ComparesToArgument', holds information about how exactly to compare to 88 /// the argument. 89 typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector; 90 91 /// A reference to an argument or return value by its number. 92 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but 93 /// obviously uint32_t should be enough for all practical purposes. 94 typedef uint32_t ArgNo; 95 static const ArgNo Ret = std::numeric_limits<ArgNo>::max(); 96 97 /// Incapsulates a single range on a single symbol within a branch. 98 class ValueRange { 99 ArgNo ArgN; // Argument to which we apply the range. 100 ValueRangeKind Kind; // Kind of range definition. 101 IntRangeVector Args; // Polymorphic arguments. 102 103 public: 104 ValueRange(ArgNo ArgN, ValueRangeKind Kind, const IntRangeVector &Args) 105 : ArgN(ArgN), Kind(Kind), Args(Args) {} 106 107 ArgNo getArgNo() const { return ArgN; } 108 ValueRangeKind getKind() const { return Kind; } 109 110 BinaryOperator::Opcode getOpcode() const { 111 assert(Kind == ComparesToArgument); 112 assert(Args.size() == 1); 113 BinaryOperator::Opcode Op = 114 static_cast<BinaryOperator::Opcode>(Args[0].first); 115 assert(BinaryOperator::isComparisonOp(Op) && 116 "Only comparison ops are supported for ComparesToArgument"); 117 return Op; 118 } 119 120 ArgNo getOtherArgNo() const { 121 assert(Kind == ComparesToArgument); 122 assert(Args.size() == 1); 123 return static_cast<ArgNo>(Args[0].second); 124 } 125 126 const IntRangeVector &getRanges() const { 127 assert(Kind != ComparesToArgument); 128 return Args; 129 } 130 131 // We avoid creating a virtual apply() method because 132 // it makes initializer lists harder to write. 133 private: 134 ProgramStateRef applyAsOutOfRange(ProgramStateRef State, 135 const CallEvent &Call, 136 const Summary &Summary) const; 137 ProgramStateRef applyAsWithinRange(ProgramStateRef State, 138 const CallEvent &Call, 139 const Summary &Summary) const; 140 ProgramStateRef applyAsComparesToArgument(ProgramStateRef State, 141 const CallEvent &Call, 142 const Summary &Summary) const; 143 144 public: 145 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 146 const Summary &Summary) const { 147 switch (Kind) { 148 case OutOfRange: 149 return applyAsOutOfRange(State, Call, Summary); 150 case WithinRange: 151 return applyAsWithinRange(State, Call, Summary); 152 case ComparesToArgument: 153 return applyAsComparesToArgument(State, Call, Summary); 154 } 155 llvm_unreachable("Unknown ValueRange kind!"); 156 } 157 }; 158 159 /// The complete list of ranges that defines a single branch. 160 typedef std::vector<ValueRange> ValueRangeSet; 161 162 using ArgTypes = std::vector<QualType>; 163 using Ranges = std::vector<ValueRangeSet>; 164 165 /// Includes information about function prototype (which is necessary to 166 /// ensure we're modeling the right function and casting values properly), 167 /// approach to invalidation, and a list of branches - essentially, a list 168 /// of list of ranges - essentially, a list of lists of lists of segments. 169 struct Summary { 170 const ArgTypes ArgTys; 171 const QualType RetTy; 172 const InvalidationKind InvalidationKd; 173 Ranges Cases; 174 ValueRangeSet ArgConstraints; 175 176 Summary(ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd) 177 : ArgTys(ArgTys), RetTy(RetTy), InvalidationKd(InvalidationKd) {} 178 179 Summary &Case(ValueRangeSet VRS) { 180 Cases.push_back(VRS); 181 return *this; 182 } 183 184 private: 185 static void assertTypeSuitableForSummary(QualType T) { 186 assert(!T->isVoidType() && 187 "We should have had no significant void types in the spec"); 188 assert(T.isCanonical() && 189 "We should only have canonical types in the spec"); 190 // FIXME: lift this assert (but not the ones above!) 191 assert(T->isIntegralOrEnumerationType() && 192 "We only support integral ranges in the spec"); 193 } 194 195 public: 196 QualType getArgType(ArgNo ArgN) const { 197 QualType T = (ArgN == Ret) ? RetTy : ArgTys[ArgN]; 198 assertTypeSuitableForSummary(T); 199 return T; 200 } 201 202 /// Try our best to figure out if the call expression is the call of 203 /// *the* library function to which this specification applies. 204 bool matchesCall(const CallExpr *CE) const; 205 }; 206 207 // The same function (as in, function identifier) may have different 208 // summaries assigned to it, with different argument and return value types. 209 // We call these "variants" of the function. This can be useful for handling 210 // C++ function overloads, and also it can be used when the same function 211 // may have different definitions on different platforms. 212 typedef std::vector<Summary> Summaries; 213 214 // The map of all functions supported by the checker. It is initialized 215 // lazily, and it doesn't change after initialization. 216 mutable llvm::StringMap<Summaries> FunctionSummaryMap; 217 218 // Auxiliary functions to support ArgNo within all structures 219 // in a unified manner. 220 static QualType getArgType(const Summary &Summary, ArgNo ArgN) { 221 return Summary.getArgType(ArgN); 222 } 223 static QualType getArgType(const CallEvent &Call, ArgNo ArgN) { 224 return ArgN == Ret ? Call.getResultType().getCanonicalType() 225 : Call.getArgExpr(ArgN)->getType().getCanonicalType(); 226 } 227 static QualType getArgType(const CallExpr *CE, ArgNo ArgN) { 228 return ArgN == Ret ? CE->getType().getCanonicalType() 229 : CE->getArg(ArgN)->getType().getCanonicalType(); 230 } 231 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) { 232 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN); 233 } 234 235 public: 236 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 237 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 238 239 private: 240 Optional<Summary> findFunctionSummary(const FunctionDecl *FD, 241 const CallExpr *CE, 242 CheckerContext &C) const; 243 244 void initFunctionSummaries(BasicValueFactory &BVF) const; 245 }; 246 } // end of anonymous namespace 247 248 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange( 249 ProgramStateRef State, const CallEvent &Call, 250 const Summary &Summary) const { 251 252 ProgramStateManager &Mgr = State->getStateManager(); 253 SValBuilder &SVB = Mgr.getSValBuilder(); 254 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 255 ConstraintManager &CM = Mgr.getConstraintManager(); 256 QualType T = getArgType(Summary, getArgNo()); 257 SVal V = getArgSVal(Call, getArgNo()); 258 259 if (auto N = V.getAs<NonLoc>()) { 260 const IntRangeVector &R = getRanges(); 261 size_t E = R.size(); 262 for (size_t I = 0; I != E; ++I) { 263 const llvm::APSInt &Min = BVF.getValue(R[I].first, T); 264 const llvm::APSInt &Max = BVF.getValue(R[I].second, T); 265 assert(Min <= Max); 266 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 267 if (!State) 268 break; 269 } 270 } 271 272 return State; 273 } 274 275 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange( 276 ProgramStateRef State, const CallEvent &Call, 277 const Summary &Summary) const { 278 279 ProgramStateManager &Mgr = State->getStateManager(); 280 SValBuilder &SVB = Mgr.getSValBuilder(); 281 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 282 ConstraintManager &CM = Mgr.getConstraintManager(); 283 QualType T = getArgType(Summary, getArgNo()); 284 SVal V = getArgSVal(Call, getArgNo()); 285 286 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R". 287 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary, 288 // and then cut away all holes in R one by one. 289 if (auto N = V.getAs<NonLoc>()) { 290 const IntRangeVector &R = getRanges(); 291 size_t E = R.size(); 292 293 const llvm::APSInt &MinusInf = BVF.getMinValue(T); 294 const llvm::APSInt &PlusInf = BVF.getMaxValue(T); 295 296 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T); 297 if (Left != PlusInf) { 298 assert(MinusInf <= Left); 299 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false); 300 if (!State) 301 return nullptr; 302 } 303 304 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T); 305 if (Right != MinusInf) { 306 assert(Right <= PlusInf); 307 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false); 308 if (!State) 309 return nullptr; 310 } 311 312 for (size_t I = 1; I != E; ++I) { 313 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T); 314 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T); 315 assert(Min <= Max); 316 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 317 if (!State) 318 return nullptr; 319 } 320 } 321 322 return State; 323 } 324 325 ProgramStateRef 326 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument( 327 ProgramStateRef State, const CallEvent &Call, 328 const Summary &Summary) const { 329 330 ProgramStateManager &Mgr = State->getStateManager(); 331 SValBuilder &SVB = Mgr.getSValBuilder(); 332 QualType CondT = SVB.getConditionType(); 333 QualType T = getArgType(Summary, getArgNo()); 334 SVal V = getArgSVal(Call, getArgNo()); 335 336 BinaryOperator::Opcode Op = getOpcode(); 337 ArgNo OtherArg = getOtherArgNo(); 338 SVal OtherV = getArgSVal(Call, OtherArg); 339 QualType OtherT = getArgType(Call, OtherArg); 340 // Note: we avoid integral promotion for comparison. 341 OtherV = SVB.evalCast(OtherV, T, OtherT); 342 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT) 343 .getAs<DefinedOrUnknownSVal>()) 344 State = State->assume(*CompV, true); 345 return State; 346 } 347 348 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, 349 CheckerContext &C) const { 350 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 351 if (!FD) 352 return; 353 354 const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 355 if (!CE) 356 return; 357 358 Optional<Summary> FoundSummary = findFunctionSummary(FD, CE, C); 359 if (!FoundSummary) 360 return; 361 362 // Now apply ranges. 363 const Summary &Summary = *FoundSummary; 364 ProgramStateRef State = C.getState(); 365 366 // Apply case/branch specifications. 367 for (const auto &VRS : Summary.Cases) { 368 ProgramStateRef NewState = State; 369 for (const auto &VR: VRS) { 370 NewState = VR.apply(NewState, Call, Summary); 371 if (!NewState) 372 break; 373 } 374 375 if (NewState && NewState != State) 376 C.addTransition(NewState); 377 } 378 } 379 380 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, 381 CheckerContext &C) const { 382 const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 383 if (!FD) 384 return false; 385 386 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 387 if (!CE) 388 return false; 389 390 Optional<Summary> FoundSummary = findFunctionSummary(FD, CE, C); 391 if (!FoundSummary) 392 return false; 393 394 const Summary &Summary = *FoundSummary; 395 switch (Summary.InvalidationKd) { 396 case EvalCallAsPure: { 397 ProgramStateRef State = C.getState(); 398 const LocationContext *LC = C.getLocationContext(); 399 SVal V = C.getSValBuilder().conjureSymbolVal( 400 CE, LC, CE->getType().getCanonicalType(), C.blockCount()); 401 State = State->BindExpr(CE, LC, V); 402 C.addTransition(State); 403 return true; 404 } 405 case NoEvalCall: 406 // Summary tells us to avoid performing eval::Call. The function is possibly 407 // evaluated by another checker, or evaluated conservatively. 408 return false; 409 } 410 llvm_unreachable("Unknown invalidation kind!"); 411 } 412 413 bool StdLibraryFunctionsChecker::Summary::matchesCall( 414 const CallExpr *CE) const { 415 // Check number of arguments: 416 if (CE->getNumArgs() != ArgTys.size()) 417 return false; 418 419 // Check return type if relevant: 420 if (!RetTy.isNull() && RetTy != CE->getType().getCanonicalType()) 421 return false; 422 423 // Check argument types when relevant: 424 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) { 425 QualType FormalT = ArgTys[I]; 426 // Null type marks irrelevant arguments. 427 if (FormalT.isNull()) 428 continue; 429 430 assertTypeSuitableForSummary(FormalT); 431 432 QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I); 433 assert(ActualT.isCanonical()); 434 if (ActualT != FormalT) 435 return false; 436 } 437 438 return true; 439 } 440 441 Optional<StdLibraryFunctionsChecker::Summary> 442 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, 443 const CallExpr *CE, 444 CheckerContext &C) const { 445 // Note: we cannot always obtain FD from CE 446 // (eg. virtual call, or call by pointer). 447 assert(CE); 448 449 if (!FD) 450 return None; 451 452 SValBuilder &SVB = C.getSValBuilder(); 453 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 454 initFunctionSummaries(BVF); 455 456 IdentifierInfo *II = FD->getIdentifier(); 457 if (!II) 458 return None; 459 StringRef Name = II->getName(); 460 if (Name.empty() || !C.isCLibraryFunction(FD, Name)) 461 return None; 462 463 auto FSMI = FunctionSummaryMap.find(Name); 464 if (FSMI == FunctionSummaryMap.end()) 465 return None; 466 467 // Verify that function signature matches the spec in advance. 468 // Otherwise we might be modeling the wrong function. 469 // Strict checking is important because we will be conducting 470 // very integral-type-sensitive operations on arguments and 471 // return values. 472 const Summaries &SpecVariants = FSMI->second; 473 for (const Summary &Spec : SpecVariants) 474 if (Spec.matchesCall(CE)) 475 return Spec; 476 477 return None; 478 } 479 480 void StdLibraryFunctionsChecker::initFunctionSummaries( 481 BasicValueFactory &BVF) const { 482 if (!FunctionSummaryMap.empty()) 483 return; 484 485 ASTContext &ACtx = BVF.getContext(); 486 487 // These types are useful for writing specifications quickly, 488 // New specifications should probably introduce more types. 489 // Some types are hard to obtain from the AST, eg. "ssize_t". 490 // In such cases it should be possible to provide multiple variants 491 // of function summary for common cases (eg. ssize_t could be int or long 492 // or long long, so three summary variants would be enough). 493 // Of course, function variants are also useful for C++ overloads. 494 QualType Irrelevant; // A placeholder, whenever we do not care about the type. 495 QualType IntTy = ACtx.IntTy; 496 QualType LongTy = ACtx.LongTy; 497 QualType LongLongTy = ACtx.LongLongTy; 498 QualType SizeTy = ACtx.getSizeType(); 499 500 RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 501 RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 502 RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue(); 503 504 // We are finally ready to define specifications for all supported functions. 505 // 506 // The signature needs to have the correct number of arguments. 507 // However, we insert `Irrelevant' when the type is insignificant. 508 // 509 // Argument ranges should always cover all variants. If return value 510 // is completely unknown, omit it from the respective range set. 511 // 512 // All types in the spec need to be canonical. 513 // 514 // Every item in the list of range sets represents a particular 515 // execution path the analyzer would need to explore once 516 // the call is modeled - a new program state is constructed 517 // for every range set, and each range line in the range set 518 // corresponds to a specific constraint within this state. 519 // 520 // Upon comparing to another argument, the other argument is casted 521 // to the current argument's type. This avoids proper promotion but 522 // seems useful. For example, read() receives size_t argument, 523 // and its return value, which is of type ssize_t, cannot be greater 524 // than this argument. If we made a promotion, and the size argument 525 // is equal to, say, 10, then we'd impose a range of [0, 10] on the 526 // return value, however the correct range is [-1, 10]. 527 // 528 // Please update the list of functions in the header after editing! 529 // 530 531 // Below are helper functions to create the summaries. 532 auto ArgumentCondition = [](ArgNo ArgN, ValueRangeKind Kind, 533 IntRangeVector Ranges) -> ValueRange { 534 ValueRange VR{ArgN, Kind, Ranges}; 535 return VR; 536 }; 537 auto ReturnValueCondition = [](ValueRangeKind Kind, 538 IntRangeVector Ranges) -> ValueRange { 539 ValueRange VR{Ret, Kind, Ranges}; 540 return VR; 541 }; 542 auto Range = [](RangeInt b, RangeInt e) { 543 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}}; 544 }; 545 auto SingleValue = [](RangeInt v) { 546 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}}; 547 }; 548 auto IsLessThan = [](ArgNo ArgN) { return IntRangeVector{{BO_LE, ArgN}}; }; 549 550 using RetType = QualType; 551 552 // Templates for summaries that are reused by many functions. 553 auto Getc = [&]() { 554 return Summary(ArgTypes{Irrelevant}, RetType{IntTy}, NoEvalCall) 555 .Case({ReturnValueCondition(WithinRange, Range(-1, 255))}); 556 }; 557 auto Read = [&](RetType R, RangeInt Max) { 558 return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R}, 559 NoEvalCall) 560 .Case({ReturnValueCondition(ComparesToArgument, IsLessThan(2)), 561 ReturnValueCondition(WithinRange, Range(-1, Max))}); 562 }; 563 auto Fread = [&]() { 564 return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy, Irrelevant}, 565 RetType{SizeTy}, NoEvalCall) 566 .Case({ 567 ReturnValueCondition(ComparesToArgument, IsLessThan(2)), 568 }); 569 }; 570 auto Getline = [&](RetType R, RangeInt Max) { 571 return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R}, 572 NoEvalCall) 573 .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})}); 574 }; 575 576 FunctionSummaryMap = { 577 // The isascii() family of functions. 578 { 579 "isalnum", 580 Summaries{ 581 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 582 // Boils down to isupper() or islower() or isdigit(). 583 .Case( 584 {ArgumentCondition(0U, WithinRange, 585 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}), 586 ReturnValueCondition(OutOfRange, SingleValue(0))}) 587 // The locale-specific range. 588 // No post-condition. We are completely unaware of 589 // locale-specific return values. 590 .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) 591 .Case({ArgumentCondition( 592 0U, OutOfRange, 593 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, 255}}), 594 ReturnValueCondition(WithinRange, SingleValue(0))})}, 595 }, 596 { 597 "isalpha", 598 Summaries{ 599 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 600 .Case({ArgumentCondition(0U, WithinRange, 601 {{'A', 'Z'}, {'a', 'z'}}), 602 ReturnValueCondition(OutOfRange, SingleValue(0))}) 603 // The locale-specific range. 604 .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) 605 .Case( 606 {ArgumentCondition(0U, OutOfRange, 607 {{'A', 'Z'}, {'a', 'z'}, {128, 255}}), 608 ReturnValueCondition(WithinRange, SingleValue(0))})}, 609 }, 610 { 611 "isascii", 612 Summaries{ 613 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 614 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 615 ReturnValueCondition(OutOfRange, SingleValue(0))}) 616 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)), 617 ReturnValueCondition(WithinRange, SingleValue(0))})}, 618 }, 619 { 620 "isblank", 621 Summaries{ 622 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 623 .Case({ArgumentCondition(0U, WithinRange, 624 {{'\t', '\t'}, {' ', ' '}}), 625 ReturnValueCondition(OutOfRange, SingleValue(0))}) 626 .Case({ArgumentCondition(0U, OutOfRange, 627 {{'\t', '\t'}, {' ', ' '}}), 628 ReturnValueCondition(WithinRange, SingleValue(0))})}, 629 }, 630 { 631 "iscntrl", 632 Summaries{ 633 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 634 .Case({ArgumentCondition(0U, WithinRange, 635 {{0, 32}, {127, 127}}), 636 ReturnValueCondition(OutOfRange, SingleValue(0))}) 637 .Case( 638 {ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}), 639 ReturnValueCondition(WithinRange, SingleValue(0))})}, 640 }, 641 { 642 "isdigit", 643 Summaries{ 644 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 645 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')), 646 ReturnValueCondition(OutOfRange, SingleValue(0))}) 647 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')), 648 ReturnValueCondition(WithinRange, SingleValue(0))})}, 649 }, 650 { 651 "isgraph", 652 Summaries{ 653 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 654 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)), 655 ReturnValueCondition(OutOfRange, SingleValue(0))}) 656 .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)), 657 ReturnValueCondition(WithinRange, SingleValue(0))})}, 658 }, 659 { 660 "islower", 661 Summaries{ 662 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 663 // Is certainly lowercase. 664 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')), 665 ReturnValueCondition(OutOfRange, SingleValue(0))}) 666 // Is ascii but not lowercase. 667 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), 668 ArgumentCondition(0U, OutOfRange, Range('a', 'z')), 669 ReturnValueCondition(WithinRange, SingleValue(0))}) 670 // The locale-specific range. 671 .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) 672 // Is not an unsigned char. 673 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 255)), 674 ReturnValueCondition(WithinRange, SingleValue(0))})}, 675 }, 676 { 677 "isprint", 678 Summaries{ 679 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 680 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)), 681 ReturnValueCondition(OutOfRange, SingleValue(0))}) 682 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)), 683 ReturnValueCondition(WithinRange, SingleValue(0))})}, 684 }, 685 { 686 "ispunct", 687 Summaries{ 688 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 689 .Case({ArgumentCondition( 690 0U, WithinRange, 691 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 692 ReturnValueCondition(OutOfRange, SingleValue(0))}) 693 .Case({ArgumentCondition( 694 0U, OutOfRange, 695 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), 696 ReturnValueCondition(WithinRange, SingleValue(0))})}, 697 }, 698 { 699 "isspace", 700 Summaries{ 701 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 702 // Space, '\f', '\n', '\r', '\t', '\v'. 703 .Case({ArgumentCondition(0U, WithinRange, 704 {{9, 13}, {' ', ' '}}), 705 ReturnValueCondition(OutOfRange, SingleValue(0))}) 706 // The locale-specific range. 707 .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) 708 .Case({ArgumentCondition(0U, OutOfRange, 709 {{9, 13}, {' ', ' '}, {128, 255}}), 710 ReturnValueCondition(WithinRange, SingleValue(0))})}, 711 }, 712 { 713 "isupper", 714 Summaries{ 715 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 716 // Is certainly uppercase. 717 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')), 718 ReturnValueCondition(OutOfRange, SingleValue(0))}) 719 // The locale-specific range. 720 .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) 721 // Other. 722 .Case({ArgumentCondition(0U, OutOfRange, 723 {{'A', 'Z'}, {128, 255}}), 724 ReturnValueCondition(WithinRange, SingleValue(0))})}, 725 }, 726 { 727 "isxdigit", 728 Summaries{ 729 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) 730 .Case( 731 {ArgumentCondition(0U, WithinRange, 732 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 733 ReturnValueCondition(OutOfRange, SingleValue(0))}) 734 .Case( 735 {ArgumentCondition(0U, OutOfRange, 736 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), 737 ReturnValueCondition(WithinRange, SingleValue(0))})}, 738 }, 739 740 // The getc() family of functions that returns either a char or an EOF. 741 {"getc", Summaries{Getc()}}, 742 {"fgetc", Summaries{Getc()}}, 743 {"getchar", Summaries{Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall) 744 .Case({ReturnValueCondition(WithinRange, 745 Range(-1, 255))})}}, 746 747 // read()-like functions that never return more than buffer size. 748 // We are not sure how ssize_t is defined on every platform, so we 749 // provide three variants that should cover common cases. 750 {"read", Summaries{Read(IntTy, IntMax), Read(LongTy, LongMax), 751 Read(LongLongTy, LongLongMax)}}, 752 {"write", Summaries{Read(IntTy, IntMax), Read(LongTy, LongMax), 753 Read(LongLongTy, LongLongMax)}}, 754 {"fread", Summaries{Fread()}}, 755 {"fwrite", Summaries{Fread()}}, 756 // getline()-like functions either fail or read at least the delimiter. 757 {"getline", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax), 758 Getline(LongLongTy, LongLongMax)}}, 759 {"getdelim", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax), 760 Getline(LongLongTy, LongLongMax)}}, 761 }; 762 } 763 764 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 765 // If this checker grows large enough to support C++, Objective-C, or other 766 // standard libraries, we could use multiple register...Checker() functions, 767 // which would register various checkers with the help of the same Checker 768 // class, turning on different function summaries. 769 mgr.registerChecker<StdLibraryFunctionsChecker>(); 770 } 771 772 bool ento::shouldRegisterStdCLibraryFunctionsChecker(const LangOptions &LO) { 773 return true; 774 } 775