1212795Sdim//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===// 2212795Sdim// 3212795Sdim// The LLVM Compiler Infrastructure 4212795Sdim// 5212795Sdim// This file is distributed under the University of Illinois Open Source 6212795Sdim// License. See LICENSE.TXT for details. 7212795Sdim// 8212795Sdim//===----------------------------------------------------------------------===// 9212795Sdim// 10212795Sdim// Handling of format string in scanf and friends. The structure of format 11212795Sdim// strings for fscanf() are described in C99 7.19.6.2. 12212795Sdim// 13212795Sdim//===----------------------------------------------------------------------===// 14212795Sdim 15212795Sdim#include "clang/Analysis/Analyses/FormatString.h" 16249423Sdim#include "FormatStringParsing.h" 17243830Sdim#include "clang/Basic/TargetInfo.h" 18212795Sdim 19239462Sdimusing clang::analyze_format_string::ArgType; 20212795Sdimusing clang::analyze_format_string::FormatStringHandler; 21212795Sdimusing clang::analyze_format_string::LengthModifier; 22212795Sdimusing clang::analyze_format_string::OptionalAmount; 23212795Sdimusing clang::analyze_format_string::ConversionSpecifier; 24212795Sdimusing clang::analyze_scanf::ScanfConversionSpecifier; 25212795Sdimusing clang::analyze_scanf::ScanfSpecifier; 26212795Sdimusing clang::UpdateOnReturn; 27234353Sdimusing namespace clang; 28212795Sdim 29212795Sdimtypedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier> 30212795Sdim ScanfSpecifierResult; 31212795Sdim 32212795Sdimstatic bool ParseScanList(FormatStringHandler &H, 33212795Sdim ScanfConversionSpecifier &CS, 34212795Sdim const char *&Beg, const char *E) { 35212795Sdim const char *I = Beg; 36212795Sdim const char *start = I - 1; 37212795Sdim UpdateOnReturn <const char*> UpdateBeg(Beg, I); 38212795Sdim 39212795Sdim // No more characters? 40212795Sdim if (I == E) { 41212795Sdim H.HandleIncompleteScanList(start, I); 42212795Sdim return true; 43212795Sdim } 44212795Sdim 45212795Sdim // Special case: ']' is the first character. 46212795Sdim if (*I == ']') { 47212795Sdim if (++I == E) { 48212795Sdim H.HandleIncompleteScanList(start, I - 1); 49212795Sdim return true; 50212795Sdim } 51212795Sdim } 52212795Sdim 53276479Sdim // Special case: "^]" are the first characters. 54276479Sdim if (I + 1 != E && I[0] == '^' && I[1] == ']') { 55276479Sdim I += 2; 56276479Sdim if (I == E) { 57276479Sdim H.HandleIncompleteScanList(start, I - 1); 58276479Sdim return true; 59276479Sdim } 60276479Sdim } 61276479Sdim 62212795Sdim // Look for a ']' character which denotes the end of the scan list. 63212795Sdim while (*I != ']') { 64212795Sdim if (++I == E) { 65212795Sdim H.HandleIncompleteScanList(start, I - 1); 66212795Sdim return true; 67212795Sdim } 68212795Sdim } 69212795Sdim 70212795Sdim CS.setEndScanList(I); 71212795Sdim return false; 72212795Sdim} 73212795Sdim 74212795Sdim// FIXME: Much of this is copy-paste from ParsePrintfSpecifier. 75212795Sdim// We can possibly refactor. 76212795Sdimstatic ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, 77212795Sdim const char *&Beg, 78212795Sdim const char *E, 79234353Sdim unsigned &argIndex, 80243830Sdim const LangOptions &LO, 81243830Sdim const TargetInfo &Target) { 82212795Sdim 83212795Sdim using namespace clang::analyze_scanf; 84212795Sdim const char *I = Beg; 85276479Sdim const char *Start = nullptr; 86212795Sdim UpdateOnReturn <const char*> UpdateBeg(Beg, I); 87212795Sdim 88212795Sdim // Look for a '%' character that indicates the start of a format specifier. 89212795Sdim for ( ; I != E ; ++I) { 90212795Sdim char c = *I; 91212795Sdim if (c == '\0') { 92212795Sdim // Detect spurious null characters, which are likely errors. 93212795Sdim H.HandleNullChar(I); 94212795Sdim return true; 95212795Sdim } 96212795Sdim if (c == '%') { 97212795Sdim Start = I++; // Record the start of the format specifier. 98212795Sdim break; 99212795Sdim } 100212795Sdim } 101212795Sdim 102212795Sdim // No format specifier found? 103212795Sdim if (!Start) 104212795Sdim return false; 105212795Sdim 106212795Sdim if (I == E) { 107212795Sdim // No more characters left? 108212795Sdim H.HandleIncompleteSpecifier(Start, E - Start); 109212795Sdim return true; 110212795Sdim } 111212795Sdim 112212795Sdim ScanfSpecifier FS; 113212795Sdim if (ParseArgPosition(H, FS, Start, I, E)) 114212795Sdim return true; 115212795Sdim 116212795Sdim if (I == E) { 117212795Sdim // No more characters left? 118212795Sdim H.HandleIncompleteSpecifier(Start, E - Start); 119212795Sdim return true; 120212795Sdim } 121212795Sdim 122212795Sdim // Look for '*' flag if it is present. 123212795Sdim if (*I == '*') { 124212795Sdim FS.setSuppressAssignment(I); 125212795Sdim if (++I == E) { 126212795Sdim H.HandleIncompleteSpecifier(Start, E - Start); 127212795Sdim return true; 128212795Sdim } 129212795Sdim } 130212795Sdim 131212795Sdim // Look for the field width (if any). Unlike printf, this is either 132212795Sdim // a fixed integer or isn't present. 133212795Sdim const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E); 134212795Sdim if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) { 135212795Sdim assert(Amt.getHowSpecified() == OptionalAmount::Constant); 136212795Sdim FS.setFieldWidth(Amt); 137212795Sdim 138212795Sdim if (I == E) { 139212795Sdim // No more characters left? 140212795Sdim H.HandleIncompleteSpecifier(Start, E - Start); 141212795Sdim return true; 142212795Sdim } 143212795Sdim } 144212795Sdim 145212795Sdim // Look for the length modifier. 146234353Sdim if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) { 147212795Sdim // No more characters left? 148212795Sdim H.HandleIncompleteSpecifier(Start, E - Start); 149212795Sdim return true; 150212795Sdim } 151212795Sdim 152212795Sdim // Detect spurious null characters, which are likely errors. 153212795Sdim if (*I == '\0') { 154212795Sdim H.HandleNullChar(I); 155212795Sdim return true; 156212795Sdim } 157212795Sdim 158212795Sdim // Finally, look for the conversion specifier. 159212795Sdim const char *conversionPosition = I++; 160212795Sdim ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier; 161212795Sdim switch (*conversionPosition) { 162212795Sdim default: 163212795Sdim break; 164212795Sdim case '%': k = ConversionSpecifier::PercentArg; break; 165212795Sdim case 'A': k = ConversionSpecifier::AArg; break; 166212795Sdim case 'E': k = ConversionSpecifier::EArg; break; 167212795Sdim case 'F': k = ConversionSpecifier::FArg; break; 168212795Sdim case 'G': k = ConversionSpecifier::GArg; break; 169212795Sdim case 'X': k = ConversionSpecifier::XArg; break; 170212795Sdim case 'a': k = ConversionSpecifier::aArg; break; 171212795Sdim case 'd': k = ConversionSpecifier::dArg; break; 172212795Sdim case 'e': k = ConversionSpecifier::eArg; break; 173212795Sdim case 'f': k = ConversionSpecifier::fArg; break; 174212795Sdim case 'g': k = ConversionSpecifier::gArg; break; 175212795Sdim case 'i': k = ConversionSpecifier::iArg; break; 176212795Sdim case 'n': k = ConversionSpecifier::nArg; break; 177212795Sdim case 'c': k = ConversionSpecifier::cArg; break; 178212795Sdim case 'C': k = ConversionSpecifier::CArg; break; 179212795Sdim case 'S': k = ConversionSpecifier::SArg; break; 180212795Sdim case '[': k = ConversionSpecifier::ScanListArg; break; 181212795Sdim case 'u': k = ConversionSpecifier::uArg; break; 182212795Sdim case 'x': k = ConversionSpecifier::xArg; break; 183212795Sdim case 'o': k = ConversionSpecifier::oArg; break; 184212795Sdim case 's': k = ConversionSpecifier::sArg; break; 185212795Sdim case 'p': k = ConversionSpecifier::pArg; break; 186243830Sdim // Apple extensions 187243830Sdim // Apple-specific 188243830Sdim case 'D': 189243830Sdim if (Target.getTriple().isOSDarwin()) 190243830Sdim k = ConversionSpecifier::DArg; 191243830Sdim break; 192243830Sdim case 'O': 193243830Sdim if (Target.getTriple().isOSDarwin()) 194243830Sdim k = ConversionSpecifier::OArg; 195243830Sdim break; 196243830Sdim case 'U': 197243830Sdim if (Target.getTriple().isOSDarwin()) 198243830Sdim k = ConversionSpecifier::UArg; 199243830Sdim break; 200212795Sdim } 201212795Sdim ScanfConversionSpecifier CS(conversionPosition, k); 202212795Sdim if (k == ScanfConversionSpecifier::ScanListArg) { 203234353Sdim if (ParseScanList(H, CS, I, E)) 204212795Sdim return true; 205212795Sdim } 206212795Sdim FS.setConversionSpecifier(CS); 207212795Sdim if (CS.consumesDataArgument() && !FS.getSuppressAssignment() 208212795Sdim && !FS.usesPositionalArg()) 209212795Sdim FS.setArgIndex(argIndex++); 210212795Sdim 211212795Sdim // FIXME: '%' and '*' doesn't make sense. Issue a warning. 212212795Sdim // FIXME: 'ConsumedSoFar' and '*' doesn't make sense. 213212795Sdim 214212795Sdim if (k == ScanfConversionSpecifier::InvalidSpecifier) { 215212795Sdim // Assume the conversion takes one argument. 216212795Sdim return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, I - Beg); 217212795Sdim } 218212795Sdim return ScanfSpecifierResult(Start, FS); 219212795Sdim} 220234353Sdim 221239462SdimArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { 222234353Sdim const ScanfConversionSpecifier &CS = getConversionSpecifier(); 223234353Sdim 224234353Sdim if (!CS.consumesDataArgument()) 225239462Sdim return ArgType::Invalid(); 226234353Sdim 227234353Sdim switch(CS.getKind()) { 228234353Sdim // Signed int. 229234353Sdim case ConversionSpecifier::dArg: 230243830Sdim case ConversionSpecifier::DArg: 231234353Sdim case ConversionSpecifier::iArg: 232234353Sdim switch (LM.getKind()) { 233239462Sdim case LengthModifier::None: 234239462Sdim return ArgType::PtrTo(Ctx.IntTy); 235234353Sdim case LengthModifier::AsChar: 236239462Sdim return ArgType::PtrTo(ArgType::AnyCharTy); 237239462Sdim case LengthModifier::AsShort: 238239462Sdim return ArgType::PtrTo(Ctx.ShortTy); 239239462Sdim case LengthModifier::AsLong: 240239462Sdim return ArgType::PtrTo(Ctx.LongTy); 241234353Sdim case LengthModifier::AsLongLong: 242234353Sdim case LengthModifier::AsQuad: 243239462Sdim return ArgType::PtrTo(Ctx.LongLongTy); 244261991Sdim case LengthModifier::AsInt64: 245261991Sdim return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64")); 246234353Sdim case LengthModifier::AsIntMax: 247239462Sdim return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); 248234353Sdim case LengthModifier::AsSizeT: 249234353Sdim // FIXME: ssize_t. 250239462Sdim return ArgType(); 251234353Sdim case LengthModifier::AsPtrDiff: 252239462Sdim return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 253234353Sdim case LengthModifier::AsLongDouble: 254234353Sdim // GNU extension. 255239462Sdim return ArgType::PtrTo(Ctx.LongLongTy); 256239462Sdim case LengthModifier::AsAllocate: 257239462Sdim case LengthModifier::AsMAllocate: 258261991Sdim case LengthModifier::AsInt32: 259261991Sdim case LengthModifier::AsInt3264: 260280031Sdim case LengthModifier::AsWide: 261239462Sdim return ArgType::Invalid(); 262234353Sdim } 263234353Sdim 264234353Sdim // Unsigned int. 265234353Sdim case ConversionSpecifier::oArg: 266243830Sdim case ConversionSpecifier::OArg: 267234353Sdim case ConversionSpecifier::uArg: 268243830Sdim case ConversionSpecifier::UArg: 269234353Sdim case ConversionSpecifier::xArg: 270234353Sdim case ConversionSpecifier::XArg: 271234353Sdim switch (LM.getKind()) { 272239462Sdim case LengthModifier::None: 273239462Sdim return ArgType::PtrTo(Ctx.UnsignedIntTy); 274239462Sdim case LengthModifier::AsChar: 275239462Sdim return ArgType::PtrTo(Ctx.UnsignedCharTy); 276239462Sdim case LengthModifier::AsShort: 277239462Sdim return ArgType::PtrTo(Ctx.UnsignedShortTy); 278239462Sdim case LengthModifier::AsLong: 279239462Sdim return ArgType::PtrTo(Ctx.UnsignedLongTy); 280234353Sdim case LengthModifier::AsLongLong: 281234353Sdim case LengthModifier::AsQuad: 282239462Sdim return ArgType::PtrTo(Ctx.UnsignedLongLongTy); 283261991Sdim case LengthModifier::AsInt64: 284261991Sdim return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")); 285234353Sdim case LengthModifier::AsIntMax: 286239462Sdim return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t")); 287234353Sdim case LengthModifier::AsSizeT: 288239462Sdim return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t")); 289234353Sdim case LengthModifier::AsPtrDiff: 290234353Sdim // FIXME: Unsigned version of ptrdiff_t? 291239462Sdim return ArgType(); 292234353Sdim case LengthModifier::AsLongDouble: 293234353Sdim // GNU extension. 294239462Sdim return ArgType::PtrTo(Ctx.UnsignedLongLongTy); 295239462Sdim case LengthModifier::AsAllocate: 296239462Sdim case LengthModifier::AsMAllocate: 297261991Sdim case LengthModifier::AsInt32: 298261991Sdim case LengthModifier::AsInt3264: 299280031Sdim case LengthModifier::AsWide: 300239462Sdim return ArgType::Invalid(); 301234353Sdim } 302234353Sdim 303234353Sdim // Float. 304234353Sdim case ConversionSpecifier::aArg: 305234353Sdim case ConversionSpecifier::AArg: 306234353Sdim case ConversionSpecifier::eArg: 307234353Sdim case ConversionSpecifier::EArg: 308234353Sdim case ConversionSpecifier::fArg: 309234353Sdim case ConversionSpecifier::FArg: 310234353Sdim case ConversionSpecifier::gArg: 311234353Sdim case ConversionSpecifier::GArg: 312234353Sdim switch (LM.getKind()) { 313239462Sdim case LengthModifier::None: 314239462Sdim return ArgType::PtrTo(Ctx.FloatTy); 315239462Sdim case LengthModifier::AsLong: 316239462Sdim return ArgType::PtrTo(Ctx.DoubleTy); 317234353Sdim case LengthModifier::AsLongDouble: 318239462Sdim return ArgType::PtrTo(Ctx.LongDoubleTy); 319234353Sdim default: 320239462Sdim return ArgType::Invalid(); 321234353Sdim } 322234353Sdim 323234353Sdim // Char, string and scanlist. 324234353Sdim case ConversionSpecifier::cArg: 325234353Sdim case ConversionSpecifier::sArg: 326234353Sdim case ConversionSpecifier::ScanListArg: 327234353Sdim switch (LM.getKind()) { 328239462Sdim case LengthModifier::None: 329239462Sdim return ArgType::PtrTo(ArgType::AnyCharTy); 330234353Sdim case LengthModifier::AsLong: 331280031Sdim case LengthModifier::AsWide: 332261991Sdim return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t")); 333234353Sdim case LengthModifier::AsAllocate: 334234353Sdim case LengthModifier::AsMAllocate: 335239462Sdim return ArgType::PtrTo(ArgType::CStrTy); 336280031Sdim case LengthModifier::AsShort: 337280031Sdim if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) 338280031Sdim return ArgType::PtrTo(ArgType::AnyCharTy); 339234353Sdim default: 340239462Sdim return ArgType::Invalid(); 341234353Sdim } 342234353Sdim case ConversionSpecifier::CArg: 343234353Sdim case ConversionSpecifier::SArg: 344234353Sdim // FIXME: Mac OS X specific? 345234353Sdim switch (LM.getKind()) { 346234353Sdim case LengthModifier::None: 347280031Sdim case LengthModifier::AsWide: 348261991Sdim return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t")); 349234353Sdim case LengthModifier::AsAllocate: 350234353Sdim case LengthModifier::AsMAllocate: 351239462Sdim return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *")); 352280031Sdim case LengthModifier::AsShort: 353280031Sdim if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) 354280031Sdim return ArgType::PtrTo(ArgType::AnyCharTy); 355234353Sdim default: 356239462Sdim return ArgType::Invalid(); 357234353Sdim } 358234353Sdim 359234353Sdim // Pointer. 360234353Sdim case ConversionSpecifier::pArg: 361239462Sdim return ArgType::PtrTo(ArgType::CPointerTy); 362234353Sdim 363239462Sdim // Write-back. 364239462Sdim case ConversionSpecifier::nArg: 365239462Sdim switch (LM.getKind()) { 366239462Sdim case LengthModifier::None: 367239462Sdim return ArgType::PtrTo(Ctx.IntTy); 368239462Sdim case LengthModifier::AsChar: 369239462Sdim return ArgType::PtrTo(Ctx.SignedCharTy); 370239462Sdim case LengthModifier::AsShort: 371239462Sdim return ArgType::PtrTo(Ctx.ShortTy); 372239462Sdim case LengthModifier::AsLong: 373239462Sdim return ArgType::PtrTo(Ctx.LongTy); 374239462Sdim case LengthModifier::AsLongLong: 375239462Sdim case LengthModifier::AsQuad: 376239462Sdim return ArgType::PtrTo(Ctx.LongLongTy); 377261991Sdim case LengthModifier::AsInt64: 378261991Sdim return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64")); 379239462Sdim case LengthModifier::AsIntMax: 380239462Sdim return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); 381239462Sdim case LengthModifier::AsSizeT: 382239462Sdim return ArgType(); // FIXME: ssize_t 383239462Sdim case LengthModifier::AsPtrDiff: 384239462Sdim return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 385239462Sdim case LengthModifier::AsLongDouble: 386239462Sdim return ArgType(); // FIXME: Is this a known extension? 387239462Sdim case LengthModifier::AsAllocate: 388239462Sdim case LengthModifier::AsMAllocate: 389261991Sdim case LengthModifier::AsInt32: 390261991Sdim case LengthModifier::AsInt3264: 391280031Sdim case LengthModifier::AsWide: 392239462Sdim return ArgType::Invalid(); 393239462Sdim } 394239462Sdim 395234353Sdim default: 396234353Sdim break; 397234353Sdim } 398234353Sdim 399239462Sdim return ArgType(); 400234353Sdim} 401234353Sdim 402276479Sdimbool ScanfSpecifier::fixType(QualType QT, QualType RawQT, 403276479Sdim const LangOptions &LangOpt, 404234353Sdim ASTContext &Ctx) { 405234353Sdim 406239462Sdim // %n is different from other conversion specifiers; don't try to fix it. 407239462Sdim if (CS.getKind() == ConversionSpecifier::nArg) 408239462Sdim return false; 409239462Sdim 410276479Sdim if (!QT->isPointerType()) 411276479Sdim return false; 412276479Sdim 413234353Sdim QualType PT = QT->getPointeeType(); 414239462Sdim 415239462Sdim // If it's an enum, get its underlying type. 416276479Sdim if (const EnumType *ETy = PT->getAs<EnumType>()) 417276479Sdim PT = ETy->getDecl()->getIntegerType(); 418276479Sdim 419234353Sdim const BuiltinType *BT = PT->getAs<BuiltinType>(); 420234353Sdim if (!BT) 421234353Sdim return false; 422234353Sdim 423234353Sdim // Pointer to a character. 424234353Sdim if (PT->isAnyCharacterType()) { 425234353Sdim CS.setKind(ConversionSpecifier::sArg); 426234353Sdim if (PT->isWideCharType()) 427234353Sdim LM.setKind(LengthModifier::AsWideChar); 428234353Sdim else 429234353Sdim LM.setKind(LengthModifier::None); 430276479Sdim 431276479Sdim // If we know the target array length, we can use it as a field width. 432276479Sdim if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) { 433276479Sdim if (CAT->getSizeModifier() == ArrayType::Normal) 434276479Sdim FieldWidth = OptionalAmount(OptionalAmount::Constant, 435276479Sdim CAT->getSize().getZExtValue() - 1, 436276479Sdim "", 0, false); 437276479Sdim 438276479Sdim } 439234353Sdim return true; 440234353Sdim } 441234353Sdim 442234353Sdim // Figure out the length modifier. 443234353Sdim switch (BT->getKind()) { 444234353Sdim // no modifier 445234353Sdim case BuiltinType::UInt: 446234353Sdim case BuiltinType::Int: 447234353Sdim case BuiltinType::Float: 448234353Sdim LM.setKind(LengthModifier::None); 449234353Sdim break; 450234353Sdim 451234353Sdim // hh 452234353Sdim case BuiltinType::Char_U: 453234353Sdim case BuiltinType::UChar: 454234353Sdim case BuiltinType::Char_S: 455234353Sdim case BuiltinType::SChar: 456234353Sdim LM.setKind(LengthModifier::AsChar); 457234353Sdim break; 458234353Sdim 459234353Sdim // h 460234353Sdim case BuiltinType::Short: 461234353Sdim case BuiltinType::UShort: 462234353Sdim LM.setKind(LengthModifier::AsShort); 463234353Sdim break; 464234353Sdim 465234353Sdim // l 466234353Sdim case BuiltinType::Long: 467234353Sdim case BuiltinType::ULong: 468234353Sdim case BuiltinType::Double: 469234353Sdim LM.setKind(LengthModifier::AsLong); 470234353Sdim break; 471234353Sdim 472234353Sdim // ll 473234353Sdim case BuiltinType::LongLong: 474234353Sdim case BuiltinType::ULongLong: 475234353Sdim LM.setKind(LengthModifier::AsLongLong); 476234353Sdim break; 477234353Sdim 478234353Sdim // L 479234353Sdim case BuiltinType::LongDouble: 480234353Sdim LM.setKind(LengthModifier::AsLongDouble); 481234353Sdim break; 482234353Sdim 483234353Sdim // Don't know. 484234353Sdim default: 485234353Sdim return false; 486234353Sdim } 487234353Sdim 488234353Sdim // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. 489249423Sdim if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11)) 490239462Sdim namedTypeToLengthModifier(PT, LM); 491234353Sdim 492234353Sdim // If fixing the length modifier was enough, we are done. 493243830Sdim if (hasValidLengthModifier(Ctx.getTargetInfo())) { 494243830Sdim const analyze_scanf::ArgType &AT = getArgType(Ctx); 495243830Sdim if (AT.isValid() && AT.matchesType(Ctx, QT)) 496243830Sdim return true; 497243830Sdim } 498234353Sdim 499234353Sdim // Figure out the conversion specifier. 500234353Sdim if (PT->isRealFloatingType()) 501234353Sdim CS.setKind(ConversionSpecifier::fArg); 502234353Sdim else if (PT->isSignedIntegerType()) 503234353Sdim CS.setKind(ConversionSpecifier::dArg); 504234353Sdim else if (PT->isUnsignedIntegerType()) 505234353Sdim CS.setKind(ConversionSpecifier::uArg); 506234353Sdim else 507234353Sdim llvm_unreachable("Unexpected type"); 508234353Sdim 509234353Sdim return true; 510234353Sdim} 511234353Sdim 512234353Sdimvoid ScanfSpecifier::toString(raw_ostream &os) const { 513234353Sdim os << "%"; 514234353Sdim 515234353Sdim if (usesPositionalArg()) 516234353Sdim os << getPositionalArgIndex() << "$"; 517234353Sdim if (SuppressAssignment) 518234353Sdim os << "*"; 519234353Sdim 520234353Sdim FieldWidth.toString(os); 521234353Sdim os << LM.toString(); 522234353Sdim os << CS.toString(); 523234353Sdim} 524234353Sdim 525212795Sdimbool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H, 526212795Sdim const char *I, 527234353Sdim const char *E, 528243830Sdim const LangOptions &LO, 529243830Sdim const TargetInfo &Target) { 530212795Sdim 531212795Sdim unsigned argIndex = 0; 532212795Sdim 533212795Sdim // Keep looking for a format specifier until we have exhausted the string. 534212795Sdim while (I != E) { 535234353Sdim const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex, 536243830Sdim LO, Target); 537212795Sdim // Did a fail-stop error of any kind occur when parsing the specifier? 538212795Sdim // If so, don't do any more processing. 539212795Sdim if (FSR.shouldStop()) 540243830Sdim return true; 541212795Sdim // Did we exhaust the string or encounter an error that 542212795Sdim // we can recover from? 543212795Sdim if (!FSR.hasValue()) 544212795Sdim continue; 545212795Sdim // We have a format specifier. Pass it to the callback. 546212795Sdim if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(), 547212795Sdim I - FSR.getStart())) { 548212795Sdim return true; 549212795Sdim } 550212795Sdim } 551212795Sdim assert(I == E && "Format string not exhausted"); 552212795Sdim return false; 553212795Sdim} 554