1212904Sdim//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// 2203955Srdivacky// 3203955Srdivacky// The LLVM Compiler Infrastructure 4203955Srdivacky// 5203955Srdivacky// This file is distributed under the University of Illinois Open Source 6203955Srdivacky// License. See LICENSE.TXT for details. 7203955Srdivacky// 8203955Srdivacky//===----------------------------------------------------------------------===// 9203955Srdivacky// 10203955Srdivacky// Handling of format string in printf and friends. The structure of format 11203955Srdivacky// strings for fprintf() are described in C99 7.19.6.1. 12203955Srdivacky// 13203955Srdivacky//===----------------------------------------------------------------------===// 14203955Srdivacky 15212904Sdim#include "clang/Analysis/Analyses/FormatString.h" 16249423Sdim#include "FormatStringParsing.h" 17243830Sdim#include "clang/Basic/TargetInfo.h" 18203955Srdivacky 19239462Sdimusing clang::analyze_format_string::ArgType; 20212904Sdimusing clang::analyze_format_string::FormatStringHandler; 21212904Sdimusing clang::analyze_format_string::LengthModifier; 22212904Sdimusing clang::analyze_format_string::OptionalAmount; 23212904Sdimusing clang::analyze_format_string::ConversionSpecifier; 24212904Sdimusing clang::analyze_printf::PrintfSpecifier; 25204643Srdivacky 26203955Srdivackyusing namespace clang; 27203955Srdivacky 28212904Sdimtypedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> 29212904Sdim PrintfSpecifierResult; 30203955Srdivacky 31203955Srdivacky//===----------------------------------------------------------------------===// 32203955Srdivacky// Methods for parsing format strings. 33203955Srdivacky//===----------------------------------------------------------------------===// 34203955Srdivacky 35212904Sdimusing analyze_format_string::ParseNonPositionAmount; 36203955Srdivacky 37212904Sdimstatic bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, 38204643Srdivacky const char *Start, const char *&Beg, const char *E, 39204643Srdivacky unsigned *argIndex) { 40204643Srdivacky if (argIndex) { 41204643Srdivacky FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); 42226633Sdim } else { 43204643Srdivacky const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, 44212904Sdim analyze_format_string::PrecisionPos); 45204643Srdivacky if (Amt.isInvalid()) 46204643Srdivacky return true; 47204643Srdivacky FS.setPrecision(Amt); 48204643Srdivacky } 49204643Srdivacky return false; 50204643Srdivacky} 51204643Srdivacky 52212904Sdimstatic PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, 53203955Srdivacky const char *&Beg, 54204643Srdivacky const char *E, 55208987Srdivacky unsigned &argIndex, 56243830Sdim const LangOptions &LO, 57243830Sdim const TargetInfo &Target) { 58203955Srdivacky 59212904Sdim using namespace clang::analyze_format_string; 60203955Srdivacky using namespace clang::analyze_printf; 61203955Srdivacky 62203955Srdivacky const char *I = Beg; 63203955Srdivacky const char *Start = 0; 64203955Srdivacky UpdateOnReturn <const char*> UpdateBeg(Beg, I); 65203955Srdivacky 66203955Srdivacky // Look for a '%' character that indicates the start of a format specifier. 67203955Srdivacky for ( ; I != E ; ++I) { 68203955Srdivacky char c = *I; 69203955Srdivacky if (c == '\0') { 70203955Srdivacky // Detect spurious null characters, which are likely errors. 71203955Srdivacky H.HandleNullChar(I); 72203955Srdivacky return true; 73203955Srdivacky } 74203955Srdivacky if (c == '%') { 75203955Srdivacky Start = I++; // Record the start of the format specifier. 76203955Srdivacky break; 77203955Srdivacky } 78203955Srdivacky } 79203955Srdivacky 80203955Srdivacky // No format specifier found? 81203955Srdivacky if (!Start) 82203955Srdivacky return false; 83203955Srdivacky 84203955Srdivacky if (I == E) { 85203955Srdivacky // No more characters left? 86212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 87203955Srdivacky return true; 88203955Srdivacky } 89203955Srdivacky 90212904Sdim PrintfSpecifier FS; 91204643Srdivacky if (ParseArgPosition(H, FS, Start, I, E)) 92204643Srdivacky return true; 93203955Srdivacky 94204643Srdivacky if (I == E) { 95204643Srdivacky // No more characters left? 96212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 97204643Srdivacky return true; 98204643Srdivacky } 99204643Srdivacky 100203955Srdivacky // Look for flags (if any). 101203955Srdivacky bool hasMore = true; 102203955Srdivacky for ( ; I != E; ++I) { 103203955Srdivacky switch (*I) { 104203955Srdivacky default: hasMore = false; break; 105218893Sdim case '\'': 106218893Sdim // FIXME: POSIX specific. Always accept? 107218893Sdim FS.setHasThousandsGrouping(I); 108218893Sdim break; 109210299Sed case '-': FS.setIsLeftJustified(I); break; 110210299Sed case '+': FS.setHasPlusPrefix(I); break; 111210299Sed case ' ': FS.setHasSpacePrefix(I); break; 112210299Sed case '#': FS.setHasAlternativeForm(I); break; 113210299Sed case '0': FS.setHasLeadingZeros(I); break; 114203955Srdivacky } 115203955Srdivacky if (!hasMore) 116203955Srdivacky break; 117203955Srdivacky } 118203955Srdivacky 119203955Srdivacky if (I == E) { 120203955Srdivacky // No more characters left? 121212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 122203955Srdivacky return true; 123203955Srdivacky } 124203955Srdivacky 125203955Srdivacky // Look for the field width (if any). 126204643Srdivacky if (ParseFieldWidth(H, FS, Start, I, E, 127204643Srdivacky FS.usesPositionalArg() ? 0 : &argIndex)) 128204643Srdivacky return true; 129203955Srdivacky 130203955Srdivacky if (I == E) { 131203955Srdivacky // No more characters left? 132212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 133203955Srdivacky return true; 134203955Srdivacky } 135203955Srdivacky 136203955Srdivacky // Look for the precision (if any). 137203955Srdivacky if (*I == '.') { 138203955Srdivacky ++I; 139203955Srdivacky if (I == E) { 140212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 141203955Srdivacky return true; 142203955Srdivacky } 143203955Srdivacky 144204643Srdivacky if (ParsePrecision(H, FS, Start, I, E, 145204643Srdivacky FS.usesPositionalArg() ? 0 : &argIndex)) 146204643Srdivacky return true; 147203955Srdivacky 148203955Srdivacky if (I == E) { 149203955Srdivacky // No more characters left? 150212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 151203955Srdivacky return true; 152203955Srdivacky } 153203955Srdivacky } 154203955Srdivacky 155203955Srdivacky // Look for the length modifier. 156234353Sdim if (ParseLengthModifier(FS, I, E, LO) && I == E) { 157203955Srdivacky // No more characters left? 158212904Sdim H.HandleIncompleteSpecifier(Start, E - Start); 159203955Srdivacky return true; 160203955Srdivacky } 161203955Srdivacky 162203955Srdivacky if (*I == '\0') { 163203955Srdivacky // Detect spurious null characters, which are likely errors. 164203955Srdivacky H.HandleNullChar(I); 165203955Srdivacky return true; 166203955Srdivacky } 167203955Srdivacky 168203955Srdivacky // Finally, look for the conversion specifier. 169203955Srdivacky const char *conversionPosition = I++; 170203955Srdivacky ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; 171203955Srdivacky switch (*conversionPosition) { 172203955Srdivacky default: 173203955Srdivacky break; 174203955Srdivacky // C99: 7.19.6.1 (section 8). 175204643Srdivacky case '%': k = ConversionSpecifier::PercentArg; break; 176204643Srdivacky case 'A': k = ConversionSpecifier::AArg; break; 177204643Srdivacky case 'E': k = ConversionSpecifier::EArg; break; 178204643Srdivacky case 'F': k = ConversionSpecifier::FArg; break; 179204643Srdivacky case 'G': k = ConversionSpecifier::GArg; break; 180204643Srdivacky case 'X': k = ConversionSpecifier::XArg; break; 181204643Srdivacky case 'a': k = ConversionSpecifier::aArg; break; 182212904Sdim case 'c': k = ConversionSpecifier::cArg; break; 183203955Srdivacky case 'd': k = ConversionSpecifier::dArg; break; 184204643Srdivacky case 'e': k = ConversionSpecifier::eArg; break; 185204643Srdivacky case 'f': k = ConversionSpecifier::fArg; break; 186204643Srdivacky case 'g': k = ConversionSpecifier::gArg; break; 187203955Srdivacky case 'i': k = ConversionSpecifier::iArg; break; 188212904Sdim case 'n': k = ConversionSpecifier::nArg; break; 189203955Srdivacky case 'o': k = ConversionSpecifier::oArg; break; 190263508Sdim case 'p': k = ConversionSpecifier::pArg; break; 191263508Sdim case 's': k = ConversionSpecifier::sArg; break; 192203955Srdivacky case 'u': k = ConversionSpecifier::uArg; break; 193203955Srdivacky case 'x': k = ConversionSpecifier::xArg; break; 194218893Sdim // POSIX specific. 195204643Srdivacky case 'C': k = ConversionSpecifier::CArg; break; 196212904Sdim case 'S': k = ConversionSpecifier::SArg; break; 197203955Srdivacky // Objective-C. 198203955Srdivacky case '@': k = ConversionSpecifier::ObjCObjArg; break; 199203955Srdivacky // Glibc specific. 200203955Srdivacky case 'm': k = ConversionSpecifier::PrintErrno; break; 201208987Srdivacky // FreeBSD format extensions 202243830Sdim case 'b': 203243830Sdim if (LO.FormatExtensions) 204243830Sdim k = ConversionSpecifier::FreeBSDbArg; // int followed by char * 205243830Sdim break; 206243830Sdim case 'r': 207243830Sdim if (LO.FormatExtensions) 208243830Sdim k = ConversionSpecifier::FreeBSDrArg; 209243830Sdim break; 210243830Sdim case 'y': 211243830Sdim if (LO.FormatExtensions) 212243830Sdim k = ConversionSpecifier::iArg; 213243830Sdim break; 214243830Sdim // Apple-specific 215243830Sdim case 'D': 216243830Sdim if (Target.getTriple().isOSDarwin()) 217243830Sdim k = ConversionSpecifier::DArg; 218243830Sdim else if (LO.FormatExtensions) 219243830Sdim k = ConversionSpecifier::FreeBSDDArg; // u_char * followed by char * 220243830Sdim break; 221243830Sdim case 'O': 222243830Sdim if (Target.getTriple().isOSDarwin()) 223243830Sdim k = ConversionSpecifier::OArg; 224243830Sdim break; 225243830Sdim case 'U': 226243830Sdim if (Target.getTriple().isOSDarwin()) 227243830Sdim k = ConversionSpecifier::UArg; 228243830Sdim break; 229203955Srdivacky } 230212904Sdim PrintfConversionSpecifier CS(conversionPosition, k); 231204643Srdivacky FS.setConversionSpecifier(CS); 232204643Srdivacky if (CS.consumesDataArgument() && !FS.usesPositionalArg()) 233204643Srdivacky FS.setArgIndex(argIndex++); 234208987Srdivacky // FreeBSD extension 235243830Sdim if (k == ConversionSpecifier::FreeBSDbArg || 236243830Sdim k == ConversionSpecifier::FreeBSDDArg) 237208987Srdivacky argIndex++; 238203955Srdivacky 239203955Srdivacky if (k == ConversionSpecifier::InvalidSpecifier) { 240204643Srdivacky // Assume the conversion takes one argument. 241218893Sdim return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start); 242203955Srdivacky } 243212904Sdim return PrintfSpecifierResult(Start, FS); 244203955Srdivacky} 245203955Srdivacky 246212904Sdimbool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, 247212904Sdim const char *I, 248212904Sdim const char *E, 249243830Sdim const LangOptions &LO, 250243830Sdim const TargetInfo &Target) { 251204643Srdivacky 252204643Srdivacky unsigned argIndex = 0; 253204643Srdivacky 254203955Srdivacky // Keep looking for a format specifier until we have exhausted the string. 255203955Srdivacky while (I != E) { 256212904Sdim const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 257243830Sdim LO, Target); 258203955Srdivacky // Did a fail-stop error of any kind occur when parsing the specifier? 259203955Srdivacky // If so, don't do any more processing. 260203955Srdivacky if (FSR.shouldStop()) 261243830Sdim return true; 262203955Srdivacky // Did we exhaust the string or encounter an error that 263203955Srdivacky // we can recover from? 264203955Srdivacky if (!FSR.hasValue()) 265203955Srdivacky continue; 266203955Srdivacky // We have a format specifier. Pass it to the callback. 267212904Sdim if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), 268203955Srdivacky I - FSR.getStart())) 269203955Srdivacky return true; 270203955Srdivacky } 271203955Srdivacky assert(I == E && "Format string not exhausted"); 272203955Srdivacky return false; 273203955Srdivacky} 274203955Srdivacky 275203955Srdivacky//===----------------------------------------------------------------------===// 276212904Sdim// Methods on PrintfSpecifier. 277210299Sed//===----------------------------------------------------------------------===// 278210299Sed 279239462SdimArgType PrintfSpecifier::getArgType(ASTContext &Ctx, 280239462Sdim bool IsObjCLiteral) const { 281212904Sdim const PrintfConversionSpecifier &CS = getConversionSpecifier(); 282218893Sdim 283203955Srdivacky if (!CS.consumesDataArgument()) 284239462Sdim return ArgType::Invalid(); 285203955Srdivacky 286212904Sdim if (CS.getKind() == ConversionSpecifier::cArg) 287212904Sdim switch (LM.getKind()) { 288212904Sdim case LengthModifier::None: return Ctx.IntTy; 289234353Sdim case LengthModifier::AsLong: 290239462Sdim return ArgType(ArgType::WIntTy, "wint_t"); 291212904Sdim default: 292239462Sdim return ArgType::Invalid(); 293212904Sdim } 294218893Sdim 295203955Srdivacky if (CS.isIntArg()) 296210299Sed switch (LM.getKind()) { 297210299Sed case LengthModifier::AsLongDouble: 298234353Sdim // GNU extension. 299234353Sdim return Ctx.LongLongTy; 300263508Sdim case LengthModifier::None: 301263508Sdim return Ctx.IntTy; 302263508Sdim case LengthModifier::AsInt32: 303263508Sdim return ArgType(Ctx.IntTy, "__int32"); 304239462Sdim case LengthModifier::AsChar: return ArgType::AnyCharTy; 305210299Sed case LengthModifier::AsShort: return Ctx.ShortTy; 306210299Sed case LengthModifier::AsLong: return Ctx.LongTy; 307234353Sdim case LengthModifier::AsLongLong: 308234353Sdim case LengthModifier::AsQuad: 309234353Sdim return Ctx.LongLongTy; 310263508Sdim case LengthModifier::AsInt64: 311263508Sdim return ArgType(Ctx.LongLongTy, "__int64"); 312210299Sed case LengthModifier::AsIntMax: 313239462Sdim return ArgType(Ctx.getIntMaxType(), "intmax_t"); 314234353Sdim case LengthModifier::AsSizeT: 315234353Sdim // FIXME: How to get the corresponding signed version of size_t? 316239462Sdim return ArgType(); 317263508Sdim case LengthModifier::AsInt3264: 318263508Sdim return Ctx.getTargetInfo().getTriple().isArch64Bit() 319263508Sdim ? ArgType(Ctx.LongLongTy, "__int64") 320263508Sdim : ArgType(Ctx.IntTy, "__int32"); 321234353Sdim case LengthModifier::AsPtrDiff: 322239462Sdim return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"); 323234353Sdim case LengthModifier::AsAllocate: 324234353Sdim case LengthModifier::AsMAllocate: 325239462Sdim return ArgType::Invalid(); 326203955Srdivacky } 327203955Srdivacky 328203955Srdivacky if (CS.isUIntArg()) 329210299Sed switch (LM.getKind()) { 330210299Sed case LengthModifier::AsLongDouble: 331234353Sdim // GNU extension. 332234353Sdim return Ctx.UnsignedLongLongTy; 333263508Sdim case LengthModifier::None: 334263508Sdim return Ctx.UnsignedIntTy; 335263508Sdim case LengthModifier::AsInt32: 336263508Sdim return ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); 337210299Sed case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 338210299Sed case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 339210299Sed case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 340234353Sdim case LengthModifier::AsLongLong: 341234353Sdim case LengthModifier::AsQuad: 342234353Sdim return Ctx.UnsignedLongLongTy; 343263508Sdim case LengthModifier::AsInt64: 344263508Sdim return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"); 345210299Sed case LengthModifier::AsIntMax: 346239462Sdim return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); 347210299Sed case LengthModifier::AsSizeT: 348239462Sdim return ArgType(Ctx.getSizeType(), "size_t"); 349263508Sdim case LengthModifier::AsInt3264: 350263508Sdim return Ctx.getTargetInfo().getTriple().isArch64Bit() 351263508Sdim ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") 352263508Sdim : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); 353210299Sed case LengthModifier::AsPtrDiff: 354203955Srdivacky // FIXME: How to get the corresponding unsigned 355203955Srdivacky // version of ptrdiff_t? 356239462Sdim return ArgType(); 357234353Sdim case LengthModifier::AsAllocate: 358234353Sdim case LengthModifier::AsMAllocate: 359239462Sdim return ArgType::Invalid(); 360203955Srdivacky } 361203955Srdivacky 362203955Srdivacky if (CS.isDoubleArg()) { 363210299Sed if (LM.getKind() == LengthModifier::AsLongDouble) 364203955Srdivacky return Ctx.LongDoubleTy; 365203955Srdivacky return Ctx.DoubleTy; 366203955Srdivacky } 367203955Srdivacky 368239462Sdim if (CS.getKind() == ConversionSpecifier::nArg) { 369239462Sdim switch (LM.getKind()) { 370239462Sdim case LengthModifier::None: 371239462Sdim return ArgType::PtrTo(Ctx.IntTy); 372239462Sdim case LengthModifier::AsChar: 373239462Sdim return ArgType::PtrTo(Ctx.SignedCharTy); 374239462Sdim case LengthModifier::AsShort: 375239462Sdim return ArgType::PtrTo(Ctx.ShortTy); 376239462Sdim case LengthModifier::AsLong: 377239462Sdim return ArgType::PtrTo(Ctx.LongTy); 378239462Sdim case LengthModifier::AsLongLong: 379239462Sdim case LengthModifier::AsQuad: 380239462Sdim return ArgType::PtrTo(Ctx.LongLongTy); 381239462Sdim case LengthModifier::AsIntMax: 382239462Sdim return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); 383239462Sdim case LengthModifier::AsSizeT: 384239462Sdim return ArgType(); // FIXME: ssize_t 385239462Sdim case LengthModifier::AsPtrDiff: 386239462Sdim return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 387239462Sdim case LengthModifier::AsLongDouble: 388239462Sdim return ArgType(); // FIXME: Is this a known extension? 389239462Sdim case LengthModifier::AsAllocate: 390239462Sdim case LengthModifier::AsMAllocate: 391263508Sdim case LengthModifier::AsInt32: 392263508Sdim case LengthModifier::AsInt3264: 393263508Sdim case LengthModifier::AsInt64: 394239462Sdim return ArgType::Invalid(); 395239462Sdim } 396239462Sdim } 397239462Sdim 398204643Srdivacky switch (CS.getKind()) { 399212904Sdim case ConversionSpecifier::sArg: 400234353Sdim if (LM.getKind() == LengthModifier::AsWideChar) { 401234353Sdim if (IsObjCLiteral) 402249423Sdim return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 403249423Sdim "const unichar *"); 404239462Sdim return ArgType(ArgType::WCStrTy, "wchar_t *"); 405234353Sdim } 406239462Sdim return ArgType::CStrTy; 407212904Sdim case ConversionSpecifier::SArg: 408234353Sdim if (IsObjCLiteral) 409249423Sdim return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 410249423Sdim "const unichar *"); 411239462Sdim return ArgType(ArgType::WCStrTy, "wchar_t *"); 412204643Srdivacky case ConversionSpecifier::CArg: 413234353Sdim if (IsObjCLiteral) 414249423Sdim return ArgType(Ctx.UnsignedShortTy, "unichar"); 415263508Sdim return ArgType(Ctx.WideCharTy, "wchar_t"); 416212904Sdim case ConversionSpecifier::pArg: 417239462Sdim return ArgType::CPointerTy; 418234353Sdim case ConversionSpecifier::ObjCObjArg: 419239462Sdim return ArgType::ObjCPointerTy; 420204643Srdivacky default: 421204643Srdivacky break; 422204643Srdivacky } 423203955Srdivacky 424203955Srdivacky // FIXME: Handle other cases. 425239462Sdim return ArgType(); 426203955Srdivacky} 427203955Srdivacky 428234353Sdimbool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, 429234353Sdim ASTContext &Ctx, bool IsObjCLiteral) { 430239462Sdim // %n is different from other conversion specifiers; don't try to fix it. 431239462Sdim if (CS.getKind() == ConversionSpecifier::nArg) 432239462Sdim return false; 433239462Sdim 434239462Sdim // Handle Objective-C objects first. Note that while the '%@' specifier will 435239462Sdim // not warn for structure pointer or void pointer arguments (because that's 436239462Sdim // how CoreFoundation objects are implemented), we only show a fixit for '%@' 437239462Sdim // if we know it's an object (block, id, class, or __attribute__((NSObject))). 438239462Sdim if (QT->isObjCRetainableType()) { 439239462Sdim if (!IsObjCLiteral) 440239462Sdim return false; 441239462Sdim 442239462Sdim CS.setKind(ConversionSpecifier::ObjCObjArg); 443239462Sdim 444239462Sdim // Disable irrelevant flags 445239462Sdim HasThousandsGrouping = false; 446239462Sdim HasPlusPrefix = false; 447239462Sdim HasSpacePrefix = false; 448239462Sdim HasAlternativeForm = false; 449239462Sdim HasLeadingZeroes = false; 450239462Sdim Precision.setHowSpecified(OptionalAmount::NotSpecified); 451239462Sdim LM.setKind(LengthModifier::None); 452239462Sdim 453239462Sdim return true; 454239462Sdim } 455239462Sdim 456239462Sdim // Handle strings next (char *, wchar_t *) 457210299Sed if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 458212904Sdim CS.setKind(ConversionSpecifier::sArg); 459210299Sed 460210299Sed // Disable irrelevant flags 461210299Sed HasAlternativeForm = 0; 462210299Sed HasLeadingZeroes = 0; 463210299Sed 464210299Sed // Set the long length modifier for wide characters 465210299Sed if (QT->getPointeeType()->isWideCharType()) 466210299Sed LM.setKind(LengthModifier::AsWideChar); 467234353Sdim else 468234353Sdim LM.setKind(LengthModifier::None); 469210299Sed 470210299Sed return true; 471210299Sed } 472210299Sed 473239462Sdim // If it's an enum, get its underlying type. 474239462Sdim if (const EnumType *ETy = QT->getAs<EnumType>()) 475239462Sdim QT = ETy->getDecl()->getIntegerType(); 476239462Sdim 477210299Sed // We can only work with builtin types. 478234353Sdim const BuiltinType *BT = QT->getAs<BuiltinType>(); 479234353Sdim if (!BT) 480210299Sed return false; 481210299Sed 482210299Sed // Set length modifier 483210299Sed switch (BT->getKind()) { 484221345Sdim case BuiltinType::Bool: 485221345Sdim case BuiltinType::WChar_U: 486221345Sdim case BuiltinType::WChar_S: 487221345Sdim case BuiltinType::Char16: 488221345Sdim case BuiltinType::Char32: 489221345Sdim case BuiltinType::UInt128: 490221345Sdim case BuiltinType::Int128: 491226633Sdim case BuiltinType::Half: 492234353Sdim // Various types which are non-trivial to correct. 493221345Sdim return false; 494221345Sdim 495234353Sdim#define SIGNED_TYPE(Id, SingletonId) 496234353Sdim#define UNSIGNED_TYPE(Id, SingletonId) 497234353Sdim#define FLOATING_TYPE(Id, SingletonId) 498234353Sdim#define BUILTIN_TYPE(Id, SingletonId) \ 499234353Sdim case BuiltinType::Id: 500234353Sdim#include "clang/AST/BuiltinTypes.def" 501221345Sdim // Misc other stuff which doesn't make sense here. 502221345Sdim return false; 503221345Sdim 504221345Sdim case BuiltinType::UInt: 505221345Sdim case BuiltinType::Int: 506221345Sdim case BuiltinType::Float: 507221345Sdim case BuiltinType::Double: 508210299Sed LM.setKind(LengthModifier::None); 509210299Sed break; 510210299Sed 511218893Sdim case BuiltinType::Char_U: 512218893Sdim case BuiltinType::UChar: 513218893Sdim case BuiltinType::Char_S: 514218893Sdim case BuiltinType::SChar: 515218893Sdim LM.setKind(LengthModifier::AsChar); 516218893Sdim break; 517218893Sdim 518218893Sdim case BuiltinType::Short: 519218893Sdim case BuiltinType::UShort: 520218893Sdim LM.setKind(LengthModifier::AsShort); 521218893Sdim break; 522218893Sdim 523210299Sed case BuiltinType::Long: 524210299Sed case BuiltinType::ULong: 525210299Sed LM.setKind(LengthModifier::AsLong); 526210299Sed break; 527210299Sed 528210299Sed case BuiltinType::LongLong: 529210299Sed case BuiltinType::ULongLong: 530210299Sed LM.setKind(LengthModifier::AsLongLong); 531210299Sed break; 532210299Sed 533210299Sed case BuiltinType::LongDouble: 534210299Sed LM.setKind(LengthModifier::AsLongDouble); 535210299Sed break; 536210299Sed } 537210299Sed 538234353Sdim // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. 539249423Sdim if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11)) 540239462Sdim namedTypeToLengthModifier(QT, LM); 541234353Sdim 542249423Sdim // If fixing the length modifier was enough, we might be done. 543243830Sdim if (hasValidLengthModifier(Ctx.getTargetInfo())) { 544249423Sdim // If we're going to offer a fix anyway, make sure the sign matches. 545249423Sdim switch (CS.getKind()) { 546249423Sdim case ConversionSpecifier::uArg: 547249423Sdim case ConversionSpecifier::UArg: 548249423Sdim if (QT->isSignedIntegerType()) 549249423Sdim CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); 550249423Sdim break; 551249423Sdim case ConversionSpecifier::dArg: 552249423Sdim case ConversionSpecifier::DArg: 553249423Sdim case ConversionSpecifier::iArg: 554249423Sdim if (QT->isUnsignedIntegerType() && !HasPlusPrefix) 555249423Sdim CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); 556249423Sdim break; 557249423Sdim default: 558249423Sdim // Other specifiers do not have signed/unsigned variants. 559249423Sdim break; 560249423Sdim } 561249423Sdim 562243830Sdim const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); 563243830Sdim if (ATR.isValid() && ATR.matchesType(Ctx, QT)) 564243830Sdim return true; 565243830Sdim } 566234353Sdim 567210299Sed // Set conversion specifier and disable any flags which do not apply to it. 568218893Sdim // Let typedefs to char fall through to int, as %c is silly for uint8_t. 569249423Sdim if (!isa<TypedefType>(QT) && QT->isCharType()) { 570212904Sdim CS.setKind(ConversionSpecifier::cArg); 571218893Sdim LM.setKind(LengthModifier::None); 572210299Sed Precision.setHowSpecified(OptionalAmount::NotSpecified); 573210299Sed HasAlternativeForm = 0; 574210299Sed HasLeadingZeroes = 0; 575210299Sed HasPlusPrefix = 0; 576210299Sed } 577210299Sed // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 578210299Sed else if (QT->isRealFloatingType()) { 579210299Sed CS.setKind(ConversionSpecifier::fArg); 580210299Sed } 581210299Sed else if (QT->isSignedIntegerType()) { 582210299Sed CS.setKind(ConversionSpecifier::dArg); 583210299Sed HasAlternativeForm = 0; 584210299Sed } 585210299Sed else if (QT->isUnsignedIntegerType()) { 586234353Sdim CS.setKind(ConversionSpecifier::uArg); 587210299Sed HasAlternativeForm = 0; 588210299Sed HasPlusPrefix = 0; 589226633Sdim } else { 590226633Sdim llvm_unreachable("Unexpected type"); 591210299Sed } 592210299Sed 593210299Sed return true; 594210299Sed} 595210299Sed 596226633Sdimvoid PrintfSpecifier::toString(raw_ostream &os) const { 597210299Sed // Whilst some features have no defined order, we are using the order 598218893Sdim // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) 599210299Sed os << "%"; 600210299Sed 601210299Sed // Positional args 602210299Sed if (usesPositionalArg()) { 603210299Sed os << getPositionalArgIndex() << "$"; 604210299Sed } 605210299Sed 606210299Sed // Conversion flags 607210299Sed if (IsLeftJustified) os << "-"; 608210299Sed if (HasPlusPrefix) os << "+"; 609210299Sed if (HasSpacePrefix) os << " "; 610210299Sed if (HasAlternativeForm) os << "#"; 611210299Sed if (HasLeadingZeroes) os << "0"; 612210299Sed 613210299Sed // Minimum field width 614210299Sed FieldWidth.toString(os); 615210299Sed // Precision 616210299Sed Precision.toString(os); 617210299Sed // Length modifier 618210299Sed os << LM.toString(); 619210299Sed // Conversion specifier 620210299Sed os << CS.toString(); 621210299Sed} 622210299Sed 623212904Sdimbool PrintfSpecifier::hasValidPlusPrefix() const { 624210299Sed if (!HasPlusPrefix) 625210299Sed return true; 626210299Sed 627210299Sed // The plus prefix only makes sense for signed conversions 628210299Sed switch (CS.getKind()) { 629210299Sed case ConversionSpecifier::dArg: 630243830Sdim case ConversionSpecifier::DArg: 631210299Sed case ConversionSpecifier::iArg: 632210299Sed case ConversionSpecifier::fArg: 633210299Sed case ConversionSpecifier::FArg: 634210299Sed case ConversionSpecifier::eArg: 635210299Sed case ConversionSpecifier::EArg: 636210299Sed case ConversionSpecifier::gArg: 637210299Sed case ConversionSpecifier::GArg: 638210299Sed case ConversionSpecifier::aArg: 639210299Sed case ConversionSpecifier::AArg: 640243830Sdim case ConversionSpecifier::FreeBSDrArg: 641210299Sed return true; 642210299Sed 643210299Sed default: 644210299Sed return false; 645210299Sed } 646210299Sed} 647210299Sed 648212904Sdimbool PrintfSpecifier::hasValidAlternativeForm() const { 649210299Sed if (!HasAlternativeForm) 650210299Sed return true; 651210299Sed 652218893Sdim // Alternate form flag only valid with the oxXaAeEfFgG conversions 653210299Sed switch (CS.getKind()) { 654210299Sed case ConversionSpecifier::oArg: 655243830Sdim case ConversionSpecifier::OArg: 656210299Sed case ConversionSpecifier::xArg: 657218893Sdim case ConversionSpecifier::XArg: 658210299Sed case ConversionSpecifier::aArg: 659210299Sed case ConversionSpecifier::AArg: 660210299Sed case ConversionSpecifier::eArg: 661210299Sed case ConversionSpecifier::EArg: 662210299Sed case ConversionSpecifier::fArg: 663210299Sed case ConversionSpecifier::FArg: 664210299Sed case ConversionSpecifier::gArg: 665210299Sed case ConversionSpecifier::GArg: 666243830Sdim case ConversionSpecifier::FreeBSDrArg: 667210299Sed return true; 668210299Sed 669210299Sed default: 670210299Sed return false; 671210299Sed } 672210299Sed} 673210299Sed 674212904Sdimbool PrintfSpecifier::hasValidLeadingZeros() const { 675210299Sed if (!HasLeadingZeroes) 676210299Sed return true; 677210299Sed 678210299Sed // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions 679210299Sed switch (CS.getKind()) { 680210299Sed case ConversionSpecifier::dArg: 681243830Sdim case ConversionSpecifier::DArg: 682210299Sed case ConversionSpecifier::iArg: 683210299Sed case ConversionSpecifier::oArg: 684243830Sdim case ConversionSpecifier::OArg: 685210299Sed case ConversionSpecifier::uArg: 686243830Sdim case ConversionSpecifier::UArg: 687210299Sed case ConversionSpecifier::xArg: 688210299Sed case ConversionSpecifier::XArg: 689210299Sed case ConversionSpecifier::aArg: 690210299Sed case ConversionSpecifier::AArg: 691210299Sed case ConversionSpecifier::eArg: 692210299Sed case ConversionSpecifier::EArg: 693210299Sed case ConversionSpecifier::fArg: 694210299Sed case ConversionSpecifier::FArg: 695210299Sed case ConversionSpecifier::gArg: 696210299Sed case ConversionSpecifier::GArg: 697210299Sed return true; 698210299Sed 699210299Sed default: 700210299Sed return false; 701210299Sed } 702210299Sed} 703210299Sed 704212904Sdimbool PrintfSpecifier::hasValidSpacePrefix() const { 705210299Sed if (!HasSpacePrefix) 706210299Sed return true; 707210299Sed 708210299Sed // The space prefix only makes sense for signed conversions 709210299Sed switch (CS.getKind()) { 710210299Sed case ConversionSpecifier::dArg: 711243830Sdim case ConversionSpecifier::DArg: 712210299Sed case ConversionSpecifier::iArg: 713210299Sed case ConversionSpecifier::fArg: 714210299Sed case ConversionSpecifier::FArg: 715210299Sed case ConversionSpecifier::eArg: 716210299Sed case ConversionSpecifier::EArg: 717210299Sed case ConversionSpecifier::gArg: 718210299Sed case ConversionSpecifier::GArg: 719210299Sed case ConversionSpecifier::aArg: 720210299Sed case ConversionSpecifier::AArg: 721210299Sed return true; 722210299Sed 723210299Sed default: 724210299Sed return false; 725210299Sed } 726210299Sed} 727210299Sed 728212904Sdimbool PrintfSpecifier::hasValidLeftJustified() const { 729210299Sed if (!IsLeftJustified) 730210299Sed return true; 731210299Sed 732210299Sed // The left justified flag is valid for all conversions except n 733210299Sed switch (CS.getKind()) { 734212904Sdim case ConversionSpecifier::nArg: 735210299Sed return false; 736210299Sed 737210299Sed default: 738210299Sed return true; 739210299Sed } 740210299Sed} 741210299Sed 742218893Sdimbool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { 743218893Sdim if (!HasThousandsGrouping) 744218893Sdim return true; 745218893Sdim 746218893Sdim switch (CS.getKind()) { 747218893Sdim case ConversionSpecifier::dArg: 748243830Sdim case ConversionSpecifier::DArg: 749218893Sdim case ConversionSpecifier::iArg: 750218893Sdim case ConversionSpecifier::uArg: 751243830Sdim case ConversionSpecifier::UArg: 752218893Sdim case ConversionSpecifier::fArg: 753218893Sdim case ConversionSpecifier::FArg: 754218893Sdim case ConversionSpecifier::gArg: 755218893Sdim case ConversionSpecifier::GArg: 756218893Sdim return true; 757218893Sdim default: 758218893Sdim return false; 759218893Sdim } 760218893Sdim} 761218893Sdim 762212904Sdimbool PrintfSpecifier::hasValidPrecision() const { 763210299Sed if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) 764210299Sed return true; 765210299Sed 766210299Sed // Precision is only valid with the diouxXaAeEfFgGs conversions 767210299Sed switch (CS.getKind()) { 768210299Sed case ConversionSpecifier::dArg: 769243830Sdim case ConversionSpecifier::DArg: 770210299Sed case ConversionSpecifier::iArg: 771210299Sed case ConversionSpecifier::oArg: 772243830Sdim case ConversionSpecifier::OArg: 773210299Sed case ConversionSpecifier::uArg: 774243830Sdim case ConversionSpecifier::UArg: 775210299Sed case ConversionSpecifier::xArg: 776210299Sed case ConversionSpecifier::XArg: 777210299Sed case ConversionSpecifier::aArg: 778210299Sed case ConversionSpecifier::AArg: 779210299Sed case ConversionSpecifier::eArg: 780210299Sed case ConversionSpecifier::EArg: 781210299Sed case ConversionSpecifier::fArg: 782210299Sed case ConversionSpecifier::FArg: 783210299Sed case ConversionSpecifier::gArg: 784210299Sed case ConversionSpecifier::GArg: 785212904Sdim case ConversionSpecifier::sArg: 786210299Sed return true; 787210299Sed 788210299Sed default: 789210299Sed return false; 790210299Sed } 791210299Sed} 792212904Sdimbool PrintfSpecifier::hasValidFieldWidth() const { 793210299Sed if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) 794210299Sed return true; 795210299Sed 796210299Sed // The field width is valid for all conversions except n 797210299Sed switch (CS.getKind()) { 798212904Sdim case ConversionSpecifier::nArg: 799210299Sed return false; 800210299Sed 801210299Sed default: 802210299Sed return true; 803210299Sed } 804210299Sed} 805