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 LLVM_ATTRIBUTE_UNUSED int64_t SizeMax = 468 BVF.getMaxValue(SizeTy).getLimitedValue(); 469 int64_t SSizeMax = 470 BVF.getMaxValue(SSizeTy).getLimitedValue(); 471 472 // We are finally ready to define specifications for all supported functions. 473 // 474 // The signature needs to have the correct number of arguments. 475 // However, we insert `Irrelevant' when the type is insignificant. 476 // 477 // Argument ranges should always cover all variants. If return value 478 // is completely unknown, omit it from the respective range set. 479 // 480 // All types in the spec need to be canonical. 481 // 482 // Every item in the list of range sets represents a particular 483 // execution path the analyzer would need to explore once 484 // the call is modeled - a new program state is constructed 485 // for every range set, and each range line in the range set 486 // corresponds to a specific constraint within this state. 487 // 488 // Upon comparing to another argument, the other argument is casted 489 // to the current argument's type. This avoids proper promotion but 490 // seems useful. For example, read() receives size_t argument, 491 // and its return value, which is of type ssize_t, cannot be greater 492 // than this argument. If we made a promotion, and the size argument 493 // is equal to, say, 10, then we'd impose a range of [0, 10] on the 494 // return value, however the correct range is [-1, 10]. 495 // 496 // Please update the list of functions in the header after editing! 497 // 498 // The format is as follows: 499 // 500 //{ "function name", 501 // { spec: 502 // { argument types list, ... }, 503 // return type, purity, { range set list: 504 // { range list: 505 // { argument index, within or out of, {{from, to}, ...} }, 506 // { argument index, compares to argument, {{how, which}} }, 507 // ... 508 // } 509 // } 510 // } 511 //} 512 513 #define SUMMARY(identifier, argument_types, return_type, \ 514 invalidation_approach) \ 515 {#identifier, {argument_types, return_type, invalidation_approach, { 516 #define END_SUMMARY }}}, 517 #define ARGUMENT_TYPES(...) { __VA_ARGS__ } 518 #define RETURN_TYPE(x) x 519 #define INVALIDATION_APPROACH(x) x 520 #define CASE { 521 #define END_CASE }, 522 #define ARGUMENT_CONDITION(argument_number, condition_kind) \ 523 {argument_number, condition_kind, { 524 #define END_ARGUMENT_CONDITION }}, 525 #define RETURN_VALUE_CONDITION(condition_kind) \ 526 { Ret, condition_kind, { 527 #define END_RETURN_VALUE_CONDITION }}, 528 #define ARG_NO(x) x##U 529 #define RANGE(x, y) { x, y }, 530 #define SINGLE_VALUE(x) RANGE(x, x) 531 #define IS_LESS_THAN(arg) { BO_LE, arg } 532 533 FunctionSummaryMap = { 534 // The isascii() family of functions. 535 SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 536 INVALIDATION_APPROACH(EvalCallAsPure)) 537 CASE // Boils down to isupper() or islower() or isdigit() 538 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 539 RANGE('0', '9') 540 RANGE('A', 'Z') 541 RANGE('a', 'z') 542 END_ARGUMENT_CONDITION 543 RETURN_VALUE_CONDITION(OutOfRange) 544 SINGLE_VALUE(0) 545 END_RETURN_VALUE_CONDITION 546 END_CASE 547 CASE // The locale-specific range. 548 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 549 RANGE(128, 255) 550 END_ARGUMENT_CONDITION 551 // No post-condition. We are completely unaware of 552 // locale-specific return values. 553 END_CASE 554 CASE 555 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 556 RANGE('0', '9') 557 RANGE('A', 'Z') 558 RANGE('a', 'z') 559 RANGE(128, 255) 560 END_ARGUMENT_CONDITION 561 RETURN_VALUE_CONDITION(WithinRange) 562 SINGLE_VALUE(0) 563 END_RETURN_VALUE_CONDITION 564 END_CASE 565 END_SUMMARY 566 SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 567 INVALIDATION_APPROACH(EvalCallAsPure)) 568 CASE // isupper() or islower(). Note that 'Z' is less than 'a'. 569 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 570 RANGE('A', 'Z') 571 RANGE('a', 'z') 572 END_ARGUMENT_CONDITION 573 RETURN_VALUE_CONDITION(OutOfRange) 574 SINGLE_VALUE(0) 575 END_RETURN_VALUE_CONDITION 576 END_CASE 577 CASE // The locale-specific range. 578 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 579 RANGE(128, 255) 580 END_ARGUMENT_CONDITION 581 END_CASE 582 CASE // Other. 583 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 584 RANGE('A', 'Z') 585 RANGE('a', 'z') 586 RANGE(128, 255) 587 END_ARGUMENT_CONDITION 588 RETURN_VALUE_CONDITION(WithinRange) 589 SINGLE_VALUE(0) 590 END_RETURN_VALUE_CONDITION 591 END_CASE 592 END_SUMMARY 593 SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 594 INVALIDATION_APPROACH(EvalCallAsPure)) 595 CASE // Is ASCII. 596 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 597 RANGE(0, 127) 598 END_ARGUMENT_CONDITION 599 RETURN_VALUE_CONDITION(OutOfRange) 600 SINGLE_VALUE(0) 601 END_RETURN_VALUE_CONDITION 602 END_CASE 603 CASE 604 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 605 RANGE(0, 127) 606 END_ARGUMENT_CONDITION 607 RETURN_VALUE_CONDITION(WithinRange) 608 SINGLE_VALUE(0) 609 END_RETURN_VALUE_CONDITION 610 END_CASE 611 END_SUMMARY 612 SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 613 INVALIDATION_APPROACH(EvalCallAsPure)) 614 CASE 615 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 616 SINGLE_VALUE('\t') 617 SINGLE_VALUE(' ') 618 END_ARGUMENT_CONDITION 619 RETURN_VALUE_CONDITION(OutOfRange) 620 SINGLE_VALUE(0) 621 END_RETURN_VALUE_CONDITION 622 END_CASE 623 CASE 624 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 625 SINGLE_VALUE('\t') 626 SINGLE_VALUE(' ') 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(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 634 INVALIDATION_APPROACH(EvalCallAsPure)) 635 CASE // 0..31 or 127 636 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 637 RANGE(0, 32) 638 SINGLE_VALUE(127) 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 RANGE(0, 32) 647 SINGLE_VALUE(127) 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(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 655 INVALIDATION_APPROACH(EvalCallAsPure)) 656 CASE // Is a digit. 657 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 658 RANGE('0', '9') 659 END_ARGUMENT_CONDITION 660 RETURN_VALUE_CONDITION(OutOfRange) 661 SINGLE_VALUE(0) 662 END_RETURN_VALUE_CONDITION 663 END_CASE 664 CASE 665 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 666 RANGE('0', '9') 667 END_ARGUMENT_CONDITION 668 RETURN_VALUE_CONDITION(WithinRange) 669 SINGLE_VALUE(0) 670 END_RETURN_VALUE_CONDITION 671 END_CASE 672 END_SUMMARY 673 SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 674 INVALIDATION_APPROACH(EvalCallAsPure)) 675 CASE 676 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 677 RANGE(33, 126) 678 END_ARGUMENT_CONDITION 679 RETURN_VALUE_CONDITION(OutOfRange) 680 SINGLE_VALUE(0) 681 END_RETURN_VALUE_CONDITION 682 END_CASE 683 CASE 684 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 685 RANGE(33, 126) 686 END_ARGUMENT_CONDITION 687 RETURN_VALUE_CONDITION(WithinRange) 688 SINGLE_VALUE(0) 689 END_RETURN_VALUE_CONDITION 690 END_CASE 691 END_SUMMARY 692 SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 693 INVALIDATION_APPROACH(EvalCallAsPure)) 694 CASE // Is certainly lowercase. 695 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 696 RANGE('a', 'z') 697 END_ARGUMENT_CONDITION 698 RETURN_VALUE_CONDITION(OutOfRange) 699 SINGLE_VALUE(0) 700 END_RETURN_VALUE_CONDITION 701 END_CASE 702 CASE // Is ascii but not lowercase. 703 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 704 RANGE(0, 127) 705 END_ARGUMENT_CONDITION 706 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 707 RANGE('a', 'z') 708 END_ARGUMENT_CONDITION 709 RETURN_VALUE_CONDITION(WithinRange) 710 SINGLE_VALUE(0) 711 END_RETURN_VALUE_CONDITION 712 END_CASE 713 CASE // The locale-specific range. 714 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 715 RANGE(128, 255) 716 END_ARGUMENT_CONDITION 717 END_CASE 718 CASE // Is not an unsigned char. 719 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 720 RANGE(0, 255) 721 END_ARGUMENT_CONDITION 722 RETURN_VALUE_CONDITION(WithinRange) 723 SINGLE_VALUE(0) 724 END_RETURN_VALUE_CONDITION 725 END_CASE 726 END_SUMMARY 727 SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 728 INVALIDATION_APPROACH(EvalCallAsPure)) 729 CASE 730 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 731 RANGE(32, 126) 732 END_ARGUMENT_CONDITION 733 RETURN_VALUE_CONDITION(OutOfRange) 734 SINGLE_VALUE(0) 735 END_RETURN_VALUE_CONDITION 736 END_CASE 737 CASE 738 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 739 RANGE(32, 126) 740 END_ARGUMENT_CONDITION 741 RETURN_VALUE_CONDITION(WithinRange) 742 SINGLE_VALUE(0) 743 END_RETURN_VALUE_CONDITION 744 END_CASE 745 END_SUMMARY 746 SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 747 INVALIDATION_APPROACH(EvalCallAsPure)) 748 CASE 749 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 750 RANGE('!', '/') 751 RANGE(':', '@') 752 RANGE('[', '`') 753 RANGE('{', '~') 754 END_ARGUMENT_CONDITION 755 RETURN_VALUE_CONDITION(OutOfRange) 756 SINGLE_VALUE(0) 757 END_RETURN_VALUE_CONDITION 758 END_CASE 759 CASE 760 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 761 RANGE('!', '/') 762 RANGE(':', '@') 763 RANGE('[', '`') 764 RANGE('{', '~') 765 END_ARGUMENT_CONDITION 766 RETURN_VALUE_CONDITION(WithinRange) 767 SINGLE_VALUE(0) 768 END_RETURN_VALUE_CONDITION 769 END_CASE 770 END_SUMMARY 771 SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 772 INVALIDATION_APPROACH(EvalCallAsPure)) 773 CASE // Space, '\f', '\n', '\r', '\t', '\v'. 774 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 775 RANGE(9, 13) 776 SINGLE_VALUE(' ') 777 END_ARGUMENT_CONDITION 778 RETURN_VALUE_CONDITION(OutOfRange) 779 SINGLE_VALUE(0) 780 END_RETURN_VALUE_CONDITION 781 END_CASE 782 CASE // The locale-specific range. 783 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 784 RANGE(128, 255) 785 END_ARGUMENT_CONDITION 786 END_CASE 787 CASE 788 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 789 RANGE(9, 13) 790 SINGLE_VALUE(' ') 791 RANGE(128, 255) 792 END_ARGUMENT_CONDITION 793 RETURN_VALUE_CONDITION(WithinRange) 794 SINGLE_VALUE(0) 795 END_RETURN_VALUE_CONDITION 796 END_CASE 797 END_SUMMARY 798 SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy), 799 INVALIDATION_APPROACH(EvalCallAsPure)) 800 CASE // Is certainly uppercase. 801 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 802 RANGE('A', 'Z') 803 END_ARGUMENT_CONDITION 804 RETURN_VALUE_CONDITION(OutOfRange) 805 SINGLE_VALUE(0) 806 END_RETURN_VALUE_CONDITION 807 END_CASE 808 CASE // The locale-specific range. 809 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 810 RANGE(128, 255) 811 END_ARGUMENT_CONDITION 812 END_CASE 813 CASE // Other. 814 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 815 RANGE('A', 'Z') 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(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), 823 INVALIDATION_APPROACH(EvalCallAsPure)) 824 CASE 825 ARGUMENT_CONDITION(ARG_NO(0), WithinRange) 826 RANGE('0', '9') 827 RANGE('A', 'F') 828 RANGE('a', 'f') 829 END_ARGUMENT_CONDITION 830 RETURN_VALUE_CONDITION(OutOfRange) 831 SINGLE_VALUE(0) 832 END_RETURN_VALUE_CONDITION 833 END_CASE 834 CASE 835 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) 836 RANGE('0', '9') 837 RANGE('A', 'F') 838 RANGE('a', 'f') 839 END_ARGUMENT_CONDITION 840 RETURN_VALUE_CONDITION(WithinRange) 841 SINGLE_VALUE(0) 842 END_RETURN_VALUE_CONDITION 843 END_CASE 844 END_SUMMARY 845 846 // The getc() family of functions that returns either a char or an EOF. 847 SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 848 INVALIDATION_APPROACH(NoEvalCall)) 849 CASE // FIXME: EOF is assumed to be defined as -1. 850 RETURN_VALUE_CONDITION(WithinRange) 851 RANGE(-1, 255) 852 END_RETURN_VALUE_CONDITION 853 END_CASE 854 END_SUMMARY 855 SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), 856 INVALIDATION_APPROACH(NoEvalCall)) 857 CASE // FIXME: EOF is assumed to be defined as -1. 858 RETURN_VALUE_CONDITION(WithinRange) 859 RANGE(-1, 255) 860 END_RETURN_VALUE_CONDITION 861 END_CASE 862 END_SUMMARY 863 SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy), 864 INVALIDATION_APPROACH(NoEvalCall)) 865 CASE // FIXME: EOF is assumed to be defined as -1. 866 RETURN_VALUE_CONDITION(WithinRange) 867 RANGE(-1, 255) 868 END_RETURN_VALUE_CONDITION 869 END_CASE 870 END_SUMMARY 871 872 // read()-like functions that never return more than buffer size. 873 SUMMARY(read, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 874 RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall)) 875 CASE 876 RETURN_VALUE_CONDITION(ComparesToArgument) 877 IS_LESS_THAN(ARG_NO(2)) 878 END_RETURN_VALUE_CONDITION 879 RETURN_VALUE_CONDITION(WithinRange) 880 RANGE(-1, SSizeMax) 881 END_RETURN_VALUE_CONDITION 882 END_CASE 883 END_SUMMARY 884 SUMMARY(write, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), 885 RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall)) 886 CASE 887 RETURN_VALUE_CONDITION(ComparesToArgument) 888 IS_LESS_THAN(ARG_NO(2)) 889 END_RETURN_VALUE_CONDITION 890 RETURN_VALUE_CONDITION(WithinRange) 891 RANGE(-1, SSizeMax) 892 END_RETURN_VALUE_CONDITION 893 END_CASE 894 END_SUMMARY 895 SUMMARY(fread, 896 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 897 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 898 CASE 899 RETURN_VALUE_CONDITION(ComparesToArgument) 900 IS_LESS_THAN(ARG_NO(2)) 901 END_RETURN_VALUE_CONDITION 902 END_CASE 903 END_SUMMARY 904 SUMMARY(fwrite, 905 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), 906 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) 907 CASE 908 RETURN_VALUE_CONDITION(ComparesToArgument) 909 IS_LESS_THAN(ARG_NO(2)) 910 END_RETURN_VALUE_CONDITION 911 END_CASE 912 END_SUMMARY 913 914 // getline()-like functions either fail or read at least the delimiter. 915 SUMMARY(getline, ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), 916 RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall)) 917 CASE 918 RETURN_VALUE_CONDITION(WithinRange) 919 SINGLE_VALUE(-1) 920 RANGE(1, SSizeMax) 921 END_RETURN_VALUE_CONDITION 922 END_CASE 923 END_SUMMARY 924 SUMMARY(getdelim, 925 ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), 926 RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall)) 927 CASE 928 RETURN_VALUE_CONDITION(WithinRange) 929 SINGLE_VALUE(-1) 930 RANGE(1, SSizeMax) 931 END_RETURN_VALUE_CONDITION 932 END_CASE 933 END_SUMMARY 934 }; 935 } 936 937 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { 938 // If this checker grows large enough to support C++, Objective-C, or other 939 // standard libraries, we could use multiple register...Checker() functions, 940 // which would register various checkers with the help of the same Checker 941 // class, turning on different function summaries. 942 mgr.registerChecker<StdLibraryFunctionsChecker>(); 943 } 944