aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/ScanfFormatString.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis/ScanfFormatString.cpp')
-rw-r--r--lib/Analysis/ScanfFormatString.cpp193
1 files changed, 92 insertions, 101 deletions
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 6bc4adb4f3c6..2942400621d1 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -15,12 +15,11 @@
#include "clang/Analysis/Analyses/FormatString.h"
#include "FormatStringParsing.h"
-using clang::analyze_format_string::ArgTypeResult;
+using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
using clang::analyze_format_string::LengthModifier;
using clang::analyze_format_string::OptionalAmount;
using clang::analyze_format_string::ConversionSpecifier;
-using clang::analyze_scanf::ScanfArgTypeResult;
using clang::analyze_scanf::ScanfConversionSpecifier;
using clang::analyze_scanf::ScanfSpecifier;
using clang::UpdateOnReturn;
@@ -194,37 +193,42 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
return ScanfSpecifierResult(Start, FS);
}
-ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
+ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
const ScanfConversionSpecifier &CS = getConversionSpecifier();
if (!CS.consumesDataArgument())
- return ScanfArgTypeResult::Invalid();
+ return ArgType::Invalid();
switch(CS.getKind()) {
// Signed int.
case ConversionSpecifier::dArg:
case ConversionSpecifier::iArg:
switch (LM.getKind()) {
- case LengthModifier::None: return ArgTypeResult(Ctx.IntTy);
+ case LengthModifier::None:
+ return ArgType::PtrTo(Ctx.IntTy);
case LengthModifier::AsChar:
- return ArgTypeResult(ArgTypeResult::AnyCharTy);
- case LengthModifier::AsShort: return ArgTypeResult(Ctx.ShortTy);
- case LengthModifier::AsLong: return ArgTypeResult(Ctx.LongTy);
+ return ArgType::PtrTo(ArgType::AnyCharTy);
+ case LengthModifier::AsShort:
+ return ArgType::PtrTo(Ctx.ShortTy);
+ case LengthModifier::AsLong:
+ return ArgType::PtrTo(Ctx.LongTy);
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
- return ArgTypeResult(Ctx.LongLongTy);
+ return ArgType::PtrTo(Ctx.LongLongTy);
case LengthModifier::AsIntMax:
- return ScanfArgTypeResult(Ctx.getIntMaxType(), "intmax_t *");
+ return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
// FIXME: ssize_t.
- return ScanfArgTypeResult();
+ return ArgType();
case LengthModifier::AsPtrDiff:
- return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *");
+ return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
case LengthModifier::AsLongDouble:
// GNU extension.
- return ArgTypeResult(Ctx.LongLongTy);
- case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
- case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
+ return ArgType::PtrTo(Ctx.LongLongTy);
+ case LengthModifier::AsAllocate:
+ return ArgType::Invalid();
+ case LengthModifier::AsMAllocate:
+ return ArgType::Invalid();
}
// Unsigned int.
@@ -233,25 +237,31 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
switch (LM.getKind()) {
- case LengthModifier::None: return ArgTypeResult(Ctx.UnsignedIntTy);
- case LengthModifier::AsChar: return ArgTypeResult(Ctx.UnsignedCharTy);
- case LengthModifier::AsShort: return ArgTypeResult(Ctx.UnsignedShortTy);
- case LengthModifier::AsLong: return ArgTypeResult(Ctx.UnsignedLongTy);
+ case LengthModifier::None:
+ return ArgType::PtrTo(Ctx.UnsignedIntTy);
+ case LengthModifier::AsChar:
+ return ArgType::PtrTo(Ctx.UnsignedCharTy);
+ case LengthModifier::AsShort:
+ return ArgType::PtrTo(Ctx.UnsignedShortTy);
+ case LengthModifier::AsLong:
+ return ArgType::PtrTo(Ctx.UnsignedLongTy);
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
- return ArgTypeResult(Ctx.UnsignedLongLongTy);
+ return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
case LengthModifier::AsIntMax:
- return ScanfArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t *");
+ return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
case LengthModifier::AsSizeT:
- return ScanfArgTypeResult(Ctx.getSizeType(), "size_t *");
+ return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
case LengthModifier::AsPtrDiff:
// FIXME: Unsigned version of ptrdiff_t?
- return ScanfArgTypeResult();
+ return ArgType();
case LengthModifier::AsLongDouble:
// GNU extension.
- return ArgTypeResult(Ctx.UnsignedLongLongTy);
- case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
- case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
+ return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
+ case LengthModifier::AsAllocate:
+ return ArgType::Invalid();
+ case LengthModifier::AsMAllocate:
+ return ArgType::Invalid();
}
// Float.
@@ -264,12 +274,14 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case ConversionSpecifier::gArg:
case ConversionSpecifier::GArg:
switch (LM.getKind()) {
- case LengthModifier::None: return ArgTypeResult(Ctx.FloatTy);
- case LengthModifier::AsLong: return ArgTypeResult(Ctx.DoubleTy);
+ case LengthModifier::None:
+ return ArgType::PtrTo(Ctx.FloatTy);
+ case LengthModifier::AsLong:
+ return ArgType::PtrTo(Ctx.DoubleTy);
case LengthModifier::AsLongDouble:
- return ArgTypeResult(Ctx.LongDoubleTy);
+ return ArgType::PtrTo(Ctx.LongDoubleTy);
default:
- return ScanfArgTypeResult::Invalid();
+ return ArgType::Invalid();
}
// Char, string and scanlist.
@@ -277,37 +289,65 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case ConversionSpecifier::sArg:
case ConversionSpecifier::ScanListArg:
switch (LM.getKind()) {
- case LengthModifier::None: return ScanfArgTypeResult::CStrTy;
+ case LengthModifier::None:
+ return ArgType::PtrTo(ArgType::AnyCharTy);
case LengthModifier::AsLong:
- return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
+ return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
- return ScanfArgTypeResult(ArgTypeResult::CStrTy);
+ return ArgType::PtrTo(ArgType::CStrTy);
default:
- return ScanfArgTypeResult::Invalid();
+ return ArgType::Invalid();
}
case ConversionSpecifier::CArg:
case ConversionSpecifier::SArg:
// FIXME: Mac OS X specific?
switch (LM.getKind()) {
case LengthModifier::None:
- return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
+ return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
- return ScanfArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t **");
+ return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
default:
- return ScanfArgTypeResult::Invalid();
+ return ArgType::Invalid();
}
// Pointer.
case ConversionSpecifier::pArg:
- return ScanfArgTypeResult(ArgTypeResult(ArgTypeResult::CPointerTy));
+ return ArgType::PtrTo(ArgType::CPointerTy);
+
+ // Write-back.
+ case ConversionSpecifier::nArg:
+ switch (LM.getKind()) {
+ case LengthModifier::None:
+ return ArgType::PtrTo(Ctx.IntTy);
+ case LengthModifier::AsChar:
+ return ArgType::PtrTo(Ctx.SignedCharTy);
+ case LengthModifier::AsShort:
+ return ArgType::PtrTo(Ctx.ShortTy);
+ case LengthModifier::AsLong:
+ return ArgType::PtrTo(Ctx.LongTy);
+ case LengthModifier::AsLongLong:
+ case LengthModifier::AsQuad:
+ return ArgType::PtrTo(Ctx.LongLongTy);
+ case LengthModifier::AsIntMax:
+ return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
+ case LengthModifier::AsSizeT:
+ return ArgType(); // FIXME: ssize_t
+ case LengthModifier::AsPtrDiff:
+ return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
+ case LengthModifier::AsLongDouble:
+ return ArgType(); // FIXME: Is this a known extension?
+ case LengthModifier::AsAllocate:
+ case LengthModifier::AsMAllocate:
+ return ArgType::Invalid();
+ }
default:
break;
}
- return ScanfArgTypeResult();
+ return ArgType();
}
bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
@@ -315,7 +355,16 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
if (!QT->isPointerType())
return false;
+ // %n is different from other conversion specifiers; don't try to fix it.
+ if (CS.getKind() == ConversionSpecifier::nArg)
+ return false;
+
QualType PT = QT->getPointeeType();
+
+ // If it's an enum, get its underlying type.
+ if (const EnumType *ETy = QT->getAs<EnumType>())
+ QT = ETy->getDecl()->getIntegerType();
+
const BuiltinType *BT = PT->getAs<BuiltinType>();
if (!BT)
return false;
@@ -377,25 +426,12 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
- const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
- if (Identifier->getName() == "size_t") {
- LM.setKind(LengthModifier::AsSizeT);
- } else if (Identifier->getName() == "ssize_t") {
- // Not C99, but common in Unix.
- LM.setKind(LengthModifier::AsSizeT);
- } else if (Identifier->getName() == "intmax_t") {
- LM.setKind(LengthModifier::AsIntMax);
- } else if (Identifier->getName() == "uintmax_t") {
- LM.setKind(LengthModifier::AsIntMax);
- } else if (Identifier->getName() == "ptrdiff_t") {
- LM.setKind(LengthModifier::AsPtrDiff);
- }
- }
+ if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+ namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
- const analyze_scanf::ScanfArgTypeResult &ATR = getArgType(Ctx);
- if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
+ const analyze_scanf::ArgType &AT = getArgType(Ctx);
+ if (hasValidLengthModifier() && AT.isValid() && AT.matchesType(Ctx, QT))
return true;
// Figure out the conversion specifier.
@@ -452,48 +488,3 @@ bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
assert(I == E && "Format string not exhausted");
return false;
}
-
-bool ScanfArgTypeResult::matchesType(ASTContext& C, QualType argTy) const {
- switch (K) {
- case InvalidTy:
- llvm_unreachable("ArgTypeResult must be valid");
- case UnknownTy:
- return true;
- case CStrTy:
- return ArgTypeResult(ArgTypeResult::CStrTy).matchesType(C, argTy);
- case WCStrTy:
- return ArgTypeResult(ArgTypeResult::WCStrTy).matchesType(C, argTy);
- case PtrToArgTypeResultTy: {
- const PointerType *PT = argTy->getAs<PointerType>();
- if (!PT)
- return false;
- return A.matchesType(C, PT->getPointeeType());
- }
- }
-
- llvm_unreachable("Invalid ScanfArgTypeResult Kind!");
-}
-
-QualType ScanfArgTypeResult::getRepresentativeType(ASTContext &C) const {
- switch (K) {
- case InvalidTy:
- llvm_unreachable("No representative type for Invalid ArgTypeResult");
- case UnknownTy:
- return QualType();
- case CStrTy:
- return C.getPointerType(C.CharTy);
- case WCStrTy:
- return C.getPointerType(C.getWCharType());
- case PtrToArgTypeResultTy:
- return C.getPointerType(A.getRepresentativeType(C));
- }
-
- llvm_unreachable("Invalid ScanfArgTypeResult Kind!");
-}
-
-std::string ScanfArgTypeResult::getRepresentativeTypeName(ASTContext& C) const {
- std::string S = getRepresentativeType(C).getAsString();
- if (!Name)
- return std::string("'") + S + "'";
- return std::string("'") + Name + "' (aka '" + S + "')";
-}