diff options
| author | Seth Cantrell <seth.cantrell@gmail.com> | 2015-03-04 03:12:10 +0000 |
|---|---|---|
| committer | Seth Cantrell <seth.cantrell@gmail.com> | 2015-03-04 03:12:10 +0000 |
| commit | b480296e6cb4a2cc5d5f588e35d4148f8770fea9 (patch) | |
| tree | c7a8c0e3e3c63e4f8dc835d884b3c948d7c3cf16 /clang/lib/Analysis | |
| parent | 9412d63f683346e010261662acf97e8c10cb8d03 (diff) | |
| download | bcm5719-llvm-b480296e6cb4a2cc5d5f588e35d4148f8770fea9.tar.gz bcm5719-llvm-b480296e6cb4a2cc5d5f588e35d4148f8770fea9.zip | |
Add a format warning for "%p" with non-void* args
GCC -pedantic produces a format warning when the "%p" specifier is used with
arguments that are not void*. It's useful for portability to be able to
catch such warnings with clang as well. The warning is off by default in
both gcc and with this patch. This patch enables it either when extensions
are disabled with -pedantic, or with the specific flag -Wformat-pedantic.
The C99 and C11 specs do appear to require arguments corresponding to 'p'
specifiers to be void*: "If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined."
[7.19.6.1 p9], and of the 'p' format specifier "The argument shall be a
pointer to void." [7.19.6.1 p8]
Both printf and scanf format checking are covered.
llvm-svn: 231211
Diffstat (limited to 'clang/lib/Analysis')
| -rw-r--r-- | clang/lib/Analysis/FormatString.cpp | 82 |
1 files changed, 45 insertions, 37 deletions
diff --git a/clang/lib/Analysis/FormatString.cpp b/clang/lib/Analysis/FormatString.cpp index 662166ccaac..1b608941f0d 100644 --- a/clang/lib/Analysis/FormatString.cpp +++ b/clang/lib/Analysis/FormatString.cpp @@ -256,16 +256,17 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, // Methods on ArgType. //===----------------------------------------------------------------------===// -bool ArgType::matchesType(ASTContext &C, QualType argTy) const { +clang::analyze_format_string::ArgType::MatchKind +ArgType::matchesType(ASTContext &C, QualType argTy) const { if (Ptr) { // It has to be a pointer. const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; // We cannot write through a const qualified pointer. if (PT->getPointeeType().isConstQualified()) - return false; + return NoMatch; argTy = PT->getPointeeType(); } @@ -275,8 +276,8 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { llvm_unreachable("ArgType must be valid"); case UnknownTy: - return true; - + return Match; + case AnyCharTy: { if (const EnumType *ETy = argTy->getAs<EnumType>()) argTy = ETy->getDecl()->getIntegerType(); @@ -289,18 +290,18 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Char_U: - return true; + return Match; } - return false; + return NoMatch; } - + case SpecificTy: { if (const EnumType *ETy = argTy->getAs<EnumType>()) argTy = ETy->getDecl()->getIntegerType(); argTy = C.getCanonicalType(argTy).getUnqualifiedType(); if (T == argTy) - return true; + return Match; // Check for "compatible types". if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) switch (BT->getKind()) { @@ -309,32 +310,33 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::Char_S: case BuiltinType::SChar: case BuiltinType::Char_U: - case BuiltinType::UChar: - return T == C.UnsignedCharTy || T == C.SignedCharTy; + case BuiltinType::UChar: + return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match + : NoMatch; case BuiltinType::Short: - return T == C.UnsignedShortTy; + return T == C.UnsignedShortTy ? Match : NoMatch; case BuiltinType::UShort: - return T == C.ShortTy; + return T == C.ShortTy ? Match : NoMatch; case BuiltinType::Int: - return T == C.UnsignedIntTy; + return T == C.UnsignedIntTy ? Match : NoMatch; case BuiltinType::UInt: - return T == C.IntTy; + return T == C.IntTy ? Match : NoMatch; case BuiltinType::Long: - return T == C.UnsignedLongTy; + return T == C.UnsignedLongTy ? Match : NoMatch; case BuiltinType::ULong: - return T == C.LongTy; + return T == C.LongTy ? Match : NoMatch; case BuiltinType::LongLong: - return T == C.UnsignedLongLongTy; + return T == C.UnsignedLongLongTy ? Match : NoMatch; case BuiltinType::ULongLong: - return T == C.LongLongTy; + return T == C.LongLongTy ? Match : NoMatch; } - return false; + return NoMatch; } case CStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; QualType pointeeTy = PT->getPointeeType(); if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) switch (BT->getKind()) { @@ -343,50 +345,56 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: - return true; + return Match; default: break; } - return false; + return NoMatch; } case WCStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; QualType pointeeTy = C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); - return pointeeTy == C.getWideCharType(); + return pointeeTy == C.getWideCharType() ? Match : NoMatch; } - + case WIntTy: { - + QualType PromoArg = argTy->isPromotableIntegerType() ? C.getPromotedIntegerType(argTy) : argTy; - + QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType(); PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); - + // If the promoted argument is the corresponding signed type of the // wint_t type, then it should match. if (PromoArg->hasSignedIntegerRepresentation() && C.getCorrespondingUnsignedType(PromoArg) == WInt) - return true; + return Match; - return WInt == PromoArg; + return WInt == PromoArg ? Match : NoMatch; } case CPointerTy: - return argTy->isPointerType() || argTy->isObjCObjectPointerType() || - argTy->isBlockPointerType() || argTy->isNullPtrType(); + if (argTy->isVoidPointerType()) { + return Match; + } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() || + argTy->isBlockPointerType() || argTy->isNullPtrType()) { + return NoMatchPedantic; + } else { + return NoMatch; + } case ObjCPointerTy: { if (argTy->getAs<ObjCObjectPointerType>() || argTy->getAs<BlockPointerType>()) - return true; - + return Match; + // Handle implicit toll-free bridging. if (const PointerType *PT = argTy->getAs<PointerType>()) { // Things such as CFTypeRef are really just opaque pointers @@ -395,9 +403,9 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { // structs can be toll-free bridged, we just accept them all. QualType pointee = PT->getPointeeType(); if (pointee->getAsStructureType() || pointee->isVoidType()) - return true; + return Match; } - return false; + return NoMatch; } } |

