ScanfFormatString.cpp revision 276479
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:
260239462Sdim          return ArgType::Invalid();
261234353Sdim      }
262234353Sdim
263234353Sdim    // Unsigned int.
264234353Sdim    case ConversionSpecifier::oArg:
265243830Sdim    case ConversionSpecifier::OArg:
266234353Sdim    case ConversionSpecifier::uArg:
267243830Sdim    case ConversionSpecifier::UArg:
268234353Sdim    case ConversionSpecifier::xArg:
269234353Sdim    case ConversionSpecifier::XArg:
270234353Sdim      switch (LM.getKind()) {
271239462Sdim        case LengthModifier::None:
272239462Sdim          return ArgType::PtrTo(Ctx.UnsignedIntTy);
273239462Sdim        case LengthModifier::AsChar:
274239462Sdim          return ArgType::PtrTo(Ctx.UnsignedCharTy);
275239462Sdim        case LengthModifier::AsShort:
276239462Sdim          return ArgType::PtrTo(Ctx.UnsignedShortTy);
277239462Sdim        case LengthModifier::AsLong:
278239462Sdim          return ArgType::PtrTo(Ctx.UnsignedLongTy);
279234353Sdim        case LengthModifier::AsLongLong:
280234353Sdim        case LengthModifier::AsQuad:
281239462Sdim          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
282261991Sdim        case LengthModifier::AsInt64:
283261991Sdim          return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
284234353Sdim        case LengthModifier::AsIntMax:
285239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
286234353Sdim        case LengthModifier::AsSizeT:
287239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
288234353Sdim        case LengthModifier::AsPtrDiff:
289234353Sdim          // FIXME: Unsigned version of ptrdiff_t?
290239462Sdim          return ArgType();
291234353Sdim        case LengthModifier::AsLongDouble:
292234353Sdim          // GNU extension.
293239462Sdim          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
294239462Sdim        case LengthModifier::AsAllocate:
295239462Sdim        case LengthModifier::AsMAllocate:
296261991Sdim        case LengthModifier::AsInt32:
297261991Sdim        case LengthModifier::AsInt3264:
298239462Sdim          return ArgType::Invalid();
299234353Sdim      }
300234353Sdim
301234353Sdim    // Float.
302234353Sdim    case ConversionSpecifier::aArg:
303234353Sdim    case ConversionSpecifier::AArg:
304234353Sdim    case ConversionSpecifier::eArg:
305234353Sdim    case ConversionSpecifier::EArg:
306234353Sdim    case ConversionSpecifier::fArg:
307234353Sdim    case ConversionSpecifier::FArg:
308234353Sdim    case ConversionSpecifier::gArg:
309234353Sdim    case ConversionSpecifier::GArg:
310234353Sdim      switch (LM.getKind()) {
311239462Sdim        case LengthModifier::None:
312239462Sdim          return ArgType::PtrTo(Ctx.FloatTy);
313239462Sdim        case LengthModifier::AsLong:
314239462Sdim          return ArgType::PtrTo(Ctx.DoubleTy);
315234353Sdim        case LengthModifier::AsLongDouble:
316239462Sdim          return ArgType::PtrTo(Ctx.LongDoubleTy);
317234353Sdim        default:
318239462Sdim          return ArgType::Invalid();
319234353Sdim      }
320234353Sdim
321234353Sdim    // Char, string and scanlist.
322234353Sdim    case ConversionSpecifier::cArg:
323234353Sdim    case ConversionSpecifier::sArg:
324234353Sdim    case ConversionSpecifier::ScanListArg:
325234353Sdim      switch (LM.getKind()) {
326239462Sdim        case LengthModifier::None:
327239462Sdim          return ArgType::PtrTo(ArgType::AnyCharTy);
328234353Sdim        case LengthModifier::AsLong:
329261991Sdim          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
330234353Sdim        case LengthModifier::AsAllocate:
331234353Sdim        case LengthModifier::AsMAllocate:
332239462Sdim          return ArgType::PtrTo(ArgType::CStrTy);
333234353Sdim        default:
334239462Sdim          return ArgType::Invalid();
335234353Sdim      }
336234353Sdim    case ConversionSpecifier::CArg:
337234353Sdim    case ConversionSpecifier::SArg:
338234353Sdim      // FIXME: Mac OS X specific?
339234353Sdim      switch (LM.getKind()) {
340234353Sdim        case LengthModifier::None:
341261991Sdim          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
342234353Sdim        case LengthModifier::AsAllocate:
343234353Sdim        case LengthModifier::AsMAllocate:
344239462Sdim          return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
345234353Sdim        default:
346239462Sdim          return ArgType::Invalid();
347234353Sdim      }
348234353Sdim
349234353Sdim    // Pointer.
350234353Sdim    case ConversionSpecifier::pArg:
351239462Sdim      return ArgType::PtrTo(ArgType::CPointerTy);
352234353Sdim
353239462Sdim    // Write-back.
354239462Sdim    case ConversionSpecifier::nArg:
355239462Sdim      switch (LM.getKind()) {
356239462Sdim        case LengthModifier::None:
357239462Sdim          return ArgType::PtrTo(Ctx.IntTy);
358239462Sdim        case LengthModifier::AsChar:
359239462Sdim          return ArgType::PtrTo(Ctx.SignedCharTy);
360239462Sdim        case LengthModifier::AsShort:
361239462Sdim          return ArgType::PtrTo(Ctx.ShortTy);
362239462Sdim        case LengthModifier::AsLong:
363239462Sdim          return ArgType::PtrTo(Ctx.LongTy);
364239462Sdim        case LengthModifier::AsLongLong:
365239462Sdim        case LengthModifier::AsQuad:
366239462Sdim          return ArgType::PtrTo(Ctx.LongLongTy);
367261991Sdim        case LengthModifier::AsInt64:
368261991Sdim          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
369239462Sdim        case LengthModifier::AsIntMax:
370239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
371239462Sdim        case LengthModifier::AsSizeT:
372239462Sdim          return ArgType(); // FIXME: ssize_t
373239462Sdim        case LengthModifier::AsPtrDiff:
374239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
375239462Sdim        case LengthModifier::AsLongDouble:
376239462Sdim          return ArgType(); // FIXME: Is this a known extension?
377239462Sdim        case LengthModifier::AsAllocate:
378239462Sdim        case LengthModifier::AsMAllocate:
379261991Sdim        case LengthModifier::AsInt32:
380261991Sdim        case LengthModifier::AsInt3264:
381239462Sdim          return ArgType::Invalid();
382239462Sdim        }
383239462Sdim
384234353Sdim    default:
385234353Sdim      break;
386234353Sdim  }
387234353Sdim
388239462Sdim  return ArgType();
389234353Sdim}
390234353Sdim
391276479Sdimbool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
392276479Sdim                             const LangOptions &LangOpt,
393234353Sdim                             ASTContext &Ctx) {
394234353Sdim
395239462Sdim  // %n is different from other conversion specifiers; don't try to fix it.
396239462Sdim  if (CS.getKind() == ConversionSpecifier::nArg)
397239462Sdim    return false;
398239462Sdim
399276479Sdim  if (!QT->isPointerType())
400276479Sdim    return false;
401276479Sdim
402234353Sdim  QualType PT = QT->getPointeeType();
403239462Sdim
404239462Sdim  // If it's an enum, get its underlying type.
405276479Sdim  if (const EnumType *ETy = PT->getAs<EnumType>())
406276479Sdim    PT = ETy->getDecl()->getIntegerType();
407276479Sdim
408234353Sdim  const BuiltinType *BT = PT->getAs<BuiltinType>();
409234353Sdim  if (!BT)
410234353Sdim    return false;
411234353Sdim
412234353Sdim  // Pointer to a character.
413234353Sdim  if (PT->isAnyCharacterType()) {
414234353Sdim    CS.setKind(ConversionSpecifier::sArg);
415234353Sdim    if (PT->isWideCharType())
416234353Sdim      LM.setKind(LengthModifier::AsWideChar);
417234353Sdim    else
418234353Sdim      LM.setKind(LengthModifier::None);
419276479Sdim
420276479Sdim    // If we know the target array length, we can use it as a field width.
421276479Sdim    if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
422276479Sdim      if (CAT->getSizeModifier() == ArrayType::Normal)
423276479Sdim        FieldWidth = OptionalAmount(OptionalAmount::Constant,
424276479Sdim                                    CAT->getSize().getZExtValue() - 1,
425276479Sdim                                    "", 0, false);
426276479Sdim
427276479Sdim    }
428234353Sdim    return true;
429234353Sdim  }
430234353Sdim
431234353Sdim  // Figure out the length modifier.
432234353Sdim  switch (BT->getKind()) {
433234353Sdim    // no modifier
434234353Sdim    case BuiltinType::UInt:
435234353Sdim    case BuiltinType::Int:
436234353Sdim    case BuiltinType::Float:
437234353Sdim      LM.setKind(LengthModifier::None);
438234353Sdim      break;
439234353Sdim
440234353Sdim    // hh
441234353Sdim    case BuiltinType::Char_U:
442234353Sdim    case BuiltinType::UChar:
443234353Sdim    case BuiltinType::Char_S:
444234353Sdim    case BuiltinType::SChar:
445234353Sdim      LM.setKind(LengthModifier::AsChar);
446234353Sdim      break;
447234353Sdim
448234353Sdim    // h
449234353Sdim    case BuiltinType::Short:
450234353Sdim    case BuiltinType::UShort:
451234353Sdim      LM.setKind(LengthModifier::AsShort);
452234353Sdim      break;
453234353Sdim
454234353Sdim    // l
455234353Sdim    case BuiltinType::Long:
456234353Sdim    case BuiltinType::ULong:
457234353Sdim    case BuiltinType::Double:
458234353Sdim      LM.setKind(LengthModifier::AsLong);
459234353Sdim      break;
460234353Sdim
461234353Sdim    // ll
462234353Sdim    case BuiltinType::LongLong:
463234353Sdim    case BuiltinType::ULongLong:
464234353Sdim      LM.setKind(LengthModifier::AsLongLong);
465234353Sdim      break;
466234353Sdim
467234353Sdim    // L
468234353Sdim    case BuiltinType::LongDouble:
469234353Sdim      LM.setKind(LengthModifier::AsLongDouble);
470234353Sdim      break;
471234353Sdim
472234353Sdim    // Don't know.
473234353Sdim    default:
474234353Sdim      return false;
475234353Sdim  }
476234353Sdim
477234353Sdim  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
478249423Sdim  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
479239462Sdim    namedTypeToLengthModifier(PT, LM);
480234353Sdim
481234353Sdim  // If fixing the length modifier was enough, we are done.
482243830Sdim  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
483243830Sdim    const analyze_scanf::ArgType &AT = getArgType(Ctx);
484243830Sdim    if (AT.isValid() && AT.matchesType(Ctx, QT))
485243830Sdim      return true;
486243830Sdim  }
487234353Sdim
488234353Sdim  // Figure out the conversion specifier.
489234353Sdim  if (PT->isRealFloatingType())
490234353Sdim    CS.setKind(ConversionSpecifier::fArg);
491234353Sdim  else if (PT->isSignedIntegerType())
492234353Sdim    CS.setKind(ConversionSpecifier::dArg);
493234353Sdim  else if (PT->isUnsignedIntegerType())
494234353Sdim    CS.setKind(ConversionSpecifier::uArg);
495234353Sdim  else
496234353Sdim    llvm_unreachable("Unexpected type");
497234353Sdim
498234353Sdim  return true;
499234353Sdim}
500234353Sdim
501234353Sdimvoid ScanfSpecifier::toString(raw_ostream &os) const {
502234353Sdim  os << "%";
503234353Sdim
504234353Sdim  if (usesPositionalArg())
505234353Sdim    os << getPositionalArgIndex() << "$";
506234353Sdim  if (SuppressAssignment)
507234353Sdim    os << "*";
508234353Sdim
509234353Sdim  FieldWidth.toString(os);
510234353Sdim  os << LM.toString();
511234353Sdim  os << CS.toString();
512234353Sdim}
513234353Sdim
514212795Sdimbool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
515212795Sdim                                                    const char *I,
516234353Sdim                                                    const char *E,
517243830Sdim                                                    const LangOptions &LO,
518243830Sdim                                                    const TargetInfo &Target) {
519212795Sdim
520212795Sdim  unsigned argIndex = 0;
521212795Sdim
522212795Sdim  // Keep looking for a format specifier until we have exhausted the string.
523212795Sdim  while (I != E) {
524234353Sdim    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
525243830Sdim                                                          LO, Target);
526212795Sdim    // Did a fail-stop error of any kind occur when parsing the specifier?
527212795Sdim    // If so, don't do any more processing.
528212795Sdim    if (FSR.shouldStop())
529243830Sdim      return true;
530212795Sdim      // Did we exhaust the string or encounter an error that
531212795Sdim      // we can recover from?
532212795Sdim    if (!FSR.hasValue())
533212795Sdim      continue;
534212795Sdim      // We have a format specifier.  Pass it to the callback.
535212795Sdim    if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
536212795Sdim                                I - FSR.getStart())) {
537212795Sdim      return true;
538212795Sdim    }
539212795Sdim  }
540212795Sdim  assert(I == E && "Format string not exhausted");
541212795Sdim  return false;
542212795Sdim}
543