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; 190212904Sdim case 'p': k = ConversionSpecifier::pArg; break; 191212904Sdim 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; 300210299Sed case LengthModifier::None: return Ctx.IntTy; 301239462Sdim case LengthModifier::AsChar: return ArgType::AnyCharTy; 302210299Sed case LengthModifier::AsShort: return Ctx.ShortTy; 303210299Sed case LengthModifier::AsLong: return Ctx.LongTy; 304234353Sdim case LengthModifier::AsLongLong: 305234353Sdim case LengthModifier::AsQuad: 306234353Sdim return Ctx.LongLongTy; 307210299Sed case LengthModifier::AsIntMax: 308239462Sdim return ArgType(Ctx.getIntMaxType(), "intmax_t"); 309234353Sdim case LengthModifier::AsSizeT: 310234353Sdim // FIXME: How to get the corresponding signed version of size_t? 311239462Sdim return ArgType(); 312234353Sdim case LengthModifier::AsPtrDiff: 313239462Sdim return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"); 314234353Sdim case LengthModifier::AsAllocate: 315234353Sdim case LengthModifier::AsMAllocate: 316239462Sdim return ArgType::Invalid(); 317203955Srdivacky } 318203955Srdivacky 319203955Srdivacky if (CS.isUIntArg()) 320210299Sed switch (LM.getKind()) { 321210299Sed case LengthModifier::AsLongDouble: 322234353Sdim // GNU extension. 323234353Sdim return Ctx.UnsignedLongLongTy; 324210299Sed case LengthModifier::None: return Ctx.UnsignedIntTy; 325210299Sed case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 326210299Sed case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 327210299Sed case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 328234353Sdim case LengthModifier::AsLongLong: 329234353Sdim case LengthModifier::AsQuad: 330234353Sdim return Ctx.UnsignedLongLongTy; 331210299Sed case LengthModifier::AsIntMax: 332239462Sdim return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); 333210299Sed case LengthModifier::AsSizeT: 334239462Sdim return ArgType(Ctx.getSizeType(), "size_t"); 335210299Sed case LengthModifier::AsPtrDiff: 336203955Srdivacky // FIXME: How to get the corresponding unsigned 337203955Srdivacky // version of ptrdiff_t? 338239462Sdim return ArgType(); 339234353Sdim case LengthModifier::AsAllocate: 340234353Sdim case LengthModifier::AsMAllocate: 341239462Sdim return ArgType::Invalid(); 342203955Srdivacky } 343203955Srdivacky 344203955Srdivacky if (CS.isDoubleArg()) { 345210299Sed if (LM.getKind() == LengthModifier::AsLongDouble) 346203955Srdivacky return Ctx.LongDoubleTy; 347203955Srdivacky return Ctx.DoubleTy; 348203955Srdivacky } 349203955Srdivacky 350239462Sdim if (CS.getKind() == ConversionSpecifier::nArg) { 351239462Sdim switch (LM.getKind()) { 352239462Sdim case LengthModifier::None: 353239462Sdim return ArgType::PtrTo(Ctx.IntTy); 354239462Sdim case LengthModifier::AsChar: 355239462Sdim return ArgType::PtrTo(Ctx.SignedCharTy); 356239462Sdim case LengthModifier::AsShort: 357239462Sdim return ArgType::PtrTo(Ctx.ShortTy); 358239462Sdim case LengthModifier::AsLong: 359239462Sdim return ArgType::PtrTo(Ctx.LongTy); 360239462Sdim case LengthModifier::AsLongLong: 361239462Sdim case LengthModifier::AsQuad: 362239462Sdim return ArgType::PtrTo(Ctx.LongLongTy); 363239462Sdim case LengthModifier::AsIntMax: 364239462Sdim return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); 365239462Sdim case LengthModifier::AsSizeT: 366239462Sdim return ArgType(); // FIXME: ssize_t 367239462Sdim case LengthModifier::AsPtrDiff: 368239462Sdim return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 369239462Sdim case LengthModifier::AsLongDouble: 370239462Sdim return ArgType(); // FIXME: Is this a known extension? 371239462Sdim case LengthModifier::AsAllocate: 372239462Sdim case LengthModifier::AsMAllocate: 373239462Sdim return ArgType::Invalid(); 374239462Sdim } 375239462Sdim } 376239462Sdim 377204643Srdivacky switch (CS.getKind()) { 378212904Sdim case ConversionSpecifier::sArg: 379234353Sdim if (LM.getKind() == LengthModifier::AsWideChar) { 380234353Sdim if (IsObjCLiteral) 381249423Sdim return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 382249423Sdim "const unichar *"); 383239462Sdim return ArgType(ArgType::WCStrTy, "wchar_t *"); 384234353Sdim } 385239462Sdim return ArgType::CStrTy; 386212904Sdim case ConversionSpecifier::SArg: 387234353Sdim if (IsObjCLiteral) 388249423Sdim return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 389249423Sdim "const unichar *"); 390239462Sdim return ArgType(ArgType::WCStrTy, "wchar_t *"); 391204643Srdivacky case ConversionSpecifier::CArg: 392234353Sdim if (IsObjCLiteral) 393249423Sdim return ArgType(Ctx.UnsignedShortTy, "unichar"); 394239462Sdim return ArgType(Ctx.WCharTy, "wchar_t"); 395212904Sdim case ConversionSpecifier::pArg: 396239462Sdim return ArgType::CPointerTy; 397234353Sdim case ConversionSpecifier::ObjCObjArg: 398239462Sdim return ArgType::ObjCPointerTy; 399204643Srdivacky default: 400204643Srdivacky break; 401204643Srdivacky } 402203955Srdivacky 403203955Srdivacky // FIXME: Handle other cases. 404239462Sdim return ArgType(); 405203955Srdivacky} 406203955Srdivacky 407234353Sdimbool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, 408234353Sdim ASTContext &Ctx, bool IsObjCLiteral) { 409239462Sdim // %n is different from other conversion specifiers; don't try to fix it. 410239462Sdim if (CS.getKind() == ConversionSpecifier::nArg) 411239462Sdim return false; 412239462Sdim 413239462Sdim // Handle Objective-C objects first. Note that while the '%@' specifier will 414239462Sdim // not warn for structure pointer or void pointer arguments (because that's 415239462Sdim // how CoreFoundation objects are implemented), we only show a fixit for '%@' 416239462Sdim // if we know it's an object (block, id, class, or __attribute__((NSObject))). 417239462Sdim if (QT->isObjCRetainableType()) { 418239462Sdim if (!IsObjCLiteral) 419239462Sdim return false; 420239462Sdim 421239462Sdim CS.setKind(ConversionSpecifier::ObjCObjArg); 422239462Sdim 423239462Sdim // Disable irrelevant flags 424239462Sdim HasThousandsGrouping = false; 425239462Sdim HasPlusPrefix = false; 426239462Sdim HasSpacePrefix = false; 427239462Sdim HasAlternativeForm = false; 428239462Sdim HasLeadingZeroes = false; 429239462Sdim Precision.setHowSpecified(OptionalAmount::NotSpecified); 430239462Sdim LM.setKind(LengthModifier::None); 431239462Sdim 432239462Sdim return true; 433239462Sdim } 434239462Sdim 435239462Sdim // Handle strings next (char *, wchar_t *) 436210299Sed if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 437212904Sdim CS.setKind(ConversionSpecifier::sArg); 438210299Sed 439210299Sed // Disable irrelevant flags 440210299Sed HasAlternativeForm = 0; 441210299Sed HasLeadingZeroes = 0; 442210299Sed 443210299Sed // Set the long length modifier for wide characters 444210299Sed if (QT->getPointeeType()->isWideCharType()) 445210299Sed LM.setKind(LengthModifier::AsWideChar); 446234353Sdim else 447234353Sdim LM.setKind(LengthModifier::None); 448210299Sed 449210299Sed return true; 450210299Sed } 451210299Sed 452239462Sdim // If it's an enum, get its underlying type. 453239462Sdim if (const EnumType *ETy = QT->getAs<EnumType>()) 454239462Sdim QT = ETy->getDecl()->getIntegerType(); 455239462Sdim 456210299Sed // We can only work with builtin types. 457234353Sdim const BuiltinType *BT = QT->getAs<BuiltinType>(); 458234353Sdim if (!BT) 459210299Sed return false; 460210299Sed 461210299Sed // Set length modifier 462210299Sed switch (BT->getKind()) { 463221345Sdim case BuiltinType::Bool: 464221345Sdim case BuiltinType::WChar_U: 465221345Sdim case BuiltinType::WChar_S: 466221345Sdim case BuiltinType::Char16: 467221345Sdim case BuiltinType::Char32: 468221345Sdim case BuiltinType::UInt128: 469221345Sdim case BuiltinType::Int128: 470226633Sdim case BuiltinType::Half: 471234353Sdim // Various types which are non-trivial to correct. 472221345Sdim return false; 473221345Sdim 474234353Sdim#define SIGNED_TYPE(Id, SingletonId) 475234353Sdim#define UNSIGNED_TYPE(Id, SingletonId) 476234353Sdim#define FLOATING_TYPE(Id, SingletonId) 477234353Sdim#define BUILTIN_TYPE(Id, SingletonId) \ 478234353Sdim case BuiltinType::Id: 479234353Sdim#include "clang/AST/BuiltinTypes.def" 480221345Sdim // Misc other stuff which doesn't make sense here. 481221345Sdim return false; 482221345Sdim 483221345Sdim case BuiltinType::UInt: 484221345Sdim case BuiltinType::Int: 485221345Sdim case BuiltinType::Float: 486221345Sdim case BuiltinType::Double: 487210299Sed LM.setKind(LengthModifier::None); 488210299Sed break; 489210299Sed 490218893Sdim case BuiltinType::Char_U: 491218893Sdim case BuiltinType::UChar: 492218893Sdim case BuiltinType::Char_S: 493218893Sdim case BuiltinType::SChar: 494218893Sdim LM.setKind(LengthModifier::AsChar); 495218893Sdim break; 496218893Sdim 497218893Sdim case BuiltinType::Short: 498218893Sdim case BuiltinType::UShort: 499218893Sdim LM.setKind(LengthModifier::AsShort); 500218893Sdim break; 501218893Sdim 502210299Sed case BuiltinType::Long: 503210299Sed case BuiltinType::ULong: 504210299Sed LM.setKind(LengthModifier::AsLong); 505210299Sed break; 506210299Sed 507210299Sed case BuiltinType::LongLong: 508210299Sed case BuiltinType::ULongLong: 509210299Sed LM.setKind(LengthModifier::AsLongLong); 510210299Sed break; 511210299Sed 512210299Sed case BuiltinType::LongDouble: 513210299Sed LM.setKind(LengthModifier::AsLongDouble); 514210299Sed break; 515210299Sed } 516210299Sed 517234353Sdim // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. 518249423Sdim if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11)) 519239462Sdim namedTypeToLengthModifier(QT, LM); 520234353Sdim 521249423Sdim // If fixing the length modifier was enough, we might be done. 522243830Sdim if (hasValidLengthModifier(Ctx.getTargetInfo())) { 523249423Sdim // If we're going to offer a fix anyway, make sure the sign matches. 524249423Sdim switch (CS.getKind()) { 525249423Sdim case ConversionSpecifier::uArg: 526249423Sdim case ConversionSpecifier::UArg: 527249423Sdim if (QT->isSignedIntegerType()) 528249423Sdim CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); 529249423Sdim break; 530249423Sdim case ConversionSpecifier::dArg: 531249423Sdim case ConversionSpecifier::DArg: 532249423Sdim case ConversionSpecifier::iArg: 533249423Sdim if (QT->isUnsignedIntegerType() && !HasPlusPrefix) 534249423Sdim CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); 535249423Sdim break; 536249423Sdim default: 537249423Sdim // Other specifiers do not have signed/unsigned variants. 538249423Sdim break; 539249423Sdim } 540249423Sdim 541243830Sdim const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); 542243830Sdim if (ATR.isValid() && ATR.matchesType(Ctx, QT)) 543243830Sdim return true; 544243830Sdim } 545234353Sdim 546210299Sed // Set conversion specifier and disable any flags which do not apply to it. 547218893Sdim // Let typedefs to char fall through to int, as %c is silly for uint8_t. 548249423Sdim if (!isa<TypedefType>(QT) && QT->isCharType()) { 549212904Sdim CS.setKind(ConversionSpecifier::cArg); 550218893Sdim LM.setKind(LengthModifier::None); 551210299Sed Precision.setHowSpecified(OptionalAmount::NotSpecified); 552210299Sed HasAlternativeForm = 0; 553210299Sed HasLeadingZeroes = 0; 554210299Sed HasPlusPrefix = 0; 555210299Sed } 556210299Sed // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 557210299Sed else if (QT->isRealFloatingType()) { 558210299Sed CS.setKind(ConversionSpecifier::fArg); 559210299Sed } 560210299Sed else if (QT->isSignedIntegerType()) { 561210299Sed CS.setKind(ConversionSpecifier::dArg); 562210299Sed HasAlternativeForm = 0; 563210299Sed } 564210299Sed else if (QT->isUnsignedIntegerType()) { 565234353Sdim CS.setKind(ConversionSpecifier::uArg); 566210299Sed HasAlternativeForm = 0; 567210299Sed HasPlusPrefix = 0; 568226633Sdim } else { 569226633Sdim llvm_unreachable("Unexpected type"); 570210299Sed } 571210299Sed 572210299Sed return true; 573210299Sed} 574210299Sed 575226633Sdimvoid PrintfSpecifier::toString(raw_ostream &os) const { 576210299Sed // Whilst some features have no defined order, we are using the order 577218893Sdim // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) 578210299Sed os << "%"; 579210299Sed 580210299Sed // Positional args 581210299Sed if (usesPositionalArg()) { 582210299Sed os << getPositionalArgIndex() << "$"; 583210299Sed } 584210299Sed 585210299Sed // Conversion flags 586210299Sed if (IsLeftJustified) os << "-"; 587210299Sed if (HasPlusPrefix) os << "+"; 588210299Sed if (HasSpacePrefix) os << " "; 589210299Sed if (HasAlternativeForm) os << "#"; 590210299Sed if (HasLeadingZeroes) os << "0"; 591210299Sed 592210299Sed // Minimum field width 593210299Sed FieldWidth.toString(os); 594210299Sed // Precision 595210299Sed Precision.toString(os); 596210299Sed // Length modifier 597210299Sed os << LM.toString(); 598210299Sed // Conversion specifier 599210299Sed os << CS.toString(); 600210299Sed} 601210299Sed 602212904Sdimbool PrintfSpecifier::hasValidPlusPrefix() const { 603210299Sed if (!HasPlusPrefix) 604210299Sed return true; 605210299Sed 606210299Sed // The plus prefix only makes sense for signed conversions 607210299Sed switch (CS.getKind()) { 608210299Sed case ConversionSpecifier::dArg: 609243830Sdim case ConversionSpecifier::DArg: 610210299Sed case ConversionSpecifier::iArg: 611210299Sed case ConversionSpecifier::fArg: 612210299Sed case ConversionSpecifier::FArg: 613210299Sed case ConversionSpecifier::eArg: 614210299Sed case ConversionSpecifier::EArg: 615210299Sed case ConversionSpecifier::gArg: 616210299Sed case ConversionSpecifier::GArg: 617210299Sed case ConversionSpecifier::aArg: 618210299Sed case ConversionSpecifier::AArg: 619243830Sdim case ConversionSpecifier::FreeBSDrArg: 620210299Sed return true; 621210299Sed 622210299Sed default: 623210299Sed return false; 624210299Sed } 625210299Sed} 626210299Sed 627212904Sdimbool PrintfSpecifier::hasValidAlternativeForm() const { 628210299Sed if (!HasAlternativeForm) 629210299Sed return true; 630210299Sed 631218893Sdim // Alternate form flag only valid with the oxXaAeEfFgG conversions 632210299Sed switch (CS.getKind()) { 633210299Sed case ConversionSpecifier::oArg: 634243830Sdim case ConversionSpecifier::OArg: 635210299Sed case ConversionSpecifier::xArg: 636218893Sdim case ConversionSpecifier::XArg: 637210299Sed case ConversionSpecifier::aArg: 638210299Sed case ConversionSpecifier::AArg: 639210299Sed case ConversionSpecifier::eArg: 640210299Sed case ConversionSpecifier::EArg: 641210299Sed case ConversionSpecifier::fArg: 642210299Sed case ConversionSpecifier::FArg: 643210299Sed case ConversionSpecifier::gArg: 644210299Sed case ConversionSpecifier::GArg: 645243830Sdim case ConversionSpecifier::FreeBSDrArg: 646210299Sed return true; 647210299Sed 648210299Sed default: 649210299Sed return false; 650210299Sed } 651210299Sed} 652210299Sed 653212904Sdimbool PrintfSpecifier::hasValidLeadingZeros() const { 654210299Sed if (!HasLeadingZeroes) 655210299Sed return true; 656210299Sed 657210299Sed // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions 658210299Sed switch (CS.getKind()) { 659210299Sed case ConversionSpecifier::dArg: 660243830Sdim case ConversionSpecifier::DArg: 661210299Sed case ConversionSpecifier::iArg: 662210299Sed case ConversionSpecifier::oArg: 663243830Sdim case ConversionSpecifier::OArg: 664210299Sed case ConversionSpecifier::uArg: 665243830Sdim case ConversionSpecifier::UArg: 666210299Sed case ConversionSpecifier::xArg: 667210299Sed case ConversionSpecifier::XArg: 668210299Sed case ConversionSpecifier::aArg: 669210299Sed case ConversionSpecifier::AArg: 670210299Sed case ConversionSpecifier::eArg: 671210299Sed case ConversionSpecifier::EArg: 672210299Sed case ConversionSpecifier::fArg: 673210299Sed case ConversionSpecifier::FArg: 674210299Sed case ConversionSpecifier::gArg: 675210299Sed case ConversionSpecifier::GArg: 676210299Sed return true; 677210299Sed 678210299Sed default: 679210299Sed return false; 680210299Sed } 681210299Sed} 682210299Sed 683212904Sdimbool PrintfSpecifier::hasValidSpacePrefix() const { 684210299Sed if (!HasSpacePrefix) 685210299Sed return true; 686210299Sed 687210299Sed // The space prefix only makes sense for signed conversions 688210299Sed switch (CS.getKind()) { 689210299Sed case ConversionSpecifier::dArg: 690243830Sdim case ConversionSpecifier::DArg: 691210299Sed case ConversionSpecifier::iArg: 692210299Sed case ConversionSpecifier::fArg: 693210299Sed case ConversionSpecifier::FArg: 694210299Sed case ConversionSpecifier::eArg: 695210299Sed case ConversionSpecifier::EArg: 696210299Sed case ConversionSpecifier::gArg: 697210299Sed case ConversionSpecifier::GArg: 698210299Sed case ConversionSpecifier::aArg: 699210299Sed case ConversionSpecifier::AArg: 700210299Sed return true; 701210299Sed 702210299Sed default: 703210299Sed return false; 704210299Sed } 705210299Sed} 706210299Sed 707212904Sdimbool PrintfSpecifier::hasValidLeftJustified() const { 708210299Sed if (!IsLeftJustified) 709210299Sed return true; 710210299Sed 711210299Sed // The left justified flag is valid for all conversions except n 712210299Sed switch (CS.getKind()) { 713212904Sdim case ConversionSpecifier::nArg: 714210299Sed return false; 715210299Sed 716210299Sed default: 717210299Sed return true; 718210299Sed } 719210299Sed} 720210299Sed 721218893Sdimbool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { 722218893Sdim if (!HasThousandsGrouping) 723218893Sdim return true; 724218893Sdim 725218893Sdim switch (CS.getKind()) { 726218893Sdim case ConversionSpecifier::dArg: 727243830Sdim case ConversionSpecifier::DArg: 728218893Sdim case ConversionSpecifier::iArg: 729218893Sdim case ConversionSpecifier::uArg: 730243830Sdim case ConversionSpecifier::UArg: 731218893Sdim case ConversionSpecifier::fArg: 732218893Sdim case ConversionSpecifier::FArg: 733218893Sdim case ConversionSpecifier::gArg: 734218893Sdim case ConversionSpecifier::GArg: 735218893Sdim return true; 736218893Sdim default: 737218893Sdim return false; 738218893Sdim } 739218893Sdim} 740218893Sdim 741212904Sdimbool PrintfSpecifier::hasValidPrecision() const { 742210299Sed if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) 743210299Sed return true; 744210299Sed 745210299Sed // Precision is only valid with the diouxXaAeEfFgGs conversions 746210299Sed switch (CS.getKind()) { 747210299Sed case ConversionSpecifier::dArg: 748243830Sdim case ConversionSpecifier::DArg: 749210299Sed case ConversionSpecifier::iArg: 750210299Sed case ConversionSpecifier::oArg: 751243830Sdim case ConversionSpecifier::OArg: 752210299Sed case ConversionSpecifier::uArg: 753243830Sdim case ConversionSpecifier::UArg: 754210299Sed case ConversionSpecifier::xArg: 755210299Sed case ConversionSpecifier::XArg: 756210299Sed case ConversionSpecifier::aArg: 757210299Sed case ConversionSpecifier::AArg: 758210299Sed case ConversionSpecifier::eArg: 759210299Sed case ConversionSpecifier::EArg: 760210299Sed case ConversionSpecifier::fArg: 761210299Sed case ConversionSpecifier::FArg: 762210299Sed case ConversionSpecifier::gArg: 763210299Sed case ConversionSpecifier::GArg: 764212904Sdim case ConversionSpecifier::sArg: 765210299Sed return true; 766210299Sed 767210299Sed default: 768210299Sed return false; 769210299Sed } 770210299Sed} 771212904Sdimbool PrintfSpecifier::hasValidFieldWidth() const { 772210299Sed if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) 773210299Sed return true; 774210299Sed 775210299Sed // The field width is valid for all conversions except n 776210299Sed switch (CS.getKind()) { 777212904Sdim case ConversionSpecifier::nArg: 778210299Sed return false; 779210299Sed 780210299Sed default: 781210299Sed return true; 782210299Sed } 783210299Sed} 784