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