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