diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
commit | 0b57cec536236d46e3dba9bd041533462f33dbb7 (patch) | |
tree | 56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp | |
parent | 718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff) |
Notes
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp | 1065 |
1 files changed, 0 insertions, 1065 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp deleted file mode 100644 index 2cdee8da375e..000000000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ /dev/null @@ -1,1065 +0,0 @@ -//=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This checker improves modeling of a few simple library functions. -// It does not generate warnings. -// -// This checker provides a specification format - `FunctionSummaryTy' - 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 -// are satisfied on each branch. This spec can be expanded to include more -// items, like external effects of the function. -// -// The main difference between this approach and the body farms technique is -// in more explicit control over how many branches are produced. For example, -// 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, -// 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, -// once we consider a branch on which `x' is in range, say, ['!', '/'], -// we assume that such branch is an important separate path through the program, -// 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. -// -// 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: -// -// fgetc getline isdigit isupper -// fread isalnum isgraph isxdigit -// fwrite isalpha islower read -// getc isascii isprint write -// getchar isblank ispunct -// getdelim iscntrl isspace -// -//===----------------------------------------------------------------------===// - -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" - -using namespace clang; -using namespace clang::ento; - -namespace { -class StdLibraryFunctionsChecker : public Checker<check::PostCall, eval::Call> { - /// 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; - - /// 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 }; - - /// A pair of ValueRangeKindTy and IntRangeVectorTy 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 }; - - // The universal integral type to use in value range descriptions. - // Unsigned to make sure overflows are well-defined. - typedef uint64_t RangeIntTy; - - /// 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<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy; - - /// 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<ArgNoTy>::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. - - public: - ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind, - const IntRangeVectorTy &Args) - : ArgNo(ArgNo), Kind(Kind), Args(Args) {} - - ArgNoTy getArgNo() const { return ArgNo; } - ValueRangeKindTy getKind() const { return Kind; } - - BinaryOperator::Opcode getOpcode() const { - assert(Kind == ComparesToArgument); - assert(Args.size() == 1); - BinaryOperator::Opcode Op = - static_cast<BinaryOperator::Opcode>(Args[0].first); - assert(BinaryOperator::isComparisonOp(Op) && - "Only comparison ops are supported for ComparesToArgument"); - return Op; - } - - ArgNoTy getOtherArgNo() const { - assert(Kind == ComparesToArgument); - assert(Args.size() == 1); - return static_cast<ArgNoTy>(Args[0].second); - } - - const IntRangeVectorTy &getRanges() const { - assert(Kind != ComparesToArgument); - return Args; - } - - // 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; - - public: - ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const { - switch (Kind) { - case OutOfRange: - return applyAsOutOfRange(State, Call, Summary); - case WithinRange: - return applyAsWithinRange(State, Call, Summary); - case ComparesToArgument: - return applyAsComparesToArgument(State, Call, Summary); - } - llvm_unreachable("Unknown ValueRange kind!"); - } - }; - - /// The complete list of ranges that defines a single branch. - typedef std::vector<ValueRange> ValueRangeSet; - - /// 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<QualType> ArgTypes; - const QualType RetType; - const InvalidationKindTy InvalidationKind; - const std::vector<ValueRangeSet> Ranges; - - private: - static void assertTypeSuitableForSummary(QualType T) { - assert(!T->isVoidType() && - "We should have had no significant void types in the spec"); - assert(T.isCanonical() && - "We should only have canonical types in the spec"); - // FIXME: lift this assert (but not the ones above!) - assert(T->isIntegralOrEnumerationType() && - "We only support integral ranges in the spec"); - } - - public: - QualType getArgType(ArgNoTy ArgNo) const { - QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo]; - assertTypeSuitableForSummary(T); - return T; - } - - /// Try our best to figure out if the call expression is the call of - /// *the* library function to which this specification applies. - bool matchesCall(const CallExpr *CE) const; - }; - - // The same function (as in, function identifier) may have different - // summaries assigned to it, with different argument and return value types. - // 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<FunctionSummaryTy> FunctionVariantsTy; - - // The map of all functions supported by the checker. It is initialized - // lazily, and it doesn't change after initialization. - typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy; - mutable FunctionSummaryMapTy FunctionSummaryMap; - - // Auxiliary functions to support ArgNoTy within all structures - // in a unified manner. - static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) { - return Summary.getArgType(ArgNo); - } - static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) { - return ArgNo == Ret ? Call.getResultType().getCanonicalType() - : Call.getArgExpr(ArgNo)->getType().getCanonicalType(); - } - static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) { - return ArgNo == Ret ? CE->getType().getCanonicalType() - : CE->getArg(ArgNo)->getType().getCanonicalType(); - } - static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) { - return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo); - } - -public: - void checkPostCall(const CallEvent &Call, CheckerContext &C) const; - bool evalCall(const CallEvent &Call, CheckerContext &C) const; - -private: - Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD, - const CallExpr *CE, - CheckerContext &C) const; - - void initFunctionSummaries(BasicValueFactory &BVF) const; -}; -} // end of anonymous namespace - -ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange( - ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const { - - ProgramStateManager &Mgr = State->getStateManager(); - SValBuilder &SVB = Mgr.getSValBuilder(); - BasicValueFactory &BVF = SVB.getBasicValueFactory(); - ConstraintManager &CM = Mgr.getConstraintManager(); - QualType T = getArgType(Summary, getArgNo()); - SVal V = getArgSVal(Call, getArgNo()); - - if (auto N = V.getAs<NonLoc>()) { - const IntRangeVectorTy &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); - const llvm::APSInt &Max = BVF.getValue(R[I].second, T); - assert(Min <= Max); - State = CM.assumeInclusiveRange(State, *N, Min, Max, false); - if (!State) - break; - } - } - - return State; -} - -ProgramStateRef -StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange( - ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const { - - ProgramStateManager &Mgr = State->getStateManager(); - SValBuilder &SVB = Mgr.getSValBuilder(); - BasicValueFactory &BVF = SVB.getBasicValueFactory(); - ConstraintManager &CM = Mgr.getConstraintManager(); - QualType T = getArgType(Summary, getArgNo()); - SVal V = getArgSVal(Call, getArgNo()); - - // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R". - // 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<NonLoc>()) { - const IntRangeVectorTy &R = getRanges(); - size_t E = R.size(); - - const llvm::APSInt &MinusInf = BVF.getMinValue(T); - const llvm::APSInt &PlusInf = BVF.getMaxValue(T); - - const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T); - if (Left != PlusInf) { - assert(MinusInf <= Left); - State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false); - if (!State) - return nullptr; - } - - const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T); - if (Right != MinusInf) { - assert(Right <= PlusInf); - State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false); - if (!State) - return nullptr; - } - - for (size_t I = 1; I != E; ++I) { - const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T); - const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T); - assert(Min <= Max); - State = CM.assumeInclusiveRange(State, *N, Min, Max, false); - if (!State) - return nullptr; - } - } - - return State; -} - -ProgramStateRef -StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument( - ProgramStateRef State, const CallEvent &Call, - const FunctionSummaryTy &Summary) const { - - ProgramStateManager &Mgr = State->getStateManager(); - SValBuilder &SVB = Mgr.getSValBuilder(); - QualType CondT = SVB.getConditionType(); - QualType T = getArgType(Summary, getArgNo()); - SVal V = getArgSVal(Call, getArgNo()); - - BinaryOperator::Opcode Op = getOpcode(); - ArgNoTy OtherArg = getOtherArgNo(); - SVal OtherV = getArgSVal(Call, OtherArg); - QualType OtherT = getArgType(Call, OtherArg); - // Note: we avoid integral promotion for comparison. - OtherV = SVB.evalCast(OtherV, T, OtherT); - if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT) - .getAs<DefinedOrUnknownSVal>()) - State = State->assume(*CompV, true); - return State; -} - -void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, - CheckerContext &C) const { - const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); - if (!FD) - return; - - const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); - if (!CE) - return; - - Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C); - if (!FoundSummary) - return; - - // Now apply ranges. - const FunctionSummaryTy &Summary = *FoundSummary; - ProgramStateRef State = C.getState(); - - for (const auto &VRS: Summary.Ranges) { - ProgramStateRef NewState = State; - for (const auto &VR: VRS) { - NewState = VR.apply(NewState, Call, Summary); - if (!NewState) - break; - } - - if (NewState && NewState != State) - C.addTransition(NewState); - } -} - -bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, - CheckerContext &C) const { - const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); - if (!FD) - return false; - - const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); - if (!CE) - return false; - - Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C); - if (!FoundSummary) - return false; - - const FunctionSummaryTy &Summary = *FoundSummary; - switch (Summary.InvalidationKind) { - case EvalCallAsPure: { - ProgramStateRef State = C.getState(); - const LocationContext *LC = C.getLocationContext(); - SVal V = C.getSValBuilder().conjureSymbolVal( - CE, LC, CE->getType().getCanonicalType(), C.blockCount()); - State = State->BindExpr(CE, LC, V); - C.addTransition(State); - return true; - } - case NoEvalCall: - // Summary tells us to avoid performing eval::Call. The function is possibly - // evaluated by another checker, or evaluated conservatively. - return false; - } - llvm_unreachable("Unknown invalidation kind!"); -} - -bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall( - const CallExpr *CE) const { - // Check number of arguments: - if (CE->getNumArgs() != ArgTypes.size()) - return false; - - // Check return type if relevant: - if (!RetType.isNull() && RetType != 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]; - // Null type marks irrelevant arguments. - if (FormalT.isNull()) - continue; - - assertTypeSuitableForSummary(FormalT); - - QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I); - assert(ActualT.isCanonical()); - if (ActualT != FormalT) - return false; - } - - return true; -} - -Optional<StdLibraryFunctionsChecker::FunctionSummaryTy> -StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD, - const CallExpr *CE, - CheckerContext &C) const { - // Note: we cannot always obtain FD from CE - // (eg. virtual call, or call by pointer). - assert(CE); - - if (!FD) - return None; - - SValBuilder &SVB = C.getSValBuilder(); - BasicValueFactory &BVF = SVB.getBasicValueFactory(); - initFunctionSummaries(BVF); - - IdentifierInfo *II = FD->getIdentifier(); - if (!II) - return None; - StringRef Name = II->getName(); - if (Name.empty() || !C.isCLibraryFunction(FD, Name)) - return None; - - auto FSMI = FunctionSummaryMap.find(Name); - if (FSMI == FunctionSummaryMap.end()) - return None; - - // Verify that function signature matches the spec in advance. - // Otherwise we might be modeling the wrong function. - // 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) - if (Spec.matchesCall(CE)) - return Spec; - - return None; -} - -void StdLibraryFunctionsChecker::initFunctionSummaries( - BasicValueFactory &BVF) const { - if (!FunctionSummaryMap.empty()) - return; - - ASTContext &ACtx = BVF.getContext(); - - // These types are useful for writing specifications quickly, - // New specifications should probably introduce more types. - // Some types are hard to obtain from the AST, eg. "ssize_t". - // In such cases it should be possible to provide multiple variants - // of function summary for common cases (eg. ssize_t could be int or long - // or long long, so three summary variants would be enough). - // Of course, function variants are also useful for C++ overloads. - QualType Irrelevant; // A placeholder, whenever we do not care about the type. - QualType IntTy = ACtx.IntTy; - QualType LongTy = ACtx.LongTy; - 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(); - - // We are finally ready to define specifications for all supported functions. - // - // The signature needs to have the correct number of arguments. - // However, we insert `Irrelevant' when the type is insignificant. - // - // Argument ranges should always cover all variants. If return value - // is completely unknown, omit it from the respective range set. - // - // All types in the spec need to be canonical. - // - // Every item in the list of range sets represents a particular - // execution path the analyzer would need to explore once - // the call is modeled - a new program state is constructed - // for every range set, and each range line in the range set - // corresponds to a specific constraint within this state. - // - // Upon comparing to another argument, the other argument is casted - // to the current argument's type. This avoids proper promotion but - // seems useful. For example, read() receives size_t argument, - // and its return value, which is of type ssize_t, cannot be greater - // than this argument. If we made a promotion, and the size argument - // is equal to, say, 10, then we'd impose a range of [0, 10] on the - // return value, however the correct range is [-1, 10]. - // - // 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 } - - 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 - }; -} - -void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { - // If this checker grows large enough to support C++, Objective-C, or other - // standard libraries, we could use multiple register...Checker() functions, - // which would register various checkers with the help of the same Checker - // class, turning on different function summaries. - mgr.registerChecker<StdLibraryFunctionsChecker>(); -} - -bool ento::shouldRegisterStdCLibraryFunctionsChecker(const LangOptions &LO) { - return true; -} |