diff options
Diffstat (limited to 'lib/Analysis/PrintfFormatString.cpp')
-rw-r--r-- | lib/Analysis/PrintfFormatString.cpp | 167 |
1 files changed, 85 insertions, 82 deletions
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 46ece65a42e7..e1049b3c685b 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -51,7 +51,8 @@ static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, - unsigned &argIndex) { + unsigned &argIndex, + const LangOptions &LO) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; @@ -150,7 +151,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, } // Look for the length modifier. - if (ParseLengthModifier(FS, I, E) && I == E) { + if (ParseLengthModifier(FS, I, E, LO) && I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; @@ -210,13 +211,15 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, const char *I, - const char *E) { + const char *E, + const LangOptions &LO) { unsigned argIndex = 0; // Keep looking for a format specifier until we have exhausted the string. while (I != E) { - const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex); + const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, + LO); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) @@ -235,50 +238,11 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, } //===----------------------------------------------------------------------===// -// Methods on ConversionSpecifier. -//===----------------------------------------------------------------------===// -const char *ConversionSpecifier::toString() const { - switch (kind) { - case dArg: return "d"; - case iArg: return "i"; - case oArg: return "o"; - case uArg: return "u"; - case xArg: return "x"; - case XArg: return "X"; - case fArg: return "f"; - case FArg: return "F"; - case eArg: return "e"; - case EArg: return "E"; - case gArg: return "g"; - case GArg: return "G"; - case aArg: return "a"; - case AArg: return "A"; - case cArg: return "c"; - case sArg: return "s"; - case pArg: return "p"; - case nArg: return "n"; - case PercentArg: return "%"; - case ScanListArg: return "["; - case InvalidSpecifier: return NULL; - - // MacOS X unicode extensions. - case CArg: return "C"; - case SArg: return "S"; - - // Objective-C specific specifiers. - case ObjCObjArg: return "@"; - - // GlibC specific specifiers. - case PrintErrno: return "m"; - } - return NULL; -} - -//===----------------------------------------------------------------------===// // Methods on PrintfSpecifier. //===----------------------------------------------------------------------===// -ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { +ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx, + bool IsObjCLiteral) const { const PrintfConversionSpecifier &CS = getConversionSpecifier(); if (!CS.consumesDataArgument()) @@ -287,7 +251,8 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { if (CS.getKind() == ConversionSpecifier::cArg) switch (LM.getKind()) { case LengthModifier::None: return Ctx.IntTy; - case LengthModifier::AsLong: return ArgTypeResult::WIntTy; + case LengthModifier::AsLong: + return ArgTypeResult(ArgTypeResult::WIntTy, "wint_t"); default: return ArgTypeResult::Invalid(); } @@ -295,39 +260,50 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { if (CS.isIntArg()) switch (LM.getKind()) { case LengthModifier::AsLongDouble: - return ArgTypeResult::Invalid(); + // GNU extension. + return Ctx.LongLongTy; case LengthModifier::None: return Ctx.IntTy; - case LengthModifier::AsChar: return Ctx.SignedCharTy; + case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy; case LengthModifier::AsShort: return Ctx.ShortTy; case LengthModifier::AsLong: return Ctx.LongTy; - case LengthModifier::AsLongLong: return Ctx.LongLongTy; + case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: + return Ctx.LongLongTy; case LengthModifier::AsIntMax: - // FIXME: Return unknown for now. + return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t"); + case LengthModifier::AsSizeT: + // FIXME: How to get the corresponding signed version of size_t? return ArgTypeResult(); - case LengthModifier::AsSizeT: return Ctx.getSizeType(); - case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType(); + case LengthModifier::AsPtrDiff: + return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t"); + case LengthModifier::AsAllocate: + case LengthModifier::AsMAllocate: + return ArgTypeResult::Invalid(); } if (CS.isUIntArg()) switch (LM.getKind()) { case LengthModifier::AsLongDouble: - return ArgTypeResult::Invalid(); + // GNU extension. + return Ctx.UnsignedLongLongTy; case LengthModifier::None: return Ctx.UnsignedIntTy; case LengthModifier::AsChar: return Ctx.UnsignedCharTy; case LengthModifier::AsShort: return Ctx.UnsignedShortTy; case LengthModifier::AsLong: return Ctx.UnsignedLongTy; - case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy; + case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: + return Ctx.UnsignedLongLongTy; case LengthModifier::AsIntMax: - // FIXME: Return unknown for now. - return ArgTypeResult(); + return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t"); case LengthModifier::AsSizeT: - // FIXME: How to get the corresponding unsigned - // version of size_t? - return ArgTypeResult(); + return ArgTypeResult(Ctx.getSizeType(), "size_t"); case LengthModifier::AsPtrDiff: // FIXME: How to get the corresponding unsigned // version of ptrdiff_t? return ArgTypeResult(); + case LengthModifier::AsAllocate: + case LengthModifier::AsMAllocate: + return ArgTypeResult::Invalid(); } if (CS.isDoubleArg()) { @@ -338,15 +314,24 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { switch (CS.getKind()) { case ConversionSpecifier::sArg: - return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ? - ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy); + if (LM.getKind() == LengthModifier::AsWideChar) { + if (IsObjCLiteral) + return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()); + return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *"); + } + return ArgTypeResult::CStrTy; case ConversionSpecifier::SArg: - // FIXME: This appears to be Mac OS X specific. - return ArgTypeResult::WCStrTy; + if (IsObjCLiteral) + return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()); + return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *"); case ConversionSpecifier::CArg: - return Ctx.WCharTy; + if (IsObjCLiteral) + return Ctx.UnsignedShortTy; + return ArgTypeResult(Ctx.WCharTy, "wchar_t"); case ConversionSpecifier::pArg: return ArgTypeResult::CPointerTy; + case ConversionSpecifier::ObjCObjArg: + return ArgTypeResult::ObjCPointerTy; default: break; } @@ -355,7 +340,8 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { return ArgTypeResult(); } -bool PrintfSpecifier::fixType(QualType QT) { +bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, + ASTContext &Ctx, bool IsObjCLiteral) { // Handle strings first (char *, wchar_t *) if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { CS.setKind(ConversionSpecifier::sArg); @@ -367,16 +353,16 @@ bool PrintfSpecifier::fixType(QualType QT) { // Set the long length modifier for wide characters if (QT->getPointeeType()->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); + else + LM.setKind(LengthModifier::None); return true; } // We can only work with builtin types. - if (!QT->isBuiltinType()) - return false; - - // Everything else should be a base type const BuiltinType *BT = QT->getAs<BuiltinType>(); + if (!BT) + return false; // Set length modifier switch (BT->getKind()) { @@ -388,18 +374,15 @@ bool PrintfSpecifier::fixType(QualType QT) { case BuiltinType::UInt128: case BuiltinType::Int128: case BuiltinType::Half: - // Integral types which are non-trivial to correct. + // Various types which are non-trivial to correct. return false; - case BuiltinType::Void: - case BuiltinType::NullPtr: - case BuiltinType::ObjCId: - case BuiltinType::ObjCClass: - case BuiltinType::ObjCSel: - case BuiltinType::Dependent: - case BuiltinType::Overload: - case BuiltinType::BoundMember: - case BuiltinType::UnknownAny: +#define SIGNED_TYPE(Id, SingletonId) +#define UNSIGNED_TYPE(Id, SingletonId) +#define FLOATING_TYPE(Id, SingletonId) +#define BUILTIN_TYPE(Id, SingletonId) \ + case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" // Misc other stuff which doesn't make sense here. return false; @@ -437,6 +420,28 @@ bool PrintfSpecifier::fixType(QualType QT) { break; } + // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. + if (isa<TypedefType>(QT) && (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 fixing the length modifier was enough, we are done. + const analyze_printf::ArgTypeResult &ATR = getArgType(Ctx, IsObjCLiteral); + if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT)) + return true; + // Set conversion specifier and disable any flags which do not apply to it. // Let typedefs to char fall through to int, as %c is silly for uint8_t. if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) { @@ -456,9 +461,7 @@ bool PrintfSpecifier::fixType(QualType QT) { HasAlternativeForm = 0; } else if (QT->isUnsignedIntegerType()) { - // Preserve the original formatting, e.g. 'X', 'o'. - if (!cast<PrintfConversionSpecifier>(CS).isUIntArg()) - CS.setKind(ConversionSpecifier::uArg); + CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; } else { |