1314fbfa1STim Northover //= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
2314fbfa1STim Northover //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6314fbfa1STim Northover //
7314fbfa1STim Northover //===----------------------------------------------------------------------===//
8314fbfa1STim Northover //
9314fbfa1STim Northover // Handling of format string in scanf and friends.  The structure of format
10314fbfa1STim Northover // strings for fscanf() are described in C99 7.19.6.2.
11314fbfa1STim Northover //
12314fbfa1STim Northover //===----------------------------------------------------------------------===//
13314fbfa1STim Northover 
14314fbfa1STim Northover #include "clang/AST/FormatString.h"
15314fbfa1STim Northover #include "FormatStringParsing.h"
16314fbfa1STim Northover #include "clang/Basic/TargetInfo.h"
17314fbfa1STim Northover 
18314fbfa1STim Northover using clang::analyze_format_string::ArgType;
19314fbfa1STim Northover using clang::analyze_format_string::FormatStringHandler;
20314fbfa1STim Northover using clang::analyze_format_string::LengthModifier;
21314fbfa1STim Northover using clang::analyze_format_string::OptionalAmount;
22314fbfa1STim Northover using clang::analyze_format_string::ConversionSpecifier;
23314fbfa1STim Northover using clang::analyze_scanf::ScanfConversionSpecifier;
24314fbfa1STim Northover using clang::analyze_scanf::ScanfSpecifier;
25314fbfa1STim Northover using clang::UpdateOnReturn;
26314fbfa1STim Northover using namespace clang;
27314fbfa1STim Northover 
28314fbfa1STim Northover typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
29314fbfa1STim Northover         ScanfSpecifierResult;
30314fbfa1STim Northover 
ParseScanList(FormatStringHandler & H,ScanfConversionSpecifier & CS,const char * & Beg,const char * E)31314fbfa1STim Northover static bool ParseScanList(FormatStringHandler &H,
32314fbfa1STim Northover                           ScanfConversionSpecifier &CS,
33314fbfa1STim Northover                           const char *&Beg, const char *E) {
34314fbfa1STim Northover   const char *I = Beg;
35314fbfa1STim Northover   const char *start = I - 1;
36314fbfa1STim Northover   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
37314fbfa1STim Northover 
38314fbfa1STim Northover   // No more characters?
39314fbfa1STim Northover   if (I == E) {
40314fbfa1STim Northover     H.HandleIncompleteScanList(start, I);
41314fbfa1STim Northover     return true;
42314fbfa1STim Northover   }
43314fbfa1STim Northover 
44314fbfa1STim Northover   // Special case: ']' is the first character.
45314fbfa1STim Northover   if (*I == ']') {
46314fbfa1STim Northover     if (++I == E) {
47314fbfa1STim Northover       H.HandleIncompleteScanList(start, I - 1);
48314fbfa1STim Northover       return true;
49314fbfa1STim Northover     }
50314fbfa1STim Northover   }
51314fbfa1STim Northover 
52314fbfa1STim Northover   // Special case: "^]" are the first characters.
53314fbfa1STim Northover   if (I + 1 != E && I[0] == '^' && I[1] == ']') {
54314fbfa1STim Northover     I += 2;
55314fbfa1STim Northover     if (I == E) {
56314fbfa1STim Northover       H.HandleIncompleteScanList(start, I - 1);
57314fbfa1STim Northover       return true;
58314fbfa1STim Northover     }
59314fbfa1STim Northover   }
60314fbfa1STim Northover 
61314fbfa1STim Northover   // Look for a ']' character which denotes the end of the scan list.
62314fbfa1STim Northover   while (*I != ']') {
63314fbfa1STim Northover     if (++I == E) {
64314fbfa1STim Northover       H.HandleIncompleteScanList(start, I - 1);
65314fbfa1STim Northover       return true;
66314fbfa1STim Northover     }
67314fbfa1STim Northover   }
68314fbfa1STim Northover 
69314fbfa1STim Northover   CS.setEndScanList(I);
70314fbfa1STim Northover   return false;
71314fbfa1STim Northover }
72314fbfa1STim Northover 
73314fbfa1STim Northover // FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
74314fbfa1STim Northover // We can possibly refactor.
ParseScanfSpecifier(FormatStringHandler & H,const char * & Beg,const char * E,unsigned & argIndex,const LangOptions & LO,const TargetInfo & Target)75314fbfa1STim Northover static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
76314fbfa1STim Northover                                                 const char *&Beg,
77314fbfa1STim Northover                                                 const char *E,
78314fbfa1STim Northover                                                 unsigned &argIndex,
79314fbfa1STim Northover                                                 const LangOptions &LO,
80314fbfa1STim Northover                                                 const TargetInfo &Target) {
81314fbfa1STim Northover   using namespace clang::analyze_format_string;
82314fbfa1STim Northover   using namespace clang::analyze_scanf;
83314fbfa1STim Northover   const char *I = Beg;
84314fbfa1STim Northover   const char *Start = nullptr;
85314fbfa1STim Northover   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
86314fbfa1STim Northover 
87314fbfa1STim Northover     // Look for a '%' character that indicates the start of a format specifier.
88314fbfa1STim Northover   for ( ; I != E ; ++I) {
89314fbfa1STim Northover     char c = *I;
90314fbfa1STim Northover     if (c == '\0') {
91314fbfa1STim Northover         // Detect spurious null characters, which are likely errors.
92314fbfa1STim Northover       H.HandleNullChar(I);
93314fbfa1STim Northover       return true;
94314fbfa1STim Northover     }
95314fbfa1STim Northover     if (c == '%') {
96314fbfa1STim Northover       Start = I++;  // Record the start of the format specifier.
97314fbfa1STim Northover       break;
98314fbfa1STim Northover     }
99314fbfa1STim Northover   }
100314fbfa1STim Northover 
101314fbfa1STim Northover     // No format specifier found?
102314fbfa1STim Northover   if (!Start)
103314fbfa1STim Northover     return false;
104314fbfa1STim Northover 
105314fbfa1STim Northover   if (I == E) {
106314fbfa1STim Northover       // No more characters left?
107314fbfa1STim Northover     H.HandleIncompleteSpecifier(Start, E - Start);
108314fbfa1STim Northover     return true;
109314fbfa1STim Northover   }
110314fbfa1STim Northover 
111314fbfa1STim Northover   ScanfSpecifier FS;
112314fbfa1STim Northover   if (ParseArgPosition(H, FS, Start, I, E))
113314fbfa1STim Northover     return true;
114314fbfa1STim Northover 
115314fbfa1STim Northover   if (I == E) {
116314fbfa1STim Northover       // No more characters left?
117314fbfa1STim Northover     H.HandleIncompleteSpecifier(Start, E - Start);
118314fbfa1STim Northover     return true;
119314fbfa1STim Northover   }
120314fbfa1STim Northover 
121314fbfa1STim Northover   // Look for '*' flag if it is present.
122314fbfa1STim Northover   if (*I == '*') {
123314fbfa1STim Northover     FS.setSuppressAssignment(I);
124314fbfa1STim Northover     if (++I == E) {
125314fbfa1STim Northover       H.HandleIncompleteSpecifier(Start, E - Start);
126314fbfa1STim Northover       return true;
127314fbfa1STim Northover     }
128314fbfa1STim Northover   }
129314fbfa1STim Northover 
130314fbfa1STim Northover   // Look for the field width (if any).  Unlike printf, this is either
131314fbfa1STim Northover   // a fixed integer or isn't present.
132314fbfa1STim Northover   const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
133314fbfa1STim Northover   if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
134314fbfa1STim Northover     assert(Amt.getHowSpecified() == OptionalAmount::Constant);
135314fbfa1STim Northover     FS.setFieldWidth(Amt);
136314fbfa1STim Northover 
137314fbfa1STim Northover     if (I == E) {
138314fbfa1STim Northover       // No more characters left?
139314fbfa1STim Northover       H.HandleIncompleteSpecifier(Start, E - Start);
140314fbfa1STim Northover       return true;
141314fbfa1STim Northover     }
142314fbfa1STim Northover   }
143314fbfa1STim Northover 
144314fbfa1STim Northover   // Look for the length modifier.
14549a3ad21SRui Ueyama   if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) {
146314fbfa1STim Northover       // No more characters left?
147314fbfa1STim Northover     H.HandleIncompleteSpecifier(Start, E - Start);
148314fbfa1STim Northover     return true;
149314fbfa1STim Northover   }
150314fbfa1STim Northover 
151314fbfa1STim Northover   // Detect spurious null characters, which are likely errors.
152314fbfa1STim Northover   if (*I == '\0') {
153314fbfa1STim Northover     H.HandleNullChar(I);
154314fbfa1STim Northover     return true;
155314fbfa1STim Northover   }
156314fbfa1STim Northover 
157314fbfa1STim Northover   // Finally, look for the conversion specifier.
158314fbfa1STim Northover   const char *conversionPosition = I++;
159314fbfa1STim Northover   ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
160314fbfa1STim Northover   switch (*conversionPosition) {
161314fbfa1STim Northover     default:
162314fbfa1STim Northover       break;
163314fbfa1STim Northover     case '%': k = ConversionSpecifier::PercentArg;   break;
164314fbfa1STim Northover     case 'A': k = ConversionSpecifier::AArg; break;
165314fbfa1STim Northover     case 'E': k = ConversionSpecifier::EArg; break;
166314fbfa1STim Northover     case 'F': k = ConversionSpecifier::FArg; break;
167314fbfa1STim Northover     case 'G': k = ConversionSpecifier::GArg; break;
168314fbfa1STim Northover     case 'X': k = ConversionSpecifier::XArg; break;
169314fbfa1STim Northover     case 'a': k = ConversionSpecifier::aArg; break;
170314fbfa1STim Northover     case 'd': k = ConversionSpecifier::dArg; break;
171314fbfa1STim Northover     case 'e': k = ConversionSpecifier::eArg; break;
172314fbfa1STim Northover     case 'f': k = ConversionSpecifier::fArg; break;
173314fbfa1STim Northover     case 'g': k = ConversionSpecifier::gArg; break;
174314fbfa1STim Northover     case 'i': k = ConversionSpecifier::iArg; break;
175314fbfa1STim Northover     case 'n': k = ConversionSpecifier::nArg; break;
176314fbfa1STim Northover     case 'c': k = ConversionSpecifier::cArg; break;
177314fbfa1STim Northover     case 'C': k = ConversionSpecifier::CArg; break;
178314fbfa1STim Northover     case 'S': k = ConversionSpecifier::SArg; break;
179314fbfa1STim Northover     case '[': k = ConversionSpecifier::ScanListArg; break;
180314fbfa1STim Northover     case 'u': k = ConversionSpecifier::uArg; break;
181314fbfa1STim Northover     case 'x': k = ConversionSpecifier::xArg; break;
182314fbfa1STim Northover     case 'o': k = ConversionSpecifier::oArg; break;
183314fbfa1STim Northover     case 's': k = ConversionSpecifier::sArg; break;
184314fbfa1STim Northover     case 'p': k = ConversionSpecifier::pArg; break;
185314fbfa1STim Northover     // Apple extensions
186314fbfa1STim Northover       // Apple-specific
187314fbfa1STim Northover     case 'D':
188314fbfa1STim Northover       if (Target.getTriple().isOSDarwin())
189314fbfa1STim Northover         k = ConversionSpecifier::DArg;
190314fbfa1STim Northover       break;
191314fbfa1STim Northover     case 'O':
192314fbfa1STim Northover       if (Target.getTriple().isOSDarwin())
193314fbfa1STim Northover         k = ConversionSpecifier::OArg;
194314fbfa1STim Northover       break;
195314fbfa1STim Northover     case 'U':
196314fbfa1STim Northover       if (Target.getTriple().isOSDarwin())
197314fbfa1STim Northover         k = ConversionSpecifier::UArg;
198314fbfa1STim Northover       break;
199314fbfa1STim Northover   }
200314fbfa1STim Northover   ScanfConversionSpecifier CS(conversionPosition, k);
201314fbfa1STim Northover   if (k == ScanfConversionSpecifier::ScanListArg) {
202314fbfa1STim Northover     if (ParseScanList(H, CS, I, E))
203314fbfa1STim Northover       return true;
204314fbfa1STim Northover   }
205314fbfa1STim Northover   FS.setConversionSpecifier(CS);
206314fbfa1STim Northover   if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
207314fbfa1STim Northover       && !FS.usesPositionalArg())
208314fbfa1STim Northover     FS.setArgIndex(argIndex++);
209314fbfa1STim Northover 
210314fbfa1STim Northover   // FIXME: '%' and '*' doesn't make sense.  Issue a warning.
211314fbfa1STim Northover   // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
212314fbfa1STim Northover 
213314fbfa1STim Northover   if (k == ScanfConversionSpecifier::InvalidSpecifier) {
214314fbfa1STim Northover     unsigned Len = I - Beg;
215314fbfa1STim Northover     if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
216314fbfa1STim Northover       CS.setEndScanList(Beg + Len);
217314fbfa1STim Northover       FS.setConversionSpecifier(CS);
218314fbfa1STim Northover     }
219314fbfa1STim Northover     // Assume the conversion takes one argument.
220314fbfa1STim Northover     return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
221314fbfa1STim Northover   }
222314fbfa1STim Northover   return ScanfSpecifierResult(Start, FS);
223314fbfa1STim Northover }
224314fbfa1STim Northover 
getArgType(ASTContext & Ctx) const225314fbfa1STim Northover ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
226314fbfa1STim Northover   const ScanfConversionSpecifier &CS = getConversionSpecifier();
227314fbfa1STim Northover 
228314fbfa1STim Northover   if (!CS.consumesDataArgument())
229314fbfa1STim Northover     return ArgType::Invalid();
230314fbfa1STim Northover 
231314fbfa1STim Northover   switch(CS.getKind()) {
232314fbfa1STim Northover     // Signed int.
233314fbfa1STim Northover     case ConversionSpecifier::dArg:
234314fbfa1STim Northover     case ConversionSpecifier::DArg:
235314fbfa1STim Northover     case ConversionSpecifier::iArg:
236314fbfa1STim Northover       switch (LM.getKind()) {
237314fbfa1STim Northover         case LengthModifier::None:
238314fbfa1STim Northover           return ArgType::PtrTo(Ctx.IntTy);
239314fbfa1STim Northover         case LengthModifier::AsChar:
240314fbfa1STim Northover           return ArgType::PtrTo(ArgType::AnyCharTy);
241314fbfa1STim Northover         case LengthModifier::AsShort:
242314fbfa1STim Northover           return ArgType::PtrTo(Ctx.ShortTy);
243314fbfa1STim Northover         case LengthModifier::AsLong:
244314fbfa1STim Northover           return ArgType::PtrTo(Ctx.LongTy);
245314fbfa1STim Northover         case LengthModifier::AsLongLong:
246314fbfa1STim Northover         case LengthModifier::AsQuad:
247314fbfa1STim Northover           return ArgType::PtrTo(Ctx.LongLongTy);
248314fbfa1STim Northover         case LengthModifier::AsInt64:
249314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
250314fbfa1STim Northover         case LengthModifier::AsIntMax:
251314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
252314fbfa1STim Northover         case LengthModifier::AsSizeT:
253314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
254314fbfa1STim Northover         case LengthModifier::AsPtrDiff:
255314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
256314fbfa1STim Northover         case LengthModifier::AsLongDouble:
257314fbfa1STim Northover           // GNU extension.
258314fbfa1STim Northover           return ArgType::PtrTo(Ctx.LongLongTy);
259314fbfa1STim Northover         case LengthModifier::AsAllocate:
260314fbfa1STim Northover         case LengthModifier::AsMAllocate:
261314fbfa1STim Northover         case LengthModifier::AsInt32:
262314fbfa1STim Northover         case LengthModifier::AsInt3264:
263314fbfa1STim Northover         case LengthModifier::AsWide:
26458fc8082SMatt Arsenault         case LengthModifier::AsShortLong:
265314fbfa1STim Northover           return ArgType::Invalid();
266314fbfa1STim Northover       }
26758fc8082SMatt Arsenault       llvm_unreachable("Unsupported LengthModifier Type");
268314fbfa1STim Northover 
269314fbfa1STim Northover     // Unsigned int.
270314fbfa1STim Northover     case ConversionSpecifier::oArg:
271314fbfa1STim Northover     case ConversionSpecifier::OArg:
272314fbfa1STim Northover     case ConversionSpecifier::uArg:
273314fbfa1STim Northover     case ConversionSpecifier::UArg:
274314fbfa1STim Northover     case ConversionSpecifier::xArg:
275314fbfa1STim Northover     case ConversionSpecifier::XArg:
276314fbfa1STim Northover       switch (LM.getKind()) {
277314fbfa1STim Northover         case LengthModifier::None:
278314fbfa1STim Northover           return ArgType::PtrTo(Ctx.UnsignedIntTy);
279314fbfa1STim Northover         case LengthModifier::AsChar:
280314fbfa1STim Northover           return ArgType::PtrTo(Ctx.UnsignedCharTy);
281314fbfa1STim Northover         case LengthModifier::AsShort:
282314fbfa1STim Northover           return ArgType::PtrTo(Ctx.UnsignedShortTy);
283314fbfa1STim Northover         case LengthModifier::AsLong:
284314fbfa1STim Northover           return ArgType::PtrTo(Ctx.UnsignedLongTy);
285314fbfa1STim Northover         case LengthModifier::AsLongLong:
286314fbfa1STim Northover         case LengthModifier::AsQuad:
287314fbfa1STim Northover           return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
288314fbfa1STim Northover         case LengthModifier::AsInt64:
289314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
290314fbfa1STim Northover         case LengthModifier::AsIntMax:
291314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
292314fbfa1STim Northover         case LengthModifier::AsSizeT:
293314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
294314fbfa1STim Northover         case LengthModifier::AsPtrDiff:
295314fbfa1STim Northover           return ArgType::PtrTo(
296314fbfa1STim Northover               ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
297314fbfa1STim Northover         case LengthModifier::AsLongDouble:
298314fbfa1STim Northover           // GNU extension.
299314fbfa1STim Northover           return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
300314fbfa1STim Northover         case LengthModifier::AsAllocate:
301314fbfa1STim Northover         case LengthModifier::AsMAllocate:
302314fbfa1STim Northover         case LengthModifier::AsInt32:
303314fbfa1STim Northover         case LengthModifier::AsInt3264:
304314fbfa1STim Northover         case LengthModifier::AsWide:
30558fc8082SMatt Arsenault         case LengthModifier::AsShortLong:
306314fbfa1STim Northover           return ArgType::Invalid();
307314fbfa1STim Northover       }
30858fc8082SMatt Arsenault       llvm_unreachable("Unsupported LengthModifier Type");
309314fbfa1STim Northover 
310314fbfa1STim Northover     // Float.
311314fbfa1STim Northover     case ConversionSpecifier::aArg:
312314fbfa1STim Northover     case ConversionSpecifier::AArg:
313314fbfa1STim Northover     case ConversionSpecifier::eArg:
314314fbfa1STim Northover     case ConversionSpecifier::EArg:
315314fbfa1STim Northover     case ConversionSpecifier::fArg:
316314fbfa1STim Northover     case ConversionSpecifier::FArg:
317314fbfa1STim Northover     case ConversionSpecifier::gArg:
318314fbfa1STim Northover     case ConversionSpecifier::GArg:
319314fbfa1STim Northover       switch (LM.getKind()) {
320314fbfa1STim Northover         case LengthModifier::None:
321314fbfa1STim Northover           return ArgType::PtrTo(Ctx.FloatTy);
322314fbfa1STim Northover         case LengthModifier::AsLong:
323314fbfa1STim Northover           return ArgType::PtrTo(Ctx.DoubleTy);
324314fbfa1STim Northover         case LengthModifier::AsLongDouble:
325314fbfa1STim Northover           return ArgType::PtrTo(Ctx.LongDoubleTy);
326314fbfa1STim Northover         default:
327314fbfa1STim Northover           return ArgType::Invalid();
328314fbfa1STim Northover       }
329314fbfa1STim Northover 
330314fbfa1STim Northover     // Char, string and scanlist.
331314fbfa1STim Northover     case ConversionSpecifier::cArg:
332314fbfa1STim Northover     case ConversionSpecifier::sArg:
333314fbfa1STim Northover     case ConversionSpecifier::ScanListArg:
334314fbfa1STim Northover       switch (LM.getKind()) {
335314fbfa1STim Northover         case LengthModifier::None:
336314fbfa1STim Northover           return ArgType::PtrTo(ArgType::AnyCharTy);
337314fbfa1STim Northover         case LengthModifier::AsLong:
338314fbfa1STim Northover         case LengthModifier::AsWide:
339314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
340314fbfa1STim Northover         case LengthModifier::AsAllocate:
341314fbfa1STim Northover         case LengthModifier::AsMAllocate:
342314fbfa1STim Northover           return ArgType::PtrTo(ArgType::CStrTy);
343314fbfa1STim Northover         case LengthModifier::AsShort:
344314fbfa1STim Northover           if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
345314fbfa1STim Northover             return ArgType::PtrTo(ArgType::AnyCharTy);
346314fbfa1STim Northover           LLVM_FALLTHROUGH;
347314fbfa1STim Northover         default:
348314fbfa1STim Northover           return ArgType::Invalid();
349314fbfa1STim Northover       }
350314fbfa1STim Northover     case ConversionSpecifier::CArg:
351314fbfa1STim Northover     case ConversionSpecifier::SArg:
352314fbfa1STim Northover       // FIXME: Mac OS X specific?
353314fbfa1STim Northover       switch (LM.getKind()) {
354314fbfa1STim Northover         case LengthModifier::None:
355314fbfa1STim Northover         case LengthModifier::AsWide:
356314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
357314fbfa1STim Northover         case LengthModifier::AsAllocate:
358314fbfa1STim Northover         case LengthModifier::AsMAllocate:
359314fbfa1STim Northover           return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
360314fbfa1STim Northover         case LengthModifier::AsShort:
361314fbfa1STim Northover           if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
362314fbfa1STim Northover             return ArgType::PtrTo(ArgType::AnyCharTy);
363314fbfa1STim Northover           LLVM_FALLTHROUGH;
364314fbfa1STim Northover         default:
365314fbfa1STim Northover           return ArgType::Invalid();
366314fbfa1STim Northover       }
367314fbfa1STim Northover 
368314fbfa1STim Northover     // Pointer.
369314fbfa1STim Northover     case ConversionSpecifier::pArg:
370314fbfa1STim Northover       return ArgType::PtrTo(ArgType::CPointerTy);
371314fbfa1STim Northover 
372314fbfa1STim Northover     // Write-back.
373314fbfa1STim Northover     case ConversionSpecifier::nArg:
374314fbfa1STim Northover       switch (LM.getKind()) {
375314fbfa1STim Northover         case LengthModifier::None:
376314fbfa1STim Northover           return ArgType::PtrTo(Ctx.IntTy);
377314fbfa1STim Northover         case LengthModifier::AsChar:
378314fbfa1STim Northover           return ArgType::PtrTo(Ctx.SignedCharTy);
379314fbfa1STim Northover         case LengthModifier::AsShort:
380314fbfa1STim Northover           return ArgType::PtrTo(Ctx.ShortTy);
381314fbfa1STim Northover         case LengthModifier::AsLong:
382314fbfa1STim Northover           return ArgType::PtrTo(Ctx.LongTy);
383314fbfa1STim Northover         case LengthModifier::AsLongLong:
384314fbfa1STim Northover         case LengthModifier::AsQuad:
385314fbfa1STim Northover           return ArgType::PtrTo(Ctx.LongLongTy);
386314fbfa1STim Northover         case LengthModifier::AsInt64:
387314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
388314fbfa1STim Northover         case LengthModifier::AsIntMax:
389314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
390314fbfa1STim Northover         case LengthModifier::AsSizeT:
391314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
392314fbfa1STim Northover         case LengthModifier::AsPtrDiff:
393314fbfa1STim Northover           return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
394314fbfa1STim Northover         case LengthModifier::AsLongDouble:
395314fbfa1STim Northover           return ArgType(); // FIXME: Is this a known extension?
396314fbfa1STim Northover         case LengthModifier::AsAllocate:
397314fbfa1STim Northover         case LengthModifier::AsMAllocate:
398314fbfa1STim Northover         case LengthModifier::AsInt32:
399314fbfa1STim Northover         case LengthModifier::AsInt3264:
400314fbfa1STim Northover         case LengthModifier::AsWide:
40158fc8082SMatt Arsenault         case LengthModifier::AsShortLong:
402314fbfa1STim Northover           return ArgType::Invalid();
403314fbfa1STim Northover         }
404314fbfa1STim Northover 
405314fbfa1STim Northover     default:
406314fbfa1STim Northover       break;
407314fbfa1STim Northover   }
408314fbfa1STim Northover 
409314fbfa1STim Northover   return ArgType();
410314fbfa1STim Northover }
411314fbfa1STim Northover 
fixType(QualType QT,QualType RawQT,const LangOptions & LangOpt,ASTContext & Ctx)412314fbfa1STim Northover bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
413314fbfa1STim Northover                              const LangOptions &LangOpt,
414314fbfa1STim Northover                              ASTContext &Ctx) {
415314fbfa1STim Northover 
416314fbfa1STim Northover   // %n is different from other conversion specifiers; don't try to fix it.
417314fbfa1STim Northover   if (CS.getKind() == ConversionSpecifier::nArg)
418314fbfa1STim Northover     return false;
419314fbfa1STim Northover 
420314fbfa1STim Northover   if (!QT->isPointerType())
421314fbfa1STim Northover     return false;
422314fbfa1STim Northover 
423314fbfa1STim Northover   QualType PT = QT->getPointeeType();
424314fbfa1STim Northover 
425314fbfa1STim Northover   // If it's an enum, get its underlying type.
426314fbfa1STim Northover   if (const EnumType *ETy = PT->getAs<EnumType>()) {
427314fbfa1STim Northover     // Don't try to fix incomplete enums.
428314fbfa1STim Northover     if (!ETy->getDecl()->isComplete())
429314fbfa1STim Northover       return false;
430314fbfa1STim Northover     PT = ETy->getDecl()->getIntegerType();
431314fbfa1STim Northover   }
432314fbfa1STim Northover 
433314fbfa1STim Northover   const BuiltinType *BT = PT->getAs<BuiltinType>();
434314fbfa1STim Northover   if (!BT)
435314fbfa1STim Northover     return false;
436314fbfa1STim Northover 
437314fbfa1STim Northover   // Pointer to a character.
438314fbfa1STim Northover   if (PT->isAnyCharacterType()) {
439314fbfa1STim Northover     CS.setKind(ConversionSpecifier::sArg);
440314fbfa1STim Northover     if (PT->isWideCharType())
441314fbfa1STim Northover       LM.setKind(LengthModifier::AsWideChar);
442314fbfa1STim Northover     else
443314fbfa1STim Northover       LM.setKind(LengthModifier::None);
444314fbfa1STim Northover 
445314fbfa1STim Northover     // If we know the target array length, we can use it as a field width.
446314fbfa1STim Northover     if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
447314fbfa1STim Northover       if (CAT->getSizeModifier() == ArrayType::Normal)
448314fbfa1STim Northover         FieldWidth = OptionalAmount(OptionalAmount::Constant,
449314fbfa1STim Northover                                     CAT->getSize().getZExtValue() - 1,
450314fbfa1STim Northover                                     "", 0, false);
451314fbfa1STim Northover 
452314fbfa1STim Northover     }
453314fbfa1STim Northover     return true;
454314fbfa1STim Northover   }
455314fbfa1STim Northover 
456314fbfa1STim Northover   // Figure out the length modifier.
457314fbfa1STim Northover   switch (BT->getKind()) {
458314fbfa1STim Northover     // no modifier
459314fbfa1STim Northover     case BuiltinType::UInt:
460314fbfa1STim Northover     case BuiltinType::Int:
461314fbfa1STim Northover     case BuiltinType::Float:
462314fbfa1STim Northover       LM.setKind(LengthModifier::None);
463314fbfa1STim Northover       break;
464314fbfa1STim Northover 
465314fbfa1STim Northover     // hh
466314fbfa1STim Northover     case BuiltinType::Char_U:
467314fbfa1STim Northover     case BuiltinType::UChar:
468314fbfa1STim Northover     case BuiltinType::Char_S:
469314fbfa1STim Northover     case BuiltinType::SChar:
470314fbfa1STim Northover       LM.setKind(LengthModifier::AsChar);
471314fbfa1STim Northover       break;
472314fbfa1STim Northover 
473314fbfa1STim Northover     // h
474314fbfa1STim Northover     case BuiltinType::Short:
475314fbfa1STim Northover     case BuiltinType::UShort:
476314fbfa1STim Northover       LM.setKind(LengthModifier::AsShort);
477314fbfa1STim Northover       break;
478314fbfa1STim Northover 
479314fbfa1STim Northover     // l
480314fbfa1STim Northover     case BuiltinType::Long:
481314fbfa1STim Northover     case BuiltinType::ULong:
482314fbfa1STim Northover     case BuiltinType::Double:
483314fbfa1STim Northover       LM.setKind(LengthModifier::AsLong);
484314fbfa1STim Northover       break;
485314fbfa1STim Northover 
486314fbfa1STim Northover     // ll
487314fbfa1STim Northover     case BuiltinType::LongLong:
488314fbfa1STim Northover     case BuiltinType::ULongLong:
489314fbfa1STim Northover       LM.setKind(LengthModifier::AsLongLong);
490314fbfa1STim Northover       break;
491314fbfa1STim Northover 
492314fbfa1STim Northover     // L
493314fbfa1STim Northover     case BuiltinType::LongDouble:
494314fbfa1STim Northover       LM.setKind(LengthModifier::AsLongDouble);
495314fbfa1STim Northover       break;
496314fbfa1STim Northover 
497314fbfa1STim Northover     // Don't know.
498314fbfa1STim Northover     default:
499314fbfa1STim Northover       return false;
500314fbfa1STim Northover   }
501314fbfa1STim Northover 
502314fbfa1STim Northover   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
503*888673b6SJonas Devlieghere   if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
504314fbfa1STim Northover     namedTypeToLengthModifier(PT, LM);
505314fbfa1STim Northover 
506314fbfa1STim Northover   // If fixing the length modifier was enough, we are done.
50758fc8082SMatt Arsenault   if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
508314fbfa1STim Northover     const analyze_scanf::ArgType &AT = getArgType(Ctx);
509314fbfa1STim Northover     if (AT.isValid() && AT.matchesType(Ctx, QT))
510314fbfa1STim Northover       return true;
511314fbfa1STim Northover   }
512314fbfa1STim Northover 
513314fbfa1STim Northover   // Figure out the conversion specifier.
514314fbfa1STim Northover   if (PT->isRealFloatingType())
515314fbfa1STim Northover     CS.setKind(ConversionSpecifier::fArg);
516314fbfa1STim Northover   else if (PT->isSignedIntegerType())
517314fbfa1STim Northover     CS.setKind(ConversionSpecifier::dArg);
518314fbfa1STim Northover   else if (PT->isUnsignedIntegerType())
519314fbfa1STim Northover     CS.setKind(ConversionSpecifier::uArg);
520314fbfa1STim Northover   else
521314fbfa1STim Northover     llvm_unreachable("Unexpected type");
522314fbfa1STim Northover 
523314fbfa1STim Northover   return true;
524314fbfa1STim Northover }
525314fbfa1STim Northover 
toString(raw_ostream & os) const526314fbfa1STim Northover void ScanfSpecifier::toString(raw_ostream &os) const {
527314fbfa1STim Northover   os << "%";
528314fbfa1STim Northover 
529314fbfa1STim Northover   if (usesPositionalArg())
530314fbfa1STim Northover     os << getPositionalArgIndex() << "$";
531314fbfa1STim Northover   if (SuppressAssignment)
532314fbfa1STim Northover     os << "*";
533314fbfa1STim Northover 
534314fbfa1STim Northover   FieldWidth.toString(os);
535314fbfa1STim Northover   os << LM.toString();
536314fbfa1STim Northover   os << CS.toString();
537314fbfa1STim Northover }
538314fbfa1STim Northover 
ParseScanfString(FormatStringHandler & H,const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)539314fbfa1STim Northover bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
540314fbfa1STim Northover                                                     const char *I,
541314fbfa1STim Northover                                                     const char *E,
542314fbfa1STim Northover                                                     const LangOptions &LO,
543314fbfa1STim Northover                                                     const TargetInfo &Target) {
544314fbfa1STim Northover 
545314fbfa1STim Northover   unsigned argIndex = 0;
546314fbfa1STim Northover 
547314fbfa1STim Northover   // Keep looking for a format specifier until we have exhausted the string.
548314fbfa1STim Northover   while (I != E) {
549314fbfa1STim Northover     const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
550314fbfa1STim Northover                                                           LO, Target);
551314fbfa1STim Northover     // Did a fail-stop error of any kind occur when parsing the specifier?
552314fbfa1STim Northover     // If so, don't do any more processing.
553314fbfa1STim Northover     if (FSR.shouldStop())
554314fbfa1STim Northover       return true;
555314fbfa1STim Northover       // Did we exhaust the string or encounter an error that
556314fbfa1STim Northover       // we can recover from?
557314fbfa1STim Northover     if (!FSR.hasValue())
558314fbfa1STim Northover       continue;
559314fbfa1STim Northover       // We have a format specifier.  Pass it to the callback.
560314fbfa1STim Northover     if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
561314fbfa1STim Northover                                 I - FSR.getStart())) {
562314fbfa1STim Northover       return true;
563314fbfa1STim Northover     }
564314fbfa1STim Northover   }
565314fbfa1STim Northover   assert(I == E && "Format string not exhausted");
566314fbfa1STim Northover   return false;
567314fbfa1STim Northover }
568