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 std::string Name = FD->getQualifiedNameAsString(); 444 if (Name.empty() || !C.isCLibraryFunction(FD, Name)) 445 return None; 446 447 auto FSMI = FunctionSummaryMap.find(Name); 448 if (FSMI == FunctionSummaryMap.end()) 449 return None; 450 451 // Verify that function signature matches the spec in advance. 452 // Otherwise we might be modeling the wrong function. 453 // Strict checking is important because we will be conducting 454 // very integral-type-sensitive operations on arguments and 455 // return values. 456 const FunctionVariantsTy &SpecVariants = FSMI->second; 457 for (const FunctionSummaryTy &Spec : SpecVariants) 458 if (Spec.matchesCall(CE)) 459 return Spec; 460 461 return None; 462 } 463 464 void StdLibraryFunctionsChecker::initFunctionSummaries( 465 BasicValueFactory &BVF) const { 466 if (!FunctionSummaryMap.empty()) 467 return; 468 469 ASTContext &ACtx = BVF.getContext(); 470 471 // These types are useful for writing specifications quickly, 472 // New specifications should probably introduce more types. 473 // Some types are hard to obtain from the AST, eg. "ssize_t". 474 // In such cases it should be possible to provide multiple variants 475 // of function summary for common cases (eg. ssize_t could be int or long 476 // or long long, so three summary variants would be enough). 477 // Of course, function variants are also useful for C++ overloads. 478 QualType Irrelevant; // A placeholder, whenever we do not care about the type. 479 QualType IntTy = ACtx.IntTy; 480 QualType LongTy = ACtx.LongTy; 481 QualType LongLongTy = ACtx.LongLongTy; 482 QualType SizeTy = ACtx.getSizeType(); 483 484 RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); 485 RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); 486 RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue(); 487 488 // We are finally ready to define specifications for all supported functions. 489 // 490 // The signature needs to have the correct number of arguments. 491 // However, we insert `Irrelevant' when the type is insignificant. 492 // 493 // Argument ranges should always cover all variants. If return value 494 // is completely unknown, omit it from the respective range set. 495 // 496 // All types in the spec need to be canonical. 497 // 498 // Every item in the list of range sets represents a particular 499 // execution path the analyzer would need to explore once 500 // the call is modeled - a new program state is constructed 501 // for every range set, and each range line in the range set 502 // corresponds to a specific constraint within this state. 503 // 504 // Upon comparing to another argument, the other argument is casted 505 // to the current argument's type. This avoids proper promotion but 506 // seems useful. For example, read() receives size_t argument, 507 // and its return value, which is of type ssize_t, cannot be greater 508 // than this argument. If we made a promotion, and the size argument 509 // is equal to, say, 10, then we'd impose a range of [0, 10] on the 510 // return value, however the correct range is [-1, 10]. 511 // 512 // Please update the list of functions in the header after editing! 513 // 514 // The format is as follows: 515 // 516 //{ "function name", 517 // { spec: 518 // { argument types list, ... }, 519 // return type, purity, { range set list: 520 // { range list: 521 // { argument index, within or out of, {{from, to}, ...} }, 522 // { argument index, compares to argument, {{how, which}} }, 523 // ... 524 // } 525 // } 526 // } 527 //} 528 529 #define SUMMARY_WITH_VARIANTS(identifier) {#identifier, { 530 #define END_SUMMARY_WITH_VARIANTS }}, 531 #define VARIANT(argument_types, return_type, invalidation_approach) \ 532 { argument_types, return_type, invalidation_approach, { 533 #define END_VARIANT } }, 534 #define SUMMARY(identifier, argument_types, return_type, \ 535 invalidation_approach) \ 536 { #identifier, { { argument_types, return_type, invalidation_approach, { 537 #define END_SUMMARY } } } }, 538 #define ARGUMENT_TYPES(...) { __VA_ARGS__ } 539 #define RETURN_TYPE(x) x 540 #define INVALIDATION_APPROACH(x) x 541 #define CASE { 542 #define END_CASE }, 543 #define ARGUMENT_CONDITION(argument_number, condition_kind) \ 544 { argument_number, condition_kind, { 545 #define END_ARGUMENT_CONDITION }}, 546 #define RETURN_VALUE_CONDITION(condition_kind) \ 547 { Ret, condition_kind, { 548 #define END_RETURN_VALUE_CONDITION }}, 549 #define ARG_NO(x) x##U 550 #define RANGE(x, y) { x, y }, 551 #define SINGLE_VALUE(x) RANGE(x, x) 552 #define IS_LESS_THAN(arg) { BO_LE, arg } 553 554 FunctionSummaryMap = { 555 // The isascii() family of functions. 556 SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 557 INVALIDATION_APPROACH(EvalCallAsPure)) 558 CASE // Boils down to isupper() or islower() or isdigit() 559 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 560 RANGE('0', '9') 561 RANGE('A', 'Z') 562 RANGE('a', 'z') 563 END_ARGUMENT_CONDITION 564 RETURN_VALUE_CONDITION(OutOfRange) 565 SINGLE_VALUE(0) 566 END_RETURN_VALUE_CONDITION 567 END_CASE 568 CASE // The locale-specific range. 569 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 570 RANGE(128, 255) 571 END_ARGUMENT_CONDITION 572 // No post-condition. We are completely unaware of 573 // locale-specific return values. 574 END_CASE 575 CASE 576 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 577 RANGE('0', '9') 578 RANGE('A', 'Z') 579 RANGE('a', 'z') 580 RANGE(128, 255) 581 END_ARGUMENT_CONDITION 582 RETURN_VALUE_CONDITION(WithinRange) 583 SINGLE_VALUE(0) 584 END_RETURN_VALUE_CONDITION 585 END_CASE 586 END_SUMMARY 587 SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 588 INVALIDATION_APPROACH(EvalCallAsPure)) 589 CASE // isupper() or islower(). Note that 'Z' is less than 'a'. 590 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 591 RANGE('A', 'Z') 592 RANGE('a', 'z') 593 END_ARGUMENT_CONDITION 594 RETURN_VALUE_CONDITION(OutOfRange) 595 SINGLE_VALUE(0) 596 END_RETURN_VALUE_CONDITION 597 END_CASE 598 CASE // The locale-specific range. 599 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 600 RANGE(128, 255) 601 END_ARGUMENT_CONDITION 602 END_CASE 603 CASE // Other. 604 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 605 RANGE('A', 'Z') 606 RANGE('a', 'z') 607 RANGE(128, 255) 608 END_ARGUMENT_CONDITION 609 RETURN_VALUE_CONDITION(WithinRange) 610 SINGLE_VALUE(0) 611 END_RETURN_VALUE_CONDITION 612 END_CASE 613 END_SUMMARY 614 SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 615 INVALIDATION_APPROACH(EvalCallAsPure)) 616 CASE // Is ASCII. 617 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 618 RANGE(0, 127) 619 END_ARGUMENT_CONDITION 620 RETURN_VALUE_CONDITION(OutOfRange) 621 SINGLE_VALUE(0) 622 END_RETURN_VALUE_CONDITION 623 END_CASE 624 CASE 625 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 626 RANGE(0, 127) 627 END_ARGUMENT_CONDITION 628 RETURN_VALUE_CONDITION(WithinRange) 629 SINGLE_VALUE(0) 630 END_RETURN_VALUE_CONDITION 631 END_CASE 632 END_SUMMARY 633 SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 634 INVALIDATION_APPROACH(EvalCallAsPure)) 635 CASE 636 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 637 SINGLE_VALUE('\t') 638 SINGLE_VALUE(' ') 639 END_ARGUMENT_CONDITION 640 RETURN_VALUE_CONDITION(OutOfRange) 641 SINGLE_VALUE(0) 642 END_RETURN_VALUE_CONDITION 643 END_CASE 644 CASE 645 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 646 SINGLE_VALUE('\t') 647 SINGLE_VALUE(' ') 648 END_ARGUMENT_CONDITION 649 RETURN_VALUE_CONDITION(WithinRange) 650 SINGLE_VALUE(0) 651 END_RETURN_VALUE_CONDITION 652 END_CASE 653 END_SUMMARY 654 SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 655 INVALIDATION_APPROACH(EvalCallAsPure)) 656 CASE // 0..31 or 127 657 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 658 RANGE(0, 32) 659 SINGLE_VALUE(127) 660 END_ARGUMENT_CONDITION 661 RETURN_VALUE_CONDITION(OutOfRange) 662 SINGLE_VALUE(0) 663 END_RETURN_VALUE_CONDITION 664 END_CASE 665 CASE 666 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 667 RANGE(0, 32) 668 SINGLE_VALUE(127) 669 END_ARGUMENT_CONDITION 670 RETURN_VALUE_CONDITION(WithinRange) 671 SINGLE_VALUE(0) 672 END_RETURN_VALUE_CONDITION 673 END_CASE 674 END_SUMMARY 675 SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 676 INVALIDATION_APPROACH(EvalCallAsPure)) 677 CASE // Is a digit. 678 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 679 RANGE('0', '9') 680 END_ARGUMENT_CONDITION 681 RETURN_VALUE_CONDITION(OutOfRange) 682 SINGLE_VALUE(0) 683 END_RETURN_VALUE_CONDITION 684 END_CASE 685 CASE 686 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 687 RANGE('0', '9') 688 END_ARGUMENT_CONDITION 689 RETURN_VALUE_CONDITION(WithinRange) 690 SINGLE_VALUE(0) 691 END_RETURN_VALUE_CONDITION 692 END_CASE 693 END_SUMMARY 694 SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 695 INVALIDATION_APPROACH(EvalCallAsPure)) 696 CASE 697 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 698 RANGE(33, 126) 699 END_ARGUMENT_CONDITION 700 RETURN_VALUE_CONDITION(OutOfRange) 701 SINGLE_VALUE(0) 702 END_RETURN_VALUE_CONDITION 703 END_CASE 704 CASE 705 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 706 RANGE(33, 126) 707 END_ARGUMENT_CONDITION 708 RETURN_VALUE_CONDITION(WithinRange) 709 SINGLE_VALUE(0) 710 END_RETURN_VALUE_CONDITION 711 END_CASE 712 END_SUMMARY 713 SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 714 INVALIDATION_APPROACH(EvalCallAsPure)) 715 CASE // Is certainly lowercase. 716 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 717 RANGE('a', 'z') 718 END_ARGUMENT_CONDITION 719 RETURN_VALUE_CONDITION(OutOfRange) 720 SINGLE_VALUE(0) 721 END_RETURN_VALUE_CONDITION 722 END_CASE 723 CASE // Is ascii but not lowercase. 724 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 725 RANGE(0, 127) 726 END_ARGUMENT_CONDITION 727 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 728 RANGE('a', 'z') 729 END_ARGUMENT_CONDITION 730 RETURN_VALUE_CONDITION(WithinRange) 731 SINGLE_VALUE(0) 732 END_RETURN_VALUE_CONDITION 733 END_CASE 734 CASE // The locale-specific range. 735 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 736 RANGE(128, 255) 737 END_ARGUMENT_CONDITION 738 END_CASE 739 CASE // Is not an unsigned char. 740 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 741 RANGE(0, 255) 742 END_ARGUMENT_CONDITION 743 RETURN_VALUE_CONDITION(WithinRange) 744 SINGLE_VALUE(0) 745 END_RETURN_VALUE_CONDITION 746 END_CASE 747 END_SUMMARY 748 SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 749 INVALIDATION_APPROACH(EvalCallAsPure)) 750 CASE 751 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 752 RANGE(32, 126) 753 END_ARGUMENT_CONDITION 754 RETURN_VALUE_CONDITION(OutOfRange) 755 SINGLE_VALUE(0) 756 END_RETURN_VALUE_CONDITION 757 END_CASE 758 CASE 759 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 760 RANGE(32, 126) 761 END_ARGUMENT_CONDITION 762 RETURN_VALUE_CONDITION(WithinRange) 763 SINGLE_VALUE(0) 764 END_RETURN_VALUE_CONDITION 765 END_CASE 766 END_SUMMARY 767 SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 768 INVALIDATION_APPROACH(EvalCallAsPure)) 769 CASE 770 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 771 RANGE('!', '/') 772 RANGE(':', '@') 773 RANGE('[', '`') 774 RANGE('{', '~') 775 END_ARGUMENT_CONDITION 776 RETURN_VALUE_CONDITION(OutOfRange) 777 SINGLE_VALUE(0) 778 END_RETURN_VALUE_CONDITION 779 END_CASE 780 CASE 781 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 782 RANGE('!', '/') 783 RANGE(':', '@') 784 RANGE('[', '`') 785 RANGE('{', '~') 786 END_ARGUMENT_CONDITION 787 RETURN_VALUE_CONDITION(WithinRange) 788 SINGLE_VALUE(0) 789 END_RETURN_VALUE_CONDITION 790 END_CASE 791 END_SUMMARY 792 SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 793 INVALIDATION_APPROACH(EvalCallAsPure)) 794 CASE // Space, '\f', '\n', '\r', '\t', '\v'. 795 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 796 RANGE(9, 13) 797 SINGLE_VALUE(' ') 798 END_ARGUMENT_CONDITION 799 RETURN_VALUE_CONDITION(OutOfRange) 800 SINGLE_VALUE(0) 801 END_RETURN_VALUE_CONDITION 802 END_CASE 803 CASE // The locale-specific range. 804 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 805 RANGE(128, 255) 806 END_ARGUMENT_CONDITION 807 END_CASE 808 CASE 809 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 810 RANGE(9, 13) 811 SINGLE_VALUE(' ') 812 RANGE(128, 255) 813 END_ARGUMENT_CONDITION 814 RETURN_VALUE_CONDITION(WithinRange) 815 SINGLE_VALUE(0) 816 END_RETURN_VALUE_CONDITION 817 END_CASE 818 END_SUMMARY 819 SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy), 820 INVALIDATION_APPROACH(EvalCallAsPure)) 821 CASE // Is certainly uppercase. 822 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 823 RANGE('A', 'Z') 824 END_ARGUMENT_CONDITION 825 RETURN_VALUE_CONDITION(OutOfRange) 826 SINGLE_VALUE(0) 827 END_RETURN_VALUE_CONDITION 828 END_CASE 829 CASE // The locale-specific range. 830 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 831 RANGE(128, 255) 832 END_ARGUMENT_CONDITION 833 END_CASE 834 CASE // Other. 835 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 836 RANGE('A', 'Z') RANGE(128, 255) 837 END_ARGUMENT_CONDITION 838 RETURN_VALUE_CONDITION(WithinRange) 839 SINGLE_VALUE(0) 840 END_RETURN_VALUE_CONDITION 841 END_CASE 842 END_SUMMARY 843 SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 844 INVALIDATION_APPROACH(EvalCallAsPure)) 845 CASE 846 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 847 RANGE('0', '9') 848 RANGE('A', 'F') 849 RANGE('a', 'f') 850 END_ARGUMENT_CONDITION 851 RETURN_VALUE_CONDITION(OutOfRange) 852 SINGLE_VALUE(0) 853 END_RETURN_VALUE_CONDITION 854 END_CASE 855 CASE 856 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 857 RANGE('0', '9') 858 RANGE('A', 'F') 859 RANGE('a', 'f') 860 END_ARGUMENT_CONDITION 861 RETURN_VALUE_CONDITION(WithinRange) 862 SINGLE_VALUE(0) 863 END_RETURN_VALUE_CONDITION 864 END_CASE 865 END_SUMMARY 866 867 // The getc() family of functions that returns either a char or an EOF. 868 SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 869 INVALIDATION_APPROACH(NoEvalCall)) 870 CASE // FIXME: EOF is assumed to be defined as -1. 871 RETURN_VALUE_CONDITION(WithinRange) 872 RANGE(-1, 255) 873 END_RETURN_VALUE_CONDITION 874 END_CASE 875 END_SUMMARY 876 SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 877 INVALIDATION_APPROACH(NoEvalCall)) 878 CASE // FIXME: EOF is assumed to be defined as -1. 879 RETURN_VALUE_CONDITION(WithinRange) 880 RANGE(-1, 255) 881 END_RETURN_VALUE_CONDITION 882 END_CASE 883 END_SUMMARY 884 SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy), 885 INVALIDATION_APPROACH(NoEvalCall)) 886 CASE // FIXME: EOF is assumed to be defined as -1. 887 RETURN_VALUE_CONDITION(WithinRange) 888 RANGE(-1, 255) 889 END_RETURN_VALUE_CONDITION 890 END_CASE 891 END_SUMMARY 892 893 // read()-like functions that never return more than buffer size. 894 // We are not sure how ssize_t is defined on every platform, so we provide 895 // three variants that should cover common cases. 896 SUMMARY_WITH_VARIANTS(read) 897 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 898 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 899 CASE 900 RETURN_VALUE_CONDITION(ComparesToArgument) 901 IS_LESS_THAN(ARG_NO(2)) 902 END_RETURN_VALUE_CONDITION 903 RETURN_VALUE_CONDITION(WithinRange) 904 RANGE(-1, IntMax) 905 END_RETURN_VALUE_CONDITION 906 END_CASE 907 END_VARIANT 908 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 909 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 910 CASE 911 RETURN_VALUE_CONDITION(ComparesToArgument) 912 IS_LESS_THAN(ARG_NO(2)) 913 END_RETURN_VALUE_CONDITION 914 RETURN_VALUE_CONDITION(WithinRange) 915 RANGE(-1, LongMax) 916 END_RETURN_VALUE_CONDITION 917 END_CASE 918 END_VARIANT 919 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 920 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 921 CASE 922 RETURN_VALUE_CONDITION(ComparesToArgument) 923 IS_LESS_THAN(ARG_NO(2)) 924 END_RETURN_VALUE_CONDITION 925 RETURN_VALUE_CONDITION(WithinRange) 926 RANGE(-1, LongLongMax) 927 END_RETURN_VALUE_CONDITION 928 END_CASE 929 END_VARIANT 930 END_SUMMARY_WITH_VARIANTS 931 SUMMARY_WITH_VARIANTS(write) 932 // Again, due to elusive nature of ssize_t, we have duplicate 933 // our summaries to cover different variants. 934 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 935 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 936 CASE 937 RETURN_VALUE_CONDITION(ComparesToArgument) 938 IS_LESS_THAN(ARG_NO(2)) 939 END_RETURN_VALUE_CONDITION 940 RETURN_VALUE_CONDITION(WithinRange) 941 RANGE(-1, IntMax) 942 END_RETURN_VALUE_CONDITION 943 END_CASE 944 END_VARIANT 945 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 946 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 947 CASE 948 RETURN_VALUE_CONDITION(ComparesToArgument) 949 IS_LESS_THAN(ARG_NO(2)) 950 END_RETURN_VALUE_CONDITION 951 RETURN_VALUE_CONDITION(WithinRange) 952 RANGE(-1, LongMax) 953 END_RETURN_VALUE_CONDITION 954 END_CASE 955 END_VARIANT 956 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 957 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 958 CASE 959 RETURN_VALUE_CONDITION(ComparesToArgument) 960 IS_LESS_THAN(ARG_NO(2)) 961 END_RETURN_VALUE_CONDITION 962 RETURN_VALUE_CONDITION(WithinRange) 963 RANGE(-1, LongLongMax) 964 END_RETURN_VALUE_CONDITION 965 END_CASE 966 END_VARIANT 967 END_SUMMARY_WITH_VARIANTS 968 SUMMARY(fread, 969 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 970 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 971 CASE 972 RETURN_VALUE_CONDITION(ComparesToArgument) 973 IS_LESS_THAN(ARG_NO(2)) 974 END_RETURN_VALUE_CONDITION 975 END_CASE 976 END_SUMMARY 977 SUMMARY(fwrite, 978 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 979 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 980 CASE 981 RETURN_VALUE_CONDITION(ComparesToArgument) 982 IS_LESS_THAN(ARG_NO(2)) 983 END_RETURN_VALUE_CONDITION 984 END_CASE 985 END_SUMMARY 986 987 // getline()-like functions either fail or read at least the delimiter. 988 SUMMARY_WITH_VARIANTS(getline) 989 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 990 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 991 CASE 992 RETURN_VALUE_CONDITION(WithinRange) 993 SINGLE_VALUE(-1) 994 RANGE(1, IntMax) 995 END_RETURN_VALUE_CONDITION 996 END_CASE 997 END_VARIANT 998 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 999 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 1000 CASE 1001 RETURN_VALUE_CONDITION(WithinRange) 1002 SINGLE_VALUE(-1) 1003 RANGE(1, LongMax) 1004 END_RETURN_VALUE_CONDITION 1005 END_CASE 1006 END_VARIANT 1007 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 1008 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 1009 CASE 1010 RETURN_VALUE_CONDITION(WithinRange) 1011 SINGLE_VALUE(-1) 1012 RANGE(1, LongLongMax) 1013 END_RETURN_VALUE_CONDITION 1014 END_CASE 1015 END_VARIANT 1016 END_SUMMARY_WITH_VARIANTS 1017 SUMMARY_WITH_VARIANTS(getdelim) 1018 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1019 RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) 1020 CASE 1021 RETURN_VALUE_CONDITION(WithinRange) 1022 SINGLE_VALUE(-1) 1023 RANGE(1, IntMax) 1024 END_RETURN_VALUE_CONDITION 1025 END_CASE 1026 END_VARIANT 1027 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1028 RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) 1029 CASE 1030 RETURN_VALUE_CONDITION(WithinRange) 1031 SINGLE_VALUE(-1) 1032 RANGE(1, LongMax) 1033 END_RETURN_VALUE_CONDITION 1034 END_CASE 1035 END_VARIANT 1036 VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 1037 RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) 1038 CASE 1039 RETURN_VALUE_CONDITION(WithinRange) 1040 SINGLE_VALUE(-1) 1041 RANGE(1, LongLongMax) 1042 END_RETURN_VALUE_CONDITION 1043 END_CASE 1044 END_VARIANT 1045 END_SUMMARY_WITH_VARIANTS 1046 }; 1047 } 1048 1049 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 1050 // If this checker grows large enough to support C++, Objective-C, or other 1051 // standard libraries, we could use multiple register...Checker() functions, 1052 // which would register various checkers with the help of the same Checker 1053 // class, turning on different function summaries. 1054 mgr.registerChecker<StdLibraryFunctionsChecker>(); 1055 } 1056