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