diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 2cdee8da375e7d..e8668775ab855f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -9,7 +9,7 @@ // This checker improves modeling of a few simple library functions. // It does not generate warnings. // -// This checker provides a specification format - `FunctionSummaryTy' - and +// This checker provides a specification format - `Summary' - and // contains descriptions of some library functions in this format. Each // specification contains a list of branches for splitting the program state // upon call, and range constraints on argument and return-value symbols that @@ -21,7 +21,7 @@ // consider standard C function `ispunct(int x)', which returns a non-zero value // iff `x' is a punctuation character, that is, when `x' is in range // ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~']. -// `FunctionSummaryTy' provides only two branches for this function. However, +// `Summary' provides only two branches for this function. However, // any attempt to describe this range with if-statements in the body farm // would result in many more branches. Because each branch needs to be analyzed // independently, this significantly reduces performance. Additionally, @@ -30,13 +30,13 @@ // which may lead to false positives because considering this particular path // was not consciously intended, and therefore it might have been unreachable. // -// This checker uses eval::Call for modeling "pure" functions, for which -// their `FunctionSummaryTy' is a precise model. This avoids unnecessary -// invalidation passes. Conflicts with other checkers are unlikely because -// if the function has no other effects, other checkers would probably never -// want to improve upon the modeling done by this checker. +// This checker uses eval::Call for modeling pure functions (functions without +// side effets), for which their `Summary' is a precise model. This avoids +// unnecessary invalidation passes. Conflicts with other checkers are unlikely +// because if the function has no other effects, other checkers would probably +// never want to improve upon the modeling done by this checker. // -// Non-"pure" functions, for which only partial improvement over the default +// Non-pure functions, for which only partial improvement over the default // behavior is expected, are modeled via check::PostCall, non-intrusively. // // The following standard C functions are currently supported: @@ -64,49 +64,48 @@ class StdLibraryFunctionsChecker : public Checker { /// Below is a series of typedefs necessary to define function specs. /// We avoid nesting types here because each additional qualifier /// would need to be repeated in every function spec. - struct FunctionSummaryTy; + struct Summary; /// Specify how much the analyzer engine should entrust modeling this function /// to us. If he doesn't, he performs additional invalidations. - enum InvalidationKindTy { NoEvalCall, EvalCallAsPure }; + enum InvalidationKind { NoEvalCall, EvalCallAsPure }; - /// A pair of ValueRangeKindTy and IntRangeVectorTy would describe a range + /// A pair of ValueRangeKind and IntRangeVector would describe a range /// imposed on a particular argument or return value symbol. /// /// Given a range, should the argument stay inside or outside this range? /// The special `ComparesToArgument' value indicates that we should /// impose a constraint that involves other argument or return value symbols. - enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument }; + enum ValueRangeKind { OutOfRange, WithinRange, ComparesToArgument }; // The universal integral type to use in value range descriptions. // Unsigned to make sure overflows are well-defined. - typedef uint64_t RangeIntTy; + typedef uint64_t RangeInt; /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is /// a non-negative integer, which less than 5 and not equal to 2. For /// `ComparesToArgument', holds information about how exactly to compare to /// the argument. - typedef std::vector> IntRangeVectorTy; + typedef std::vector> IntRangeVector; /// A reference to an argument or return value by its number. /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but /// obviously uint32_t should be enough for all practical purposes. - typedef uint32_t ArgNoTy; - static const ArgNoTy Ret = std::numeric_limits::max(); + typedef uint32_t ArgNo; + static const ArgNo Ret = std::numeric_limits::max(); /// Incapsulates a single range on a single symbol within a branch. class ValueRange { - ArgNoTy ArgNo; // Argument to which we apply the range. - ValueRangeKindTy Kind; // Kind of range definition. - IntRangeVectorTy Args; // Polymorphic arguments. + ArgNo ArgN; // Argument to which we apply the range. + ValueRangeKind Kind; // Kind of range definition. + IntRangeVector Args; // Polymorphic arguments. public: - ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind, - const IntRangeVectorTy &Args) - : ArgNo(ArgNo), Kind(Kind), Args(Args) {} + ValueRange(ArgNo ArgN, ValueRangeKind Kind, const IntRangeVector &Args) + : ArgN(ArgN), Kind(Kind), Args(Args) {} - ArgNoTy getArgNo() const { return ArgNo; } - ValueRangeKindTy getKind() const { return Kind; } + ArgNo getArgNo() const { return ArgN; } + ValueRangeKind getKind() const { return Kind; } BinaryOperator::Opcode getOpcode() const { assert(Kind == ComparesToArgument); @@ -118,13 +117,13 @@ class StdLibraryFunctionsChecker : public Checker { return Op; } - ArgNoTy getOtherArgNo() const { + ArgNo getOtherArgNo() const { assert(Kind == ComparesToArgument); assert(Args.size() == 1); - return static_cast(Args[0].second); + return static_cast(Args[0].second); } - const IntRangeVectorTy &getRanges() const { + const IntRangeVector &getRanges() const { assert(Kind != ComparesToArgument); return Args; } @@ -132,19 +131,19 @@ class StdLibraryFunctionsChecker : public Checker { // We avoid creating a virtual apply() method because // it makes initializer lists harder to write. private: - ProgramStateRef - applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const; - ProgramStateRef - applyAsWithinRange(ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const; - ProgramStateRef - applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const; + ProgramStateRef applyAsOutOfRange(ProgramStateRef State, + const CallEvent &Call, + const Summary &Summary) const; + ProgramStateRef applyAsWithinRange(ProgramStateRef State, + const CallEvent &Call, + const Summary &Summary) const; + ProgramStateRef applyAsComparesToArgument(ProgramStateRef State, + const CallEvent &Call, + const Summary &Summary) const; public: ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const { + const Summary &Summary) const { switch (Kind) { case OutOfRange: return applyAsOutOfRange(State, Call, Summary); @@ -160,15 +159,27 @@ class StdLibraryFunctionsChecker : public Checker { /// The complete list of ranges that defines a single branch. typedef std::vector ValueRangeSet; + using ArgTypes = std::vector; + using Ranges = std::vector; + /// Includes information about function prototype (which is necessary to /// ensure we're modeling the right function and casting values properly), /// approach to invalidation, and a list of branches - essentially, a list /// of list of ranges - essentially, a list of lists of lists of segments. - struct FunctionSummaryTy { - const std::vector ArgTypes; - const QualType RetType; - const InvalidationKindTy InvalidationKind; - const std::vector Ranges; + struct Summary { + const ArgTypes ArgTys; + const QualType RetTy; + const InvalidationKind InvalidationKd; + Ranges Cases; + ValueRangeSet ArgConstraints; + + Summary(ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd) + : ArgTys(ArgTys), RetTy(RetTy), InvalidationKd(InvalidationKd) {} + + Summary &Case(ValueRangeSet VRS) { + Cases.push_back(VRS); + return *this; + } private: static void assertTypeSuitableForSummary(QualType T) { @@ -182,8 +193,8 @@ class StdLibraryFunctionsChecker : public Checker { } public: - QualType getArgType(ArgNoTy ArgNo) const { - QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo]; + QualType getArgType(ArgNo ArgN) const { + QualType T = (ArgN == Ret) ? RetTy : ArgTys[ArgN]; assertTypeSuitableForSummary(T); return T; } @@ -198,28 +209,27 @@ class StdLibraryFunctionsChecker : public Checker { // We call these "variants" of the function. This can be useful for handling // C++ function overloads, and also it can be used when the same function // may have different definitions on different platforms. - typedef std::vector FunctionVariantsTy; + typedef std::vector Summaries; // The map of all functions supported by the checker. It is initialized // lazily, and it doesn't change after initialization. - typedef llvm::StringMap FunctionSummaryMapTy; - mutable FunctionSummaryMapTy FunctionSummaryMap; + mutable llvm::StringMap FunctionSummaryMap; - // Auxiliary functions to support ArgNoTy within all structures + // Auxiliary functions to support ArgNo within all structures // in a unified manner. - static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) { - return Summary.getArgType(ArgNo); + static QualType getArgType(const Summary &Summary, ArgNo ArgN) { + return Summary.getArgType(ArgN); } - static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) { - return ArgNo == Ret ? Call.getResultType().getCanonicalType() - : Call.getArgExpr(ArgNo)->getType().getCanonicalType(); + static QualType getArgType(const CallEvent &Call, ArgNo ArgN) { + return ArgN == Ret ? Call.getResultType().getCanonicalType() + : Call.getArgExpr(ArgN)->getType().getCanonicalType(); } - static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) { - return ArgNo == Ret ? CE->getType().getCanonicalType() - : CE->getArg(ArgNo)->getType().getCanonicalType(); + static QualType getArgType(const CallExpr *CE, ArgNo ArgN) { + return ArgN == Ret ? CE->getType().getCanonicalType() + : CE->getArg(ArgN)->getType().getCanonicalType(); } - static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) { - return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo); + static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) { + return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN); } public: @@ -227,9 +237,9 @@ class StdLibraryFunctionsChecker : public Checker { bool evalCall(const CallEvent &Call, CheckerContext &C) const; private: - Optional findFunctionSummary(const FunctionDecl *FD, - const CallExpr *CE, - CheckerContext &C) const; + Optional findFunctionSummary(const FunctionDecl *FD, + const CallExpr *CE, + CheckerContext &C) const; void initFunctionSummaries(BasicValueFactory &BVF) const; }; @@ -237,7 +247,7 @@ class StdLibraryFunctionsChecker : public Checker { ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange( ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const { + const Summary &Summary) const { ProgramStateManager &Mgr = State->getStateManager(); SValBuilder &SVB = Mgr.getSValBuilder(); @@ -247,7 +257,7 @@ ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange( SVal V = getArgSVal(Call, getArgNo()); if (auto N = V.getAs()) { - const IntRangeVectorTy &R = getRanges(); + const IntRangeVector &R = getRanges(); size_t E = R.size(); for (size_t I = 0; I != E; ++I) { const llvm::APSInt &Min = BVF.getValue(R[I].first, T); @@ -262,10 +272,9 @@ ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange( return State; } -ProgramStateRef -StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange( +ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange( ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const { + const Summary &Summary) const { ProgramStateManager &Mgr = State->getStateManager(); SValBuilder &SVB = Mgr.getSValBuilder(); @@ -278,7 +287,7 @@ StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange( // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary, // and then cut away all holes in R one by one. if (auto N = V.getAs()) { - const IntRangeVectorTy &R = getRanges(); + const IntRangeVector &R = getRanges(); size_t E = R.size(); const llvm::APSInt &MinusInf = BVF.getMinValue(T); @@ -316,7 +325,7 @@ StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange( ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument( ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const { + const Summary &Summary) const { ProgramStateManager &Mgr = State->getStateManager(); SValBuilder &SVB = Mgr.getSValBuilder(); @@ -325,7 +334,7 @@ StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument( SVal V = getArgSVal(Call, getArgNo()); BinaryOperator::Opcode Op = getOpcode(); - ArgNoTy OtherArg = getOtherArgNo(); + ArgNo OtherArg = getOtherArgNo(); SVal OtherV = getArgSVal(Call, OtherArg); QualType OtherT = getArgType(Call, OtherArg); // Note: we avoid integral promotion for comparison. @@ -346,15 +355,16 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, if (!CE) return; - Optional FoundSummary = findFunctionSummary(FD, CE, C); + Optional FoundSummary = findFunctionSummary(FD, CE, C); if (!FoundSummary) return; // Now apply ranges. - const FunctionSummaryTy &Summary = *FoundSummary; + const Summary &Summary = *FoundSummary; ProgramStateRef State = C.getState(); - for (const auto &VRS: Summary.Ranges) { + // Apply case/branch specifications. + for (const auto &VRS : Summary.Cases) { ProgramStateRef NewState = State; for (const auto &VR: VRS) { NewState = VR.apply(NewState, Call, Summary); @@ -377,12 +387,12 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, if (!CE) return false; - Optional FoundSummary = findFunctionSummary(FD, CE, C); + Optional FoundSummary = findFunctionSummary(FD, CE, C); if (!FoundSummary) return false; - const FunctionSummaryTy &Summary = *FoundSummary; - switch (Summary.InvalidationKind) { + const Summary &Summary = *FoundSummary; + switch (Summary.InvalidationKd) { case EvalCallAsPure: { ProgramStateRef State = C.getState(); const LocationContext *LC = C.getLocationContext(); @@ -400,19 +410,19 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, llvm_unreachable("Unknown invalidation kind!"); } -bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall( +bool StdLibraryFunctionsChecker::Summary::matchesCall( const CallExpr *CE) const { // Check number of arguments: - if (CE->getNumArgs() != ArgTypes.size()) + if (CE->getNumArgs() != ArgTys.size()) return false; // Check return type if relevant: - if (!RetType.isNull() && RetType != CE->getType().getCanonicalType()) + if (!RetTy.isNull() && RetTy != CE->getType().getCanonicalType()) return false; // Check argument types when relevant: - for (size_t I = 0, E = ArgTypes.size(); I != E; ++I) { - QualType FormalT = ArgTypes[I]; + for (size_t I = 0, E = ArgTys.size(); I != E; ++I) { + QualType FormalT = ArgTys[I]; // Null type marks irrelevant arguments. if (FormalT.isNull()) continue; @@ -428,7 +438,7 @@ bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall( return true; } -Optional +Optional StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, const CallExpr *CE, CheckerContext &C) const { @@ -459,8 +469,8 @@ StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, // Strict checking is important because we will be conducting // very integral-type-sensitive operations on arguments and // return values. - const FunctionVariantsTy &SpecVariants = FSMI->second; - for (const FunctionSummaryTy &Spec : SpecVariants) + const Summaries &SpecVariants = FSMI->second; + for (const Summary &Spec : SpecVariants) if (Spec.matchesCall(CE)) return Spec; @@ -487,9 +497,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( QualType LongLongTy = ACtx.LongLongTy; QualType SizeTy = ACtx.getSizeType(); - RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); - RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); - RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue(); + RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); + RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); + RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue(); // We are finally ready to define specifications for all supported functions. // @@ -517,538 +527,237 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( // // Please update the list of functions in the header after editing! // - // The format is as follows: - // - //{ "function name", - // { spec: - // { argument types list, ... }, - // return type, purity, { range set list: - // { range list: - // { argument index, within or out of, {{from, to}, ...} }, - // { argument index, compares to argument, {{how, which}} }, - // ... - // } - // } - // } - //} - -#define SUMMARY_WITH_VARIANTS(identifier) {#identifier, { -#define END_SUMMARY_WITH_VARIANTS }}, -#define VARIANT(argument_types, return_type, invalidation_approach) \ - { argument_types, return_type, invalidation_approach, { -#define END_VARIANT } }, -#define SUMMARY(identifier, argument_types, return_type, \ - invalidation_approach) \ - { #identifier, { { argument_types, return_type, invalidation_approach, { -#define END_SUMMARY } } } }, -#define ARGUMENT_TYPES(...) { __VA_ARGS__ } -#define RETURN_TYPE(x) x -#define INVALIDATION_APPROACH(x) x -#define CASE { -#define END_CASE }, -#define ARGUMENT_CONDITION(argument_number, condition_kind) \ - { argument_number, condition_kind, { -#define END_ARGUMENT_CONDITION }}, -#define RETURN_VALUE_CONDITION(condition_kind) \ - { Ret, condition_kind, { -#define END_RETURN_VALUE_CONDITION }}, -#define ARG_NO(x) x##U -#define RANGE(x, y) { x, y }, -#define SINGLE_VALUE(x) RANGE(x, x) -#define IS_LESS_THAN(arg) { BO_LE, arg } + + // Below are helper functions to create the summaries. + auto ArgumentCondition = [](ArgNo ArgN, ValueRangeKind Kind, + IntRangeVector Ranges) -> ValueRange { + ValueRange VR{ArgN, Kind, Ranges}; + return VR; + }; + auto ReturnValueCondition = [](ValueRangeKind Kind, + IntRangeVector Ranges) -> ValueRange { + ValueRange VR{Ret, Kind, Ranges}; + return VR; + }; + auto Range = [](RangeInt b, RangeInt e) { + return IntRangeVector{std::pair{b, e}}; + }; + auto SingleValue = [](RangeInt v) { + return IntRangeVector{std::pair{v, v}}; + }; + auto IsLessThan = [](ArgNo ArgN) { return IntRangeVector{{BO_LE, ArgN}}; }; + + using RetType = QualType; + + // Templates for summaries that are reused by many functions. + auto Getc = [&]() { + return Summary(ArgTypes{Irrelevant}, RetType{IntTy}, NoEvalCall) + .Case({ReturnValueCondition(WithinRange, Range(-1, 255))}); + }; + auto Read = [&](RetType R, RangeInt Max) { + return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R}, + NoEvalCall) + .Case({ReturnValueCondition(ComparesToArgument, IsLessThan(2)), + ReturnValueCondition(WithinRange, Range(-1, Max))}); + }; + auto Fread = [&]() { + return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy, Irrelevant}, + RetType{SizeTy}, NoEvalCall) + .Case({ + ReturnValueCondition(ComparesToArgument, IsLessThan(2)), + }); + }; + auto Getline = [&](RetType R, RangeInt Max) { + return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R}, + NoEvalCall) + .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})}); + }; FunctionSummaryMap = { - // The isascii() family of functions. - SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE // Boils down to isupper() or islower() or isdigit() - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE('0', '9') - RANGE('A', 'Z') - RANGE('a', 'z') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE // The locale-specific range. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(128, 255) - END_ARGUMENT_CONDITION - // No post-condition. We are completely unaware of - // locale-specific return values. - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE('0', '9') - RANGE('A', 'Z') - RANGE('a', 'z') - RANGE(128, 255) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE // isupper() or islower(). Note that 'Z' is less than 'a'. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE('A', 'Z') - RANGE('a', 'z') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE // The locale-specific range. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(128, 255) - END_ARGUMENT_CONDITION - END_CASE - CASE // Other. - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE('A', 'Z') - RANGE('a', 'z') - RANGE(128, 255) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE // Is ASCII. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(0, 127) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE(0, 127) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - SINGLE_VALUE('\t') - SINGLE_VALUE(' ') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - SINGLE_VALUE('\t') - SINGLE_VALUE(' ') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE // 0..31 or 127 - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(0, 32) - SINGLE_VALUE(127) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE(0, 32) - SINGLE_VALUE(127) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE // Is a digit. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE('0', '9') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE('0', '9') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(33, 126) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE(33, 126) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE // Is certainly lowercase. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE('a', 'z') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE // Is ascii but not lowercase. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(0, 127) - END_ARGUMENT_CONDITION - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE('a', 'z') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE // The locale-specific range. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(128, 255) - END_ARGUMENT_CONDITION - END_CASE - CASE // Is not an unsigned char. - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE(0, 255) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(32, 126) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE(32, 126) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE('!', '/') - RANGE(':', '@') - RANGE('[', '`') - RANGE('{', '~') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE('!', '/') - RANGE(':', '@') - RANGE('[', '`') - RANGE('{', '~') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE // Space, '\f', '\n', '\r', '\t', '\v'. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(9, 13) - SINGLE_VALUE(' ') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE // The locale-specific range. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(128, 255) - END_ARGUMENT_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE(9, 13) - SINGLE_VALUE(' ') - RANGE(128, 255) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE // Is certainly uppercase. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE('A', 'Z') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE // The locale-specific range. - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE(128, 255) - END_ARGUMENT_CONDITION - END_CASE - CASE // Other. - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE('A', 'Z') RANGE(128, 255) - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(EvalCallAsPure)) - CASE - ARGUMENT_CONDITION(ARG_NO(0), WithinRange) - RANGE('0', '9') - RANGE('A', 'F') - RANGE('a', 'f') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(OutOfRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - CASE - ARGUMENT_CONDITION(ARG_NO(0), OutOfRange) - RANGE('0', '9') - RANGE('A', 'F') - RANGE('a', 'f') - END_ARGUMENT_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(0) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - - // The getc() family of functions that returns either a char or an EOF. - SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(NoEvalCall)) - CASE // FIXME: EOF is assumed to be defined as -1. - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, 255) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(NoEvalCall)) - CASE // FIXME: EOF is assumed to be defined as -1. - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, 255) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy), - INVALIDATION_APPROACH(NoEvalCall)) - CASE // FIXME: EOF is assumed to be defined as -1. - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, 255) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - - // read()-like functions that never return more than buffer size. - // We are not sure how ssize_t is defined on every platform, so we provide - // three variants that should cover common cases. - SUMMARY_WITH_VARIANTS(read) - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), - RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, IntMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), - RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, LongMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), - RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, LongLongMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - END_SUMMARY_WITH_VARIANTS - SUMMARY_WITH_VARIANTS(write) - // Again, due to elusive nature of ssize_t, we have duplicate - // our summaries to cover different variants. - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), - RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, IntMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), - RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, LongMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), - RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, LongLongMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - END_SUMMARY_WITH_VARIANTS - SUMMARY(fread, - ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), - RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(fwrite, - ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant), - RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - - // getline()-like functions either fail or read at least the delimiter. - SUMMARY_WITH_VARIANTS(getline) - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), - RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(-1) - RANGE(1, IntMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), - RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(-1) - RANGE(1, LongMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), - RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(-1) - RANGE(1, LongLongMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - END_SUMMARY_WITH_VARIANTS - SUMMARY_WITH_VARIANTS(getdelim) - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), - RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(-1) - RANGE(1, IntMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), - RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(-1) - RANGE(1, LongMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), - RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(-1) - RANGE(1, LongLongMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_VARIANT - END_SUMMARY_WITH_VARIANTS + // The isascii() family of functions. + { + "isalnum", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + // Boils down to isupper() or islower() or isdigit(). + .Case( + {ArgumentCondition(0U, WithinRange, + {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + // The locale-specific range. + // No post-condition. We are completely unaware of + // locale-specific return values. + .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) + .Case({ArgumentCondition( + 0U, OutOfRange, + {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, 255}}), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isalpha", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case({ArgumentCondition(0U, WithinRange, + {{'A', 'Z'}, {'a', 'z'}}), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + // The locale-specific range. + .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) + .Case( + {ArgumentCondition(0U, OutOfRange, + {{'A', 'Z'}, {'a', 'z'}, {128, 255}}), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isascii", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isblank", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case({ArgumentCondition(0U, WithinRange, + {{'\t', '\t'}, {' ', ' '}}), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + .Case({ArgumentCondition(0U, OutOfRange, + {{'\t', '\t'}, {' ', ' '}}), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "iscntrl", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case({ArgumentCondition(0U, WithinRange, + {{0, 32}, {127, 127}}), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + .Case( + {ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isdigit", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isgraph", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "islower", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + // Is certainly lowercase. + .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + // Is ascii but not lowercase. + .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)), + ArgumentCondition(0U, OutOfRange, Range('a', 'z')), + ReturnValueCondition(WithinRange, SingleValue(0))}) + // The locale-specific range. + .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) + // Is not an unsigned char. + .Case({ArgumentCondition(0U, OutOfRange, Range(0, 255)), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isprint", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "ispunct", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case({ArgumentCondition( + 0U, WithinRange, + {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + .Case({ArgumentCondition( + 0U, OutOfRange, + {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isspace", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + // Space, '\f', '\n', '\r', '\t', '\v'. + .Case({ArgumentCondition(0U, WithinRange, + {{9, 13}, {' ', ' '}}), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + // The locale-specific range. + .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) + .Case({ArgumentCondition(0U, OutOfRange, + {{9, 13}, {' ', ' '}, {128, 255}}), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isupper", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + // Is certainly uppercase. + .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + // The locale-specific range. + .Case({ArgumentCondition(0U, WithinRange, {{128, 255}})}) + // Other. + .Case({ArgumentCondition(0U, OutOfRange, + {{'A', 'Z'}, {128, 255}}), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + { + "isxdigit", + Summaries{ + Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .Case( + {ArgumentCondition(0U, WithinRange, + {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), + ReturnValueCondition(OutOfRange, SingleValue(0))}) + .Case( + {ArgumentCondition(0U, OutOfRange, + {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}), + ReturnValueCondition(WithinRange, SingleValue(0))})}, + }, + + // The getc() family of functions that returns either a char or an EOF. + {"getc", Summaries{Getc()}}, + {"fgetc", Summaries{Getc()}}, + {"getchar", Summaries{Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall) + .Case({ReturnValueCondition(WithinRange, + Range(-1, 255))})}}, + + // read()-like functions that never return more than buffer size. + // We are not sure how ssize_t is defined on every platform, so we + // provide three variants that should cover common cases. + {"read", Summaries{Read(IntTy, IntMax), Read(LongTy, LongMax), + Read(LongLongTy, LongLongMax)}}, + {"write", Summaries{Read(IntTy, IntMax), Read(LongTy, LongMax), + Read(LongLongTy, LongLongMax)}}, + {"fread", Summaries{Fread()}}, + {"fwrite", Summaries{Fread()}}, + // getline()-like functions either fail or read at least the delimiter. + {"getline", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax), + Getline(LongLongTy, LongLongMax)}}, + {"getdelim", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax), + Getline(LongLongTy, LongLongMax)}}, }; }