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