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 - `FunctionSummaryTy' - 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 // `FunctionSummaryTy' 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, for which 34 // their `FunctionSummaryTy' is a precise model. This avoids unnecessary 35 // invalidation passes. Conflicts with other checkers are unlikely because 36 // if the function has no other effects, other checkers would probably never 37 // 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 FunctionSummaryTy; 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 InvalidationKindTy { NoEvalCall, EvalCallAsPure }; 72 73 /// A pair of ValueRangeKindTy and IntRangeVectorTy 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 ValueRangeKindTy { 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 RangeIntTy; 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<RangeIntTy, RangeIntTy>> IntRangeVectorTy; 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 ArgNoTy; 95 static const ArgNoTy Ret = std::numeric_limits<ArgNoTy>::max(); 96 97 /// Incapsulates a single range on a single symbol within a branch. 98 class ValueRange { 99 ArgNoTy ArgNo; // Argument to which we apply the range. 100 ValueRangeKindTy Kind; // Kind of range definition. 101 IntRangeVectorTy Args; // Polymorphic arguments. 102 103 public: 104 ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind, 105 const IntRangeVectorTy &Args) 106 : ArgNo(ArgNo), Kind(Kind), Args(Args) {} 107 108 ArgNoTy getArgNo() const { return ArgNo; } 109 ValueRangeKindTy getKind() const { return Kind; } 110 111 BinaryOperator::Opcode getOpcode() const { 112 assert(Kind == ComparesToArgument); 113 assert(Args.size() == 1); 114 BinaryOperator::Opcode Op = 115 static_cast<BinaryOperator::Opcode>(Args[0].first); 116 assert(BinaryOperator::isComparisonOp(Op) && 117 "Only comparison ops are supported for ComparesToArgument"); 118 return Op; 119 } 120 121 ArgNoTy getOtherArgNo() const { 122 assert(Kind == ComparesToArgument); 123 assert(Args.size() == 1); 124 return static_cast<ArgNoTy>(Args[0].second); 125 } 126 127 const IntRangeVectorTy &getRanges() const { 128 assert(Kind != ComparesToArgument); 129 return Args; 130 } 131 132 // We avoid creating a virtual apply() method because 133 // it makes initializer lists harder to write. 134 private: 135 ProgramStateRef 136 applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call, 137 const FunctionSummaryTy &Summary) const; 138 ProgramStateRef 139 applyAsWithinRange(ProgramStateRef State, const CallEvent &Call, 140 const FunctionSummaryTy &Summary) const; 141 ProgramStateRef 142 applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call, 143 const FunctionSummaryTy &Summary) const; 144 145 public: 146 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, 147 const FunctionSummaryTy &Summary) const { 148 switch (Kind) { 149 case OutOfRange: 150 return applyAsOutOfRange(State, Call, Summary); 151 case WithinRange: 152 return applyAsWithinRange(State, Call, Summary); 153 case ComparesToArgument: 154 return applyAsComparesToArgument(State, Call, Summary); 155 } 156 llvm_unreachable("Unknown ValueRange kind!"); 157 } 158 }; 159 160 /// The complete list of ranges that defines a single branch. 161 typedef std::vector<ValueRange> ValueRangeSet; 162 163 /// Includes information about function prototype (which is necessary to 164 /// ensure we're modeling the right function and casting values properly), 165 /// approach to invalidation, and a list of branches - essentially, a list 166 /// of list of ranges - essentially, a list of lists of lists of segments. 167 struct FunctionSummaryTy { 168 const std::vector<QualType> ArgTypes; 169 const QualType RetType; 170 const InvalidationKindTy InvalidationKind; 171 const std::vector<ValueRangeSet> Ranges; 172 173 private: 174 static void assertTypeSuitableForSummary(QualType T) { 175 assert(!T->isVoidType() && 176 "We should have had no significant void types in the spec"); 177 assert(T.isCanonical() && 178 "We should only have canonical types in the spec"); 179 // FIXME: lift this assert (but not the ones above!) 180 assert(T->isIntegralOrEnumerationType() && 181 "We only support integral ranges in the spec"); 182 } 183 184 public: 185 QualType getArgType(ArgNoTy ArgNo) const { 186 QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo]; 187 assertTypeSuitableForSummary(T); 188 return T; 189 } 190 191 /// Try our best to figure out if the call expression is the call of 192 /// *the* library function to which this specification applies. 193 bool matchesCall(const CallExpr *CE) const; 194 }; 195 196 // The same function (as in, function identifier) may have different 197 // summaries assigned to it, with different argument and return value types. 198 // We call these "variants" of the function. This can be useful for handling 199 // C++ function overloads, and also it can be used when the same function 200 // may have different definitions on different platforms. 201 typedef std::vector<FunctionSummaryTy> FunctionVariantsTy; 202 203 // The map of all functions supported by the checker. It is initialized 204 // lazily, and it doesn't change after initialization. 205 typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy; 206 mutable FunctionSummaryMapTy FunctionSummaryMap; 207 208 // Auxiliary functions to support ArgNoTy within all structures 209 // in a unified manner. 210 static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) { 211 return Summary.getArgType(ArgNo); 212 } 213 static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) { 214 return ArgNo == Ret ? Call.getResultType().getCanonicalType() 215 : Call.getArgExpr(ArgNo)->getType().getCanonicalType(); 216 } 217 static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) { 218 return ArgNo == Ret ? CE->getType().getCanonicalType() 219 : CE->getArg(ArgNo)->getType().getCanonicalType(); 220 } 221 static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) { 222 return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo); 223 } 224 225 public: 226 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 227 bool evalCall(const CallExpr *CE, CheckerContext &C) const; 228 229 private: 230 Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD, 231 const CallExpr *CE, 232 CheckerContext &C) const; 233 234 void initFunctionSummaries(BasicValueFactory &BVF) const; 235 }; 236 } // end of anonymous namespace 237 238 ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange( 239 ProgramStateRef State, const CallEvent &Call, 240 const FunctionSummaryTy &Summary) const { 241 242 ProgramStateManager &Mgr = State->getStateManager(); 243 SValBuilder &SVB = Mgr.getSValBuilder(); 244 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 245 ConstraintManager &CM = Mgr.getConstraintManager(); 246 QualType T = getArgType(Summary, getArgNo()); 247 SVal V = getArgSVal(Call, getArgNo()); 248 249 if (auto N = V.getAs<NonLoc>()) { 250 const IntRangeVectorTy &R = getRanges(); 251 size_t E = R.size(); 252 for (size_t I = 0; I != E; ++I) { 253 const llvm::APSInt &Min = BVF.getValue(R[I].first, T); 254 const llvm::APSInt &Max = BVF.getValue(R[I].second, T); 255 assert(Min <= Max); 256 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 257 if (!State) 258 break; 259 } 260 } 261 262 return State; 263 } 264 265 ProgramStateRef 266 StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange( 267 ProgramStateRef State, const CallEvent &Call, 268 const FunctionSummaryTy &Summary) const { 269 270 ProgramStateManager &Mgr = State->getStateManager(); 271 SValBuilder &SVB = Mgr.getSValBuilder(); 272 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 273 ConstraintManager &CM = Mgr.getConstraintManager(); 274 QualType T = getArgType(Summary, getArgNo()); 275 SVal V = getArgSVal(Call, getArgNo()); 276 277 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R". 278 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary, 279 // and then cut away all holes in R one by one. 280 if (auto N = V.getAs<NonLoc>()) { 281 const IntRangeVectorTy &R = getRanges(); 282 size_t E = R.size(); 283 284 const llvm::APSInt &MinusInf = BVF.getMinValue(T); 285 const llvm::APSInt &PlusInf = BVF.getMaxValue(T); 286 287 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T); 288 if (Left != PlusInf) { 289 assert(MinusInf <= Left); 290 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false); 291 if (!State) 292 return nullptr; 293 } 294 295 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T); 296 if (Right != MinusInf) { 297 assert(Right <= PlusInf); 298 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false); 299 if (!State) 300 return nullptr; 301 } 302 303 for (size_t I = 1; I != E; ++I) { 304 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T); 305 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T); 306 assert(Min <= Max); 307 State = CM.assumeInclusiveRange(State, *N, Min, Max, false); 308 if (!State) 309 return nullptr; 310 } 311 } 312 313 return State; 314 } 315 316 ProgramStateRef 317 StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument( 318 ProgramStateRef State, const CallEvent &Call, 319 const FunctionSummaryTy &Summary) const { 320 321 ProgramStateManager &Mgr = State->getStateManager(); 322 SValBuilder &SVB = Mgr.getSValBuilder(); 323 QualType CondT = SVB.getConditionType(); 324 QualType T = getArgType(Summary, getArgNo()); 325 SVal V = getArgSVal(Call, getArgNo()); 326 327 BinaryOperator::Opcode Op = getOpcode(); 328 ArgNoTy OtherArg = getOtherArgNo(); 329 SVal OtherV = getArgSVal(Call, OtherArg); 330 QualType OtherT = getArgType(Call, OtherArg); 331 // Note: we avoid integral promotion for comparison. 332 OtherV = SVB.evalCast(OtherV, T, OtherT); 333 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT) 334 .getAs<DefinedOrUnknownSVal>()) 335 State = State->assume(*CompV, true); 336 return State; 337 } 338 339 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, 340 CheckerContext &C) const { 341 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 342 if (!FD) 343 return; 344 345 const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 346 if (!CE) 347 return; 348 349 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C); 350 if (!FoundSummary) 351 return; 352 353 // Now apply ranges. 354 const FunctionSummaryTy &Summary = *FoundSummary; 355 ProgramStateRef State = C.getState(); 356 357 for (const auto &VRS: Summary.Ranges) { 358 ProgramStateRef NewState = State; 359 for (const auto &VR: VRS) { 360 NewState = VR.apply(NewState, Call, Summary); 361 if (!NewState) 362 break; 363 } 364 365 if (NewState && NewState != State) 366 C.addTransition(NewState); 367 } 368 } 369 370 bool StdLibraryFunctionsChecker::evalCall(const CallExpr *CE, 371 CheckerContext &C) const { 372 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl()); 373 if (!FD) 374 return false; 375 376 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C); 377 if (!FoundSummary) 378 return false; 379 380 const FunctionSummaryTy &Summary = *FoundSummary; 381 switch (Summary.InvalidationKind) { 382 case EvalCallAsPure: { 383 ProgramStateRef State = C.getState(); 384 const LocationContext *LC = C.getLocationContext(); 385 SVal V = C.getSValBuilder().conjureSymbolVal( 386 CE, LC, CE->getType().getCanonicalType(), C.blockCount()); 387 State = State->BindExpr(CE, LC, V); 388 C.addTransition(State); 389 return true; 390 } 391 case NoEvalCall: 392 // Summary tells us to avoid performing eval::Call. The function is possibly 393 // evaluated by another checker, or evaluated conservatively. 394 return false; 395 } 396 llvm_unreachable("Unknown invalidation kind!"); 397 } 398 399 bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall( 400 const CallExpr *CE) const { 401 // Check number of arguments: 402 if (CE->getNumArgs() != ArgTypes.size()) 403 return false; 404 405 // Check return type if relevant: 406 if (!RetType.isNull() && RetType != CE->getType().getCanonicalType()) 407 return false; 408 409 // Check argument types when relevant: 410 for (size_t I = 0, E = ArgTypes.size(); I != E; ++I) { 411 QualType FormalT = ArgTypes[I]; 412 // Null type marks irrelevant arguments. 413 if (FormalT.isNull()) 414 continue; 415 416 assertTypeSuitableForSummary(FormalT); 417 418 QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I); 419 assert(ActualT.isCanonical()); 420 if (ActualT != FormalT) 421 return false; 422 } 423 424 return true; 425 } 426 427 Optional<StdLibraryFunctionsChecker::FunctionSummaryTy> 428 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, 429 const CallExpr *CE, 430 CheckerContext &C) const { 431 // Note: we cannot always obtain FD from CE 432 // (eg. virtual call, or call by pointer). 433 assert(CE); 434 435 if (!FD) 436 return None; 437 438 SValBuilder &SVB = C.getSValBuilder(); 439 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 440 initFunctionSummaries(BVF); 441 442 IdentifierInfo *II = FD->getIdentifier(); 443 if (!II) 444 return None; 445 StringRef Name = II->getName(); 446 if (Name.empty() || !C.isCLibraryFunction(FD, Name)) 447 return None; 448 449 auto FSMI = FunctionSummaryMap.find(Name); 450 if (FSMI == FunctionSummaryMap.end()) 451 return None; 452 453 // Verify that function signature matches the spec in advance. 454 // Otherwise we might be modeling the wrong function. 455 // Strict checking is important because we will be conducting 456 // very integral-type-sensitive operations on arguments and 457 // return values. 458 const FunctionVariantsTy &SpecVariants = FSMI->second; 459 for (const FunctionSummaryTy &Spec : SpecVariants) 460 if (Spec.matchesCall(CE)) 461 return Spec; 462 463 return None; 464 } 465 466 void StdLibraryFunctionsChecker::initFunctionSummaries( 467 BasicValueFactory &BVF) const { 468 if (!FunctionSummaryMap.empty()) 469 return; 470 471 ASTContext &ACtx = BVF.getContext(); 472 473 // These types are useful for writing specifications quickly, 474 // New specifications should probably introduce more types. 475 // Some types are hard to obtain from the AST, eg. "ssize_t". 476 // In such cases it should be possible to provide multiple variants 477 // of function summary for common cases (eg. ssize_t could be int or long 478 // or long long, so three summary variants would be enough). 479 // Of course, function variants are also useful for C++ overloads. 480 QualType Irrelevant; // A placeholder, whenever we do not care about the type. 481 QualType IntTy = ACtx.IntTy; 482 QualType LongTy = ACtx.LongTy; 483 QualType LongLongTy = ACtx.LongLongTy; 484 QualType SizeTy = ACtx.getSizeType(); 485 486 RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 487 RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 488 RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue(); 489 490 // We are finally ready to define specifications for all supported functions. 491 // 492 // The signature needs to have the correct number of arguments. 493 // However, we insert `Irrelevant' when the type is insignificant. 494 // 495 // Argument ranges should always cover all variants. If return value 496 // is completely unknown, omit it from the respective range set. 497 // 498 // All types in the spec need to be canonical. 499 // 500 // Every item in the list of range sets represents a particular 501 // execution path the analyzer would need to explore once 502 // the call is modeled - a new program state is constructed 503 // for every range set, and each range line in the range set 504 // corresponds to a specific constraint within this state. 505 // 506 // Upon comparing to another argument, the other argument is casted 507 // to the current argument's type. This avoids proper promotion but 508 // seems useful. For example, read() receives size_t argument, 509 // and its return value, which is of type ssize_t, cannot be greater 510 // than this argument. If we made a promotion, and the size argument 511 // is equal to, say, 10, then we'd impose a range of [0, 10] on the 512 // return value, however the correct range is [-1, 10]. 513 // 514 // Please update the list of functions in the header after editing! 515 // 516 // The format is as follows: 517 // 518 //{ "function name", 519 // { spec: 520 // { argument types list, ... }, 521 // return type, purity, { range set list: 522 // { range list: 523 // { argument index, within or out of, {{from, to}, ...} }, 524 // { argument index, compares to argument, {{how, which}} }, 525 // ... 526 // } 527 // } 528 // } 529 //} 530 531 #define SUMMARY_WITH_VARIANTS(identifier) {#identifier, { 532 #define END_SUMMARY_WITH_VARIANTS }}, 533 #define VARIANT(argument_types, return_type, invalidation_approach) \ 534 { argument_types, return_type, invalidation_approach, { 535 #define END_VARIANT } }, 536 #define SUMMARY(identifier, argument_types, return_type, \ 537 invalidation_approach) \ 538 { #identifier, { { argument_types, return_type, invalidation_approach, { 539 #define END_SUMMARY } } } }, 540 #define ARGUMENT_TYPES(...) { __VA_ARGS__ } 541 #define RETURN_TYPE(x) x 542 #define INVALIDATION_APPROACH(x) x 543 #define CASE { 544 #define END_CASE }, 545 #define ARGUMENT_CONDITION(argument_number, condition_kind) \ 546 { argument_number, condition_kind, { 547 #define END_ARGUMENT_CONDITION }}, 548 #define RETURN_VALUE_CONDITION(condition_kind) \ 549 { Ret, condition_kind, { 550 #define END_RETURN_VALUE_CONDITION }}, 551 #define ARG_NO(x) x##U 552 #define RANGE(x, y) { x, y }, 553 #define SINGLE_VALUE(x) RANGE(x, x) 554 #define IS_LESS_THAN(arg) { BO_LE, arg } 555 556 FunctionSummaryMap = { 557 // The isascii() family of functions. 558 SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 559 INVALIDATION_APPROACH(EvalCallAsPure)) 560 CASE // Boils down to isupper() or islower() or isdigit() 561 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 562 RANGE('0', '9') 563 RANGE('A', 'Z') 564 RANGE('a', 'z') 565 END_ARGUMENT_CONDITION 566 RETURN_VALUE_CONDITION(OutOfRange) 567 SINGLE_VALUE(0) 568 END_RETURN_VALUE_CONDITION 569 END_CASE 570 CASE // The locale-specific range. 571 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 572 RANGE(128, 255) 573 END_ARGUMENT_CONDITION 574 // No post-condition. We are completely unaware of 575 // locale-specific return values. 576 END_CASE 577 CASE 578 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 579 RANGE('0', '9') 580 RANGE('A', 'Z') 581 RANGE('a', 'z') 582 RANGE(128, 255) 583 END_ARGUMENT_CONDITION 584 RETURN_VALUE_CONDITION(WithinRange) 585 SINGLE_VALUE(0) 586 END_RETURN_VALUE_CONDITION 587 END_CASE 588 END_SUMMARY 589 SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 590 INVALIDATION_APPROACH(EvalCallAsPure)) 591 CASE // isupper() or islower(). Note that 'Z' is less than 'a'. 592 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 593 RANGE('A', 'Z') 594 RANGE('a', 'z') 595 END_ARGUMENT_CONDITION 596 RETURN_VALUE_CONDITION(OutOfRange) 597 SINGLE_VALUE(0) 598 END_RETURN_VALUE_CONDITION 599 END_CASE 600 CASE // The locale-specific range. 601 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 602 RANGE(128, 255) 603 END_ARGUMENT_CONDITION 604 END_CASE 605 CASE // Other. 606 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 607 RANGE('A', 'Z') 608 RANGE('a', 'z') 609 RANGE(128, 255) 610 END_ARGUMENT_CONDITION 611 RETURN_VALUE_CONDITION(WithinRange) 612 SINGLE_VALUE(0) 613 END_RETURN_VALUE_CONDITION 614 END_CASE 615 END_SUMMARY 616 SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 617 INVALIDATION_APPROACH(EvalCallAsPure)) 618 CASE // Is ASCII. 619 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 620 RANGE(0, 127) 621 END_ARGUMENT_CONDITION 622 RETURN_VALUE_CONDITION(OutOfRange) 623 SINGLE_VALUE(0) 624 END_RETURN_VALUE_CONDITION 625 END_CASE 626 CASE 627 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 628 RANGE(0, 127) 629 END_ARGUMENT_CONDITION 630 RETURN_VALUE_CONDITION(WithinRange) 631 SINGLE_VALUE(0) 632 END_RETURN_VALUE_CONDITION 633 END_CASE 634 END_SUMMARY 635 SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 636 INVALIDATION_APPROACH(EvalCallAsPure)) 637 CASE 638 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 639 SINGLE_VALUE('\t') 640 SINGLE_VALUE(' ') 641 END_ARGUMENT_CONDITION 642 RETURN_VALUE_CONDITION(OutOfRange) 643 SINGLE_VALUE(0) 644 END_RETURN_VALUE_CONDITION 645 END_CASE 646 CASE 647 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 648 SINGLE_VALUE('\t') 649 SINGLE_VALUE(' ') 650 END_ARGUMENT_CONDITION 651 RETURN_VALUE_CONDITION(WithinRange) 652 SINGLE_VALUE(0) 653 END_RETURN_VALUE_CONDITION 654 END_CASE 655 END_SUMMARY 656 SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 657 INVALIDATION_APPROACH(EvalCallAsPure)) 658 CASE // 0..31 or 127 659 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 660 RANGE(0, 32) 661 SINGLE_VALUE(127) 662 END_ARGUMENT_CONDITION 663 RETURN_VALUE_CONDITION(OutOfRange) 664 SINGLE_VALUE(0) 665 END_RETURN_VALUE_CONDITION 666 END_CASE 667 CASE 668 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 669 RANGE(0, 32) 670 SINGLE_VALUE(127) 671 END_ARGUMENT_CONDITION 672 RETURN_VALUE_CONDITION(WithinRange) 673 SINGLE_VALUE(0) 674 END_RETURN_VALUE_CONDITION 675 END_CASE 676 END_SUMMARY 677 SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 678 INVALIDATION_APPROACH(EvalCallAsPure)) 679 CASE // Is a digit. 680 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 681 RANGE('0', '9') 682 END_ARGUMENT_CONDITION 683 RETURN_VALUE_CONDITION(OutOfRange) 684 SINGLE_VALUE(0) 685 END_RETURN_VALUE_CONDITION 686 END_CASE 687 CASE 688 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 689 RANGE('0', '9') 690 END_ARGUMENT_CONDITION 691 RETURN_VALUE_CONDITION(WithinRange) 692 SINGLE_VALUE(0) 693 END_RETURN_VALUE_CONDITION 694 END_CASE 695 END_SUMMARY 696 SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 697 INVALIDATION_APPROACH(EvalCallAsPure)) 698 CASE 699 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 700 RANGE(33, 126) 701 END_ARGUMENT_CONDITION 702 RETURN_VALUE_CONDITION(OutOfRange) 703 SINGLE_VALUE(0) 704 END_RETURN_VALUE_CONDITION 705 END_CASE 706 CASE 707 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 708 RANGE(33, 126) 709 END_ARGUMENT_CONDITION 710 RETURN_VALUE_CONDITION(WithinRange) 711 SINGLE_VALUE(0) 712 END_RETURN_VALUE_CONDITION 713 END_CASE 714 END_SUMMARY 715 SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 716 INVALIDATION_APPROACH(EvalCallAsPure)) 717 CASE // Is certainly lowercase. 718 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 719 RANGE('a', 'z') 720 END_ARGUMENT_CONDITION 721 RETURN_VALUE_CONDITION(OutOfRange) 722 SINGLE_VALUE(0) 723 END_RETURN_VALUE_CONDITION 724 END_CASE 725 CASE // Is ascii but not lowercase. 726 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 727 RANGE(0, 127) 728 END_ARGUMENT_CONDITION 729 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 730 RANGE('a', 'z') 731 END_ARGUMENT_CONDITION 732 RETURN_VALUE_CONDITION(WithinRange) 733 SINGLE_VALUE(0) 734 END_RETURN_VALUE_CONDITION 735 END_CASE 736 CASE // The locale-specific range. 737 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 738 RANGE(128, 255) 739 END_ARGUMENT_CONDITION 740 END_CASE 741 CASE // Is not an unsigned char. 742 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 743 RANGE(0, 255) 744 END_ARGUMENT_CONDITION 745 RETURN_VALUE_CONDITION(WithinRange) 746 SINGLE_VALUE(0) 747 END_RETURN_VALUE_CONDITION 748 END_CASE 749 END_SUMMARY 750 SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 751 INVALIDATION_APPROACH(EvalCallAsPure)) 752 CASE 753 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 754 RANGE(32, 126) 755 END_ARGUMENT_CONDITION 756 RETURN_VALUE_CONDITION(OutOfRange) 757 SINGLE_VALUE(0) 758 END_RETURN_VALUE_CONDITION 759 END_CASE 760 CASE 761 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 762 RANGE(32, 126) 763 END_ARGUMENT_CONDITION 764 RETURN_VALUE_CONDITION(WithinRange) 765 SINGLE_VALUE(0) 766 END_RETURN_VALUE_CONDITION 767 END_CASE 768 END_SUMMARY 769 SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 770 INVALIDATION_APPROACH(EvalCallAsPure)) 771 CASE 772 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 773 RANGE('!', '/') 774 RANGE(':', '@') 775 RANGE('[', '`') 776 RANGE('{', '~') 777 END_ARGUMENT_CONDITION 778 RETURN_VALUE_CONDITION(OutOfRange) 779 SINGLE_VALUE(0) 780 END_RETURN_VALUE_CONDITION 781 END_CASE 782 CASE 783 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 784 RANGE('!', '/') 785 RANGE(':', '@') 786 RANGE('[', '`') 787 RANGE('{', '~') 788 END_ARGUMENT_CONDITION 789 RETURN_VALUE_CONDITION(WithinRange) 790 SINGLE_VALUE(0) 791 END_RETURN_VALUE_CONDITION 792 END_CASE 793 END_SUMMARY 794 SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 795 INVALIDATION_APPROACH(EvalCallAsPure)) 796 CASE // Space, '\f', '\n', '\r', '\t', '\v'. 797 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 798 RANGE(9, 13) 799 SINGLE_VALUE(' ') 800 END_ARGUMENT_CONDITION 801 RETURN_VALUE_CONDITION(OutOfRange) 802 SINGLE_VALUE(0) 803 END_RETURN_VALUE_CONDITION 804 END_CASE 805 CASE // The locale-specific range. 806 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 807 RANGE(128, 255) 808 END_ARGUMENT_CONDITION 809 END_CASE 810 CASE 811 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 812 RANGE(9, 13) 813 SINGLE_VALUE(' ') 814 RANGE(128, 255) 815 END_ARGUMENT_CONDITION 816 RETURN_VALUE_CONDITION(WithinRange) 817 SINGLE_VALUE(0) 818 END_RETURN_VALUE_CONDITION 819 END_CASE 820 END_SUMMARY 821 SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy), 822 INVALIDATION_APPROACH(EvalCallAsPure)) 823 CASE // Is certainly uppercase. 824 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 825 RANGE('A', 'Z') 826 END_ARGUMENT_CONDITION 827 RETURN_VALUE_CONDITION(OutOfRange) 828 SINGLE_VALUE(0) 829 END_RETURN_VALUE_CONDITION 830 END_CASE 831 CASE // The locale-specific range. 832 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 833 RANGE(128, 255) 834 END_ARGUMENT_CONDITION 835 END_CASE 836 CASE // Other. 837 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 838 RANGE('A', 'Z') RANGE(128, 255) 839 END_ARGUMENT_CONDITION 840 RETURN_VALUE_CONDITION(WithinRange) 841 SINGLE_VALUE(0) 842 END_RETURN_VALUE_CONDITION 843 END_CASE 844 END_SUMMARY 845 SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 846 INVALIDATION_APPROACH(EvalCallAsPure)) 847 CASE 848 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 849 RANGE('0', '9') 850 RANGE('A', 'F') 851 RANGE('a', 'f') 852 END_ARGUMENT_CONDITION 853 RETURN_VALUE_CONDITION(OutOfRange) 854 SINGLE_VALUE(0) 855 END_RETURN_VALUE_CONDITION 856 END_CASE 857 CASE 858 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 859 RANGE('0', '9') 860 RANGE('A', 'F') 861 RANGE('a', 'f') 862 END_ARGUMENT_CONDITION 863 RETURN_VALUE_CONDITION(WithinRange) 864 SINGLE_VALUE(0) 865 END_RETURN_VALUE_CONDITION 866 END_CASE 867 END_SUMMARY 868 869 // The getc() family of functions that returns either a char or an EOF. 870 SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 871 INVALIDATION_APPROACH(NoEvalCall)) 872 CASE // FIXME: EOF is assumed to be defined as -1. 873 RETURN_VALUE_CONDITION(WithinRange) 874 RANGE(-1, 255) 875 END_RETURN_VALUE_CONDITION 876 END_CASE 877 END_SUMMARY 878 SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 879 INVALIDATION_APPROACH(NoEvalCall)) 880 CASE // FIXME: EOF is assumed to be defined as -1. 881 RETURN_VALUE_CONDITION(WithinRange) 882 RANGE(-1, 255) 883 END_RETURN_VALUE_CONDITION 884 END_CASE 885 END_SUMMARY 886 SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy), 887 INVALIDATION_APPROACH(NoEvalCall)) 888 CASE // FIXME: EOF is assumed to be defined as -1. 889 RETURN_VALUE_CONDITION(WithinRange) 890 RANGE(-1, 255) 891 END_RETURN_VALUE_CONDITION 892 END_CASE 893 END_SUMMARY 894 895 // read()-like functions that never return more than buffer size. 896 // We are not sure how ssize_t is defined on every platform, so we provide 897 // three variants that should cover common cases. 898 SUMMARY_WITH_VARIANTS(read) 899 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 900 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 901 CASE 902 RETURN_VALUE_CONDITION(ComparesToArgument) 903 IS_LESS_THAN(ARG_NO(2)) 904 END_RETURN_VALUE_CONDITION 905 RETURN_VALUE_CONDITION(WithinRange) 906 RANGE(-1, IntMax) 907 END_RETURN_VALUE_CONDITION 908 END_CASE 909 END_VARIANT 910 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 911 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 912 CASE 913 RETURN_VALUE_CONDITION(ComparesToArgument) 914 IS_LESS_THAN(ARG_NO(2)) 915 END_RETURN_VALUE_CONDITION 916 RETURN_VALUE_CONDITION(WithinRange) 917 RANGE(-1, LongMax) 918 END_RETURN_VALUE_CONDITION 919 END_CASE 920 END_VARIANT 921 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 922 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 923 CASE 924 RETURN_VALUE_CONDITION(ComparesToArgument) 925 IS_LESS_THAN(ARG_NO(2)) 926 END_RETURN_VALUE_CONDITION 927 RETURN_VALUE_CONDITION(WithinRange) 928 RANGE(-1, LongLongMax) 929 END_RETURN_VALUE_CONDITION 930 END_CASE 931 END_VARIANT 932 END_SUMMARY_WITH_VARIANTS 933 SUMMARY_WITH_VARIANTS(write) 934 // Again, due to elusive nature of ssize_t, we have duplicate 935 // our summaries to cover different variants. 936 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 937 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 938 CASE 939 RETURN_VALUE_CONDITION(ComparesToArgument) 940 IS_LESS_THAN(ARG_NO(2)) 941 END_RETURN_VALUE_CONDITION 942 RETURN_VALUE_CONDITION(WithinRange) 943 RANGE(-1, IntMax) 944 END_RETURN_VALUE_CONDITION 945 END_CASE 946 END_VARIANT 947 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 948 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 949 CASE 950 RETURN_VALUE_CONDITION(ComparesToArgument) 951 IS_LESS_THAN(ARG_NO(2)) 952 END_RETURN_VALUE_CONDITION 953 RETURN_VALUE_CONDITION(WithinRange) 954 RANGE(-1, LongMax) 955 END_RETURN_VALUE_CONDITION 956 END_CASE 957 END_VARIANT 958 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 959 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 960 CASE 961 RETURN_VALUE_CONDITION(ComparesToArgument) 962 IS_LESS_THAN(ARG_NO(2)) 963 END_RETURN_VALUE_CONDITION 964 RETURN_VALUE_CONDITION(WithinRange) 965 RANGE(-1, LongLongMax) 966 END_RETURN_VALUE_CONDITION 967 END_CASE 968 END_VARIANT 969 END_SUMMARY_WITH_VARIANTS 970 SUMMARY(fread, 971 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 972 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 973 CASE 974 RETURN_VALUE_CONDITION(ComparesToArgument) 975 IS_LESS_THAN(ARG_NO(2)) 976 END_RETURN_VALUE_CONDITION 977 END_CASE 978 END_SUMMARY 979 SUMMARY(fwrite, 980 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 981 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 982 CASE 983 RETURN_VALUE_CONDITION(ComparesToArgument) 984 IS_LESS_THAN(ARG_NO(2)) 985 END_RETURN_VALUE_CONDITION 986 END_CASE 987 END_SUMMARY 988 989 // getline()-like functions either fail or read at least the delimiter. 990 SUMMARY_WITH_VARIANTS(getline) 991 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 992 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 993 CASE 994 RETURN_VALUE_CONDITION(WithinRange) 995 SINGLE_VALUE(-1) 996 RANGE(1, IntMax) 997 END_RETURN_VALUE_CONDITION 998 END_CASE 999 END_VARIANT 1000 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 1001 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 1002 CASE 1003 RETURN_VALUE_CONDITION(WithinRange) 1004 SINGLE_VALUE(-1) 1005 RANGE(1, LongMax) 1006 END_RETURN_VALUE_CONDITION 1007 END_CASE 1008 END_VARIANT 1009 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 1010 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 1011 CASE 1012 RETURN_VALUE_CONDITION(WithinRange) 1013 SINGLE_VALUE(-1) 1014 RANGE(1, LongLongMax) 1015 END_RETURN_VALUE_CONDITION 1016 END_CASE 1017 END_VARIANT 1018 END_SUMMARY_WITH_VARIANTS 1019 SUMMARY_WITH_VARIANTS(getdelim) 1020 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1021 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 1022 CASE 1023 RETURN_VALUE_CONDITION(WithinRange) 1024 SINGLE_VALUE(-1) 1025 RANGE(1, IntMax) 1026 END_RETURN_VALUE_CONDITION 1027 END_CASE 1028 END_VARIANT 1029 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1030 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 1031 CASE 1032 RETURN_VALUE_CONDITION(WithinRange) 1033 SINGLE_VALUE(-1) 1034 RANGE(1, LongMax) 1035 END_RETURN_VALUE_CONDITION 1036 END_CASE 1037 END_VARIANT 1038 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1039 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 1040 CASE 1041 RETURN_VALUE_CONDITION(WithinRange) 1042 SINGLE_VALUE(-1) 1043 RANGE(1, LongLongMax) 1044 END_RETURN_VALUE_CONDITION 1045 END_CASE 1046 END_VARIANT 1047 END_SUMMARY_WITH_VARIANTS 1048 }; 1049 } 1050 1051 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 1052 // If this checker grows large enough to support C++, Objective-C, or other 1053 // standard libraries, we could use multiple register...Checker() functions, 1054 // which would register various checkers with the help of the same Checker 1055 // class, turning on different function summaries. 1056 mgr.registerChecker<StdLibraryFunctionsChecker>(); 1057 } 1058