Index: lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -79,11 +79,13 @@ /// impose a constraint that involves other argument or return value symbols. enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument }; + 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 @@ -185,9 +187,11 @@ return T; } + static bool typesAreEqual(QualType Lhs, QualType Rhs, ASTContext &ACtx); + /// 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; + bool matchesCall(const CallExpr *CE, ASTContext &ACtx) const; }; // The map of all functions supported by the checker. It is initialized @@ -386,31 +390,53 @@ llvm_unreachable("Unknown invalidation kind!"); } +bool StdLibraryFunctionsChecker::FunctionSummaryTy::typesAreEqual( + QualType Lhs, QualType Rhs, ASTContext &ACtx) { + // Lhs comes from the FunctionSummary, Rhs comes from the call expression. + // Hence lack of symmetry. + if (Lhs.isNull()) // "Irrelevant" types. + return true; + + assertTypeSuitableForSummary(Lhs); + assert(!Rhs.isNull()); + assert(Lhs.isCanonical()); + Rhs = Rhs.getCanonicalType(); + + // We're only requiring integral types to match by size and signedness, + // not be completely identical. Currently the only reason for that is + // our inability to guess ssize_t correctly from the AST context. + // FIXME: Maybe the proper solution would be to scan through typedefs. + if (!Lhs->isIntegralOrEnumerationType()) + return Lhs == Rhs; + if (!Rhs->isIntegralOrEnumerationType()) + return false; + + if (Lhs->isSignedIntegerOrEnumerationType() != + Rhs->isSignedIntegerOrEnumerationType()) + return false; + + return ACtx.getTypeSize(Lhs) == ACtx.getTypeSize(Rhs); +} + bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall( - const CallExpr *CE) const { + const CallExpr *CE, ASTContext &ACtx) const { // Check number of arguments: if (CE->getNumArgs() != ArgTypes.size()) return false; // Check return type if relevant: - if (!RetType.isNull() && RetType != CE->getType().getCanonicalType()) + if (!typesAreEqual(RetType, CE->getType().getCanonicalType(), ACtx)) 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) + if (!typesAreEqual(FormalT, ActualT, ACtx)) return false; } - return true; } @@ -443,7 +469,7 @@ // very integral-type-sensitive operations on arguments and // return values. const FunctionSummaryTy &Spec = FSMI->second; - if (!Spec.matchesCall(CE)) + if (!Spec.matchesCall(CE, C.getASTContext())) return None; return Spec; @@ -464,9 +490,9 @@ QualType SSizeTy = ACtx.getIntTypeForBitwidth(ACtx.getTypeSize(SizeTy), true); // Don't worry about truncation here, it'd be cast back to SIZE_MAX when used. - LLVM_ATTRIBUTE_UNUSED int64_t SizeMax = + LLVM_ATTRIBUTE_UNUSED RangeIntTy SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue(); - int64_t SSizeMax = + RangeIntTy SSizeMax = BVF.getMaxValue(SSizeTy).getLimitedValue(); // We are finally ready to define specifications for all supported functions. 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); @@ -22,7 +26,6 @@ clang_analyzer_eval(fgetc(fp) >= 0); // expected-warning{{UNKNOWN}} } - typedef unsigned long size_t; typedef signed long ssize_t; ssize_t read(int, void *, size_t);