Index: lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -79,11 +79,15 @@ /// 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> IntRangeVectorTy; + typedef std::vector> IntRangeVectorTy; /// A reference to an argument or return value by its number. /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but @@ -192,7 +196,8 @@ // The map of all functions supported by the checker. It is initialized // lazily, and it doesn't change after initialization. - typedef llvm::StringMap FunctionSummaryMapTy; + typedef std::vector FunctionVariantsTy; + typedef llvm::StringMap FunctionSummaryMapTy; mutable FunctionSummaryMapTy FunctionSummaryMap; // Auxiliary functions to support ArgNoTy within all structures @@ -442,11 +447,12 @@ // Strict checking is important because we will be conducting // very integral-type-sensitive operations on arguments and // return values. - const FunctionSummaryTy &Spec = FSMI->second; - if (!Spec.matchesCall(CE)) - return None; + const FunctionVariantsTy &SpecVariants = FSMI->second; + for (const FunctionSummaryTy &Spec : SpecVariants) + if (Spec.matchesCall(CE)) + return Spec; - return Spec; + return None; } void StdLibraryFunctionsChecker::initFunctionSummaries( @@ -460,15 +466,13 @@ // New specifications should probably introduce more types. 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(); - QualType SSizeTy = ACtx.getIntTypeForBitwidth(ACtx.getTypeSize(SizeTy), true); - // Don't worry about truncation here, it'd be cast back to SIZE_MAX when used. - int64_t SizeMax = - BVF.getMaxValue(SizeTy).getLimitedValue(); - int64_t SSizeMax = - BVF.getMaxValue(SSizeTy).getLimitedValue(); - (void)SizeMax; + 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. // @@ -511,10 +515,15 @@ // } //} +#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 }}}, + {#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 @@ -871,28 +880,76 @@ END_SUMMARY // read()-like functions that never return more than buffer size. - SUMMARY(read, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), - RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, SSizeMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(write, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy), - RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(ComparesToArgument) - IS_LESS_THAN(ARG_NO(2)) - END_RETURN_VALUE_CONDITION - RETURN_VALUE_CONDITION(WithinRange) - RANGE(-1, SSizeMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY + 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) + 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)) @@ -913,25 +970,64 @@ END_SUMMARY // getline()-like functions either fail or read at least the delimiter. - SUMMARY(getline, ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant), - RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(-1) - RANGE(1, SSizeMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY - SUMMARY(getdelim, - ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant), - RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall)) - CASE - RETURN_VALUE_CONDITION(WithinRange) - SINGLE_VALUE(-1) - RANGE(1, SSizeMax) - END_RETURN_VALUE_CONDITION - END_CASE - END_SUMMARY + 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 }; } Index: test/Analysis/std-c-library-functions.c =================================================================== --- test/Analysis/std-c-library-functions.c +++ test/Analysis/std-c-library-functions.c @@ -1,4 +1,8 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s +// RUN: %clang_cc1 -triple i686-unknown-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s // RUN: %clang_cc1 -triple x86_64-unknown-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s +// RUN: %clang_cc1 -triple armv7-a15-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s +// RUN: %clang_cc1 -triple thumbv7-a15-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s void clang_analyzer_eval(int); @@ -23,7 +27,7 @@ } -typedef unsigned long size_t; +typedef typeof(sizeof(int)) size_t; typedef signed long ssize_t; ssize_t read(int, void *, size_t); ssize_t write(int, const void *, size_t);