xref: /openbsd-src/gnu/llvm/clang/lib/AST/ScanfFormatString.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Handling of format string in scanf and friends.  The structure of format
10e5dd7070Spatrick // strings for fscanf() are described in C99 7.19.6.2.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick 
14e5dd7070Spatrick #include "clang/AST/FormatString.h"
15e5dd7070Spatrick #include "FormatStringParsing.h"
16e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
17e5dd7070Spatrick 
18e5dd7070Spatrick using clang::analyze_format_string::ArgType;
19e5dd7070Spatrick using clang::analyze_format_string::FormatStringHandler;
20e5dd7070Spatrick using clang::analyze_format_string::LengthModifier;
21e5dd7070Spatrick using clang::analyze_format_string::OptionalAmount;
22e5dd7070Spatrick using clang::analyze_format_string::ConversionSpecifier;
23e5dd7070Spatrick using clang::analyze_scanf::ScanfConversionSpecifier;
24e5dd7070Spatrick using clang::analyze_scanf::ScanfSpecifier;
25e5dd7070Spatrick using clang::UpdateOnReturn;
26e5dd7070Spatrick using namespace clang;
27e5dd7070Spatrick 
28e5dd7070Spatrick typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
29e5dd7070Spatrick         ScanfSpecifierResult;
30e5dd7070Spatrick 
ParseScanList(FormatStringHandler & H,ScanfConversionSpecifier & CS,const char * & Beg,const char * E)31e5dd7070Spatrick static bool ParseScanList(FormatStringHandler &H,
32e5dd7070Spatrick                           ScanfConversionSpecifier &CS,
33e5dd7070Spatrick                           const char *&Beg, const char *E) {
34e5dd7070Spatrick   const char *I = Beg;
35e5dd7070Spatrick   const char *start = I - 1;
36e5dd7070Spatrick   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
37e5dd7070Spatrick 
38e5dd7070Spatrick   // No more characters?
39e5dd7070Spatrick   if (I == E) {
40e5dd7070Spatrick     H.HandleIncompleteScanList(start, I);
41e5dd7070Spatrick     return true;
42e5dd7070Spatrick   }
43e5dd7070Spatrick 
44e5dd7070Spatrick   // Special case: ']' is the first character.
45e5dd7070Spatrick   if (*I == ']') {
46e5dd7070Spatrick     if (++I == E) {
47e5dd7070Spatrick       H.HandleIncompleteScanList(start, I - 1);
48e5dd7070Spatrick       return true;
49e5dd7070Spatrick     }
50e5dd7070Spatrick   }
51e5dd7070Spatrick 
52e5dd7070Spatrick   // Special case: "^]" are the first characters.
53e5dd7070Spatrick   if (I + 1 != E && I[0] == '^' && I[1] == ']') {
54e5dd7070Spatrick     I += 2;
55e5dd7070Spatrick     if (I == E) {
56e5dd7070Spatrick       H.HandleIncompleteScanList(start, I - 1);
57e5dd7070Spatrick       return true;
58e5dd7070Spatrick     }
59e5dd7070Spatrick   }
60e5dd7070Spatrick 
61e5dd7070Spatrick   // Look for a ']' character which denotes the end of the scan list.
62e5dd7070Spatrick   while (*I != ']') {
63e5dd7070Spatrick     if (++I == E) {
64e5dd7070Spatrick       H.HandleIncompleteScanList(start, I - 1);
65e5dd7070Spatrick       return true;
66e5dd7070Spatrick     }
67e5dd7070Spatrick   }
68e5dd7070Spatrick 
69e5dd7070Spatrick   CS.setEndScanList(I);
70e5dd7070Spatrick   return false;
71e5dd7070Spatrick }
72e5dd7070Spatrick 
73e5dd7070Spatrick // FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
74e5dd7070Spatrick // We can possibly refactor.
ParseScanfSpecifier(FormatStringHandler & H,const char * & Beg,const char * E,unsigned & argIndex,const LangOptions & LO,const TargetInfo & Target)75e5dd7070Spatrick static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
76e5dd7070Spatrick                                                 const char *&Beg,
77e5dd7070Spatrick                                                 const char *E,
78e5dd7070Spatrick                                                 unsigned &argIndex,
79e5dd7070Spatrick                                                 const LangOptions &LO,
80e5dd7070Spatrick                                                 const TargetInfo &Target) {
81e5dd7070Spatrick   using namespace clang::analyze_format_string;
82e5dd7070Spatrick   using namespace clang::analyze_scanf;
83e5dd7070Spatrick   const char *I = Beg;
84e5dd7070Spatrick   const char *Start = nullptr;
85e5dd7070Spatrick   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
86e5dd7070Spatrick 
87e5dd7070Spatrick     // Look for a '%' character that indicates the start of a format specifier.
88e5dd7070Spatrick   for ( ; I != E ; ++I) {
89e5dd7070Spatrick     char c = *I;
90e5dd7070Spatrick     if (c == '\0') {
91e5dd7070Spatrick         // Detect spurious null characters, which are likely errors.
92e5dd7070Spatrick       H.HandleNullChar(I);
93e5dd7070Spatrick       return true;
94e5dd7070Spatrick     }
95e5dd7070Spatrick     if (c == '%') {
96e5dd7070Spatrick       Start = I++;  // Record the start of the format specifier.
97e5dd7070Spatrick       break;
98e5dd7070Spatrick     }
99e5dd7070Spatrick   }
100e5dd7070Spatrick 
101e5dd7070Spatrick     // No format specifier found?
102e5dd7070Spatrick   if (!Start)
103e5dd7070Spatrick     return false;
104e5dd7070Spatrick 
105e5dd7070Spatrick   if (I == E) {
106e5dd7070Spatrick       // No more characters left?
107e5dd7070Spatrick     H.HandleIncompleteSpecifier(Start, E - Start);
108e5dd7070Spatrick     return true;
109e5dd7070Spatrick   }
110e5dd7070Spatrick 
111e5dd7070Spatrick   ScanfSpecifier FS;
112e5dd7070Spatrick   if (ParseArgPosition(H, FS, Start, I, E))
113e5dd7070Spatrick     return true;
114e5dd7070Spatrick 
115e5dd7070Spatrick   if (I == E) {
116e5dd7070Spatrick       // No more characters left?
117e5dd7070Spatrick     H.HandleIncompleteSpecifier(Start, E - Start);
118e5dd7070Spatrick     return true;
119e5dd7070Spatrick   }
120e5dd7070Spatrick 
121e5dd7070Spatrick   // Look for '*' flag if it is present.
122e5dd7070Spatrick   if (*I == '*') {
123e5dd7070Spatrick     FS.setSuppressAssignment(I);
124e5dd7070Spatrick     if (++I == E) {
125e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
126e5dd7070Spatrick       return true;
127e5dd7070Spatrick     }
128e5dd7070Spatrick   }
129e5dd7070Spatrick 
130e5dd7070Spatrick   // Look for the field width (if any).  Unlike printf, this is either
131e5dd7070Spatrick   // a fixed integer or isn't present.
132e5dd7070Spatrick   const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
133e5dd7070Spatrick   if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
134e5dd7070Spatrick     assert(Amt.getHowSpecified() == OptionalAmount::Constant);
135e5dd7070Spatrick     FS.setFieldWidth(Amt);
136e5dd7070Spatrick 
137e5dd7070Spatrick     if (I == E) {
138e5dd7070Spatrick       // No more characters left?
139e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
140e5dd7070Spatrick       return true;
141e5dd7070Spatrick     }
142e5dd7070Spatrick   }
143e5dd7070Spatrick 
144e5dd7070Spatrick   // Look for the length modifier.
145e5dd7070Spatrick   if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) {
146e5dd7070Spatrick       // No more characters left?
147e5dd7070Spatrick     H.HandleIncompleteSpecifier(Start, E - Start);
148e5dd7070Spatrick     return true;
149e5dd7070Spatrick   }
150e5dd7070Spatrick 
151e5dd7070Spatrick   // Detect spurious null characters, which are likely errors.
152e5dd7070Spatrick   if (*I == '\0') {
153e5dd7070Spatrick     H.HandleNullChar(I);
154e5dd7070Spatrick     return true;
155e5dd7070Spatrick   }
156e5dd7070Spatrick 
157e5dd7070Spatrick   // Finally, look for the conversion specifier.
158e5dd7070Spatrick   const char *conversionPosition = I++;
159e5dd7070Spatrick   ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
160e5dd7070Spatrick   switch (*conversionPosition) {
161e5dd7070Spatrick     default:
162e5dd7070Spatrick       break;
163e5dd7070Spatrick     case '%': k = ConversionSpecifier::PercentArg;   break;
164*12c85518Srobert     case 'b': k = ConversionSpecifier::bArg; break;
165e5dd7070Spatrick     case 'A': k = ConversionSpecifier::AArg; break;
166e5dd7070Spatrick     case 'E': k = ConversionSpecifier::EArg; break;
167e5dd7070Spatrick     case 'F': k = ConversionSpecifier::FArg; break;
168e5dd7070Spatrick     case 'G': k = ConversionSpecifier::GArg; break;
169e5dd7070Spatrick     case 'X': k = ConversionSpecifier::XArg; break;
170e5dd7070Spatrick     case 'a': k = ConversionSpecifier::aArg; break;
171e5dd7070Spatrick     case 'd': k = ConversionSpecifier::dArg; break;
172e5dd7070Spatrick     case 'e': k = ConversionSpecifier::eArg; break;
173e5dd7070Spatrick     case 'f': k = ConversionSpecifier::fArg; break;
174e5dd7070Spatrick     case 'g': k = ConversionSpecifier::gArg; break;
175e5dd7070Spatrick     case 'i': k = ConversionSpecifier::iArg; break;
176e5dd7070Spatrick     case 'n': k = ConversionSpecifier::nArg; break;
177e5dd7070Spatrick     case 'c': k = ConversionSpecifier::cArg; break;
178e5dd7070Spatrick     case 'C': k = ConversionSpecifier::CArg; break;
179e5dd7070Spatrick     case 'S': k = ConversionSpecifier::SArg; break;
180e5dd7070Spatrick     case '[': k = ConversionSpecifier::ScanListArg; break;
181e5dd7070Spatrick     case 'u': k = ConversionSpecifier::uArg; break;
182e5dd7070Spatrick     case 'x': k = ConversionSpecifier::xArg; break;
183e5dd7070Spatrick     case 'o': k = ConversionSpecifier::oArg; break;
184e5dd7070Spatrick     case 's': k = ConversionSpecifier::sArg; break;
185e5dd7070Spatrick     case 'p': k = ConversionSpecifier::pArg; break;
186e5dd7070Spatrick     // Apple extensions
187e5dd7070Spatrick       // Apple-specific
188e5dd7070Spatrick     case 'D':
189e5dd7070Spatrick       if (Target.getTriple().isOSDarwin())
190e5dd7070Spatrick         k = ConversionSpecifier::DArg;
191e5dd7070Spatrick       break;
192e5dd7070Spatrick     case 'O':
193e5dd7070Spatrick       if (Target.getTriple().isOSDarwin())
194e5dd7070Spatrick         k = ConversionSpecifier::OArg;
195e5dd7070Spatrick       break;
196e5dd7070Spatrick     case 'U':
197e5dd7070Spatrick       if (Target.getTriple().isOSDarwin())
198e5dd7070Spatrick         k = ConversionSpecifier::UArg;
199e5dd7070Spatrick       break;
200e5dd7070Spatrick   }
201e5dd7070Spatrick   ScanfConversionSpecifier CS(conversionPosition, k);
202e5dd7070Spatrick   if (k == ScanfConversionSpecifier::ScanListArg) {
203e5dd7070Spatrick     if (ParseScanList(H, CS, I, E))
204e5dd7070Spatrick       return true;
205e5dd7070Spatrick   }
206e5dd7070Spatrick   FS.setConversionSpecifier(CS);
207e5dd7070Spatrick   if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
208e5dd7070Spatrick       && !FS.usesPositionalArg())
209e5dd7070Spatrick     FS.setArgIndex(argIndex++);
210e5dd7070Spatrick 
211e5dd7070Spatrick   // FIXME: '%' and '*' doesn't make sense.  Issue a warning.
212e5dd7070Spatrick   // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
213e5dd7070Spatrick 
214e5dd7070Spatrick   if (k == ScanfConversionSpecifier::InvalidSpecifier) {
215e5dd7070Spatrick     unsigned Len = I - Beg;
216e5dd7070Spatrick     if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
217e5dd7070Spatrick       CS.setEndScanList(Beg + Len);
218e5dd7070Spatrick       FS.setConversionSpecifier(CS);
219e5dd7070Spatrick     }
220e5dd7070Spatrick     // Assume the conversion takes one argument.
221e5dd7070Spatrick     return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
222e5dd7070Spatrick   }
223e5dd7070Spatrick   return ScanfSpecifierResult(Start, FS);
224e5dd7070Spatrick }
225e5dd7070Spatrick 
getArgType(ASTContext & Ctx) const226e5dd7070Spatrick ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
227e5dd7070Spatrick   const ScanfConversionSpecifier &CS = getConversionSpecifier();
228e5dd7070Spatrick 
229e5dd7070Spatrick   if (!CS.consumesDataArgument())
230e5dd7070Spatrick     return ArgType::Invalid();
231e5dd7070Spatrick 
232e5dd7070Spatrick   switch(CS.getKind()) {
233e5dd7070Spatrick     // Signed int.
234e5dd7070Spatrick     case ConversionSpecifier::dArg:
235e5dd7070Spatrick     case ConversionSpecifier::DArg:
236e5dd7070Spatrick     case ConversionSpecifier::iArg:
237e5dd7070Spatrick       switch (LM.getKind()) {
238e5dd7070Spatrick         case LengthModifier::None:
239e5dd7070Spatrick           return ArgType::PtrTo(Ctx.IntTy);
240e5dd7070Spatrick         case LengthModifier::AsChar:
241e5dd7070Spatrick           return ArgType::PtrTo(ArgType::AnyCharTy);
242e5dd7070Spatrick         case LengthModifier::AsShort:
243e5dd7070Spatrick           return ArgType::PtrTo(Ctx.ShortTy);
244e5dd7070Spatrick         case LengthModifier::AsLong:
245e5dd7070Spatrick           return ArgType::PtrTo(Ctx.LongTy);
246e5dd7070Spatrick         case LengthModifier::AsLongLong:
247e5dd7070Spatrick         case LengthModifier::AsQuad:
248e5dd7070Spatrick           return ArgType::PtrTo(Ctx.LongLongTy);
249e5dd7070Spatrick         case LengthModifier::AsInt64:
250e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
251e5dd7070Spatrick         case LengthModifier::AsIntMax:
252e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
253e5dd7070Spatrick         case LengthModifier::AsSizeT:
254e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
255e5dd7070Spatrick         case LengthModifier::AsPtrDiff:
256e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
257e5dd7070Spatrick         case LengthModifier::AsLongDouble:
258e5dd7070Spatrick           // GNU extension.
259e5dd7070Spatrick           return ArgType::PtrTo(Ctx.LongLongTy);
260e5dd7070Spatrick         case LengthModifier::AsAllocate:
261e5dd7070Spatrick         case LengthModifier::AsMAllocate:
262e5dd7070Spatrick         case LengthModifier::AsInt32:
263e5dd7070Spatrick         case LengthModifier::AsInt3264:
264e5dd7070Spatrick         case LengthModifier::AsWide:
265e5dd7070Spatrick         case LengthModifier::AsShortLong:
266e5dd7070Spatrick           return ArgType::Invalid();
267e5dd7070Spatrick       }
268e5dd7070Spatrick       llvm_unreachable("Unsupported LengthModifier Type");
269e5dd7070Spatrick 
270e5dd7070Spatrick     // Unsigned int.
271*12c85518Srobert     case ConversionSpecifier::bArg:
272e5dd7070Spatrick     case ConversionSpecifier::oArg:
273e5dd7070Spatrick     case ConversionSpecifier::OArg:
274e5dd7070Spatrick     case ConversionSpecifier::uArg:
275e5dd7070Spatrick     case ConversionSpecifier::UArg:
276e5dd7070Spatrick     case ConversionSpecifier::xArg:
277e5dd7070Spatrick     case ConversionSpecifier::XArg:
278e5dd7070Spatrick       switch (LM.getKind()) {
279e5dd7070Spatrick         case LengthModifier::None:
280e5dd7070Spatrick           return ArgType::PtrTo(Ctx.UnsignedIntTy);
281e5dd7070Spatrick         case LengthModifier::AsChar:
282e5dd7070Spatrick           return ArgType::PtrTo(Ctx.UnsignedCharTy);
283e5dd7070Spatrick         case LengthModifier::AsShort:
284e5dd7070Spatrick           return ArgType::PtrTo(Ctx.UnsignedShortTy);
285e5dd7070Spatrick         case LengthModifier::AsLong:
286e5dd7070Spatrick           return ArgType::PtrTo(Ctx.UnsignedLongTy);
287e5dd7070Spatrick         case LengthModifier::AsLongLong:
288e5dd7070Spatrick         case LengthModifier::AsQuad:
289e5dd7070Spatrick           return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
290e5dd7070Spatrick         case LengthModifier::AsInt64:
291e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
292e5dd7070Spatrick         case LengthModifier::AsIntMax:
293e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
294e5dd7070Spatrick         case LengthModifier::AsSizeT:
295e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
296e5dd7070Spatrick         case LengthModifier::AsPtrDiff:
297e5dd7070Spatrick           return ArgType::PtrTo(
298e5dd7070Spatrick               ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
299e5dd7070Spatrick         case LengthModifier::AsLongDouble:
300e5dd7070Spatrick           // GNU extension.
301e5dd7070Spatrick           return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
302e5dd7070Spatrick         case LengthModifier::AsAllocate:
303e5dd7070Spatrick         case LengthModifier::AsMAllocate:
304e5dd7070Spatrick         case LengthModifier::AsInt32:
305e5dd7070Spatrick         case LengthModifier::AsInt3264:
306e5dd7070Spatrick         case LengthModifier::AsWide:
307e5dd7070Spatrick         case LengthModifier::AsShortLong:
308e5dd7070Spatrick           return ArgType::Invalid();
309e5dd7070Spatrick       }
310e5dd7070Spatrick       llvm_unreachable("Unsupported LengthModifier Type");
311e5dd7070Spatrick 
312e5dd7070Spatrick     // Float.
313e5dd7070Spatrick     case ConversionSpecifier::aArg:
314e5dd7070Spatrick     case ConversionSpecifier::AArg:
315e5dd7070Spatrick     case ConversionSpecifier::eArg:
316e5dd7070Spatrick     case ConversionSpecifier::EArg:
317e5dd7070Spatrick     case ConversionSpecifier::fArg:
318e5dd7070Spatrick     case ConversionSpecifier::FArg:
319e5dd7070Spatrick     case ConversionSpecifier::gArg:
320e5dd7070Spatrick     case ConversionSpecifier::GArg:
321e5dd7070Spatrick       switch (LM.getKind()) {
322e5dd7070Spatrick         case LengthModifier::None:
323e5dd7070Spatrick           return ArgType::PtrTo(Ctx.FloatTy);
324e5dd7070Spatrick         case LengthModifier::AsLong:
325e5dd7070Spatrick           return ArgType::PtrTo(Ctx.DoubleTy);
326e5dd7070Spatrick         case LengthModifier::AsLongDouble:
327e5dd7070Spatrick           return ArgType::PtrTo(Ctx.LongDoubleTy);
328e5dd7070Spatrick         default:
329e5dd7070Spatrick           return ArgType::Invalid();
330e5dd7070Spatrick       }
331e5dd7070Spatrick 
332e5dd7070Spatrick     // Char, string and scanlist.
333e5dd7070Spatrick     case ConversionSpecifier::cArg:
334e5dd7070Spatrick     case ConversionSpecifier::sArg:
335e5dd7070Spatrick     case ConversionSpecifier::ScanListArg:
336e5dd7070Spatrick       switch (LM.getKind()) {
337e5dd7070Spatrick         case LengthModifier::None:
338e5dd7070Spatrick           return ArgType::PtrTo(ArgType::AnyCharTy);
339e5dd7070Spatrick         case LengthModifier::AsLong:
340e5dd7070Spatrick         case LengthModifier::AsWide:
341e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
342e5dd7070Spatrick         case LengthModifier::AsAllocate:
343e5dd7070Spatrick         case LengthModifier::AsMAllocate:
344e5dd7070Spatrick           return ArgType::PtrTo(ArgType::CStrTy);
345e5dd7070Spatrick         case LengthModifier::AsShort:
346e5dd7070Spatrick           if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
347e5dd7070Spatrick             return ArgType::PtrTo(ArgType::AnyCharTy);
348*12c85518Srobert           [[fallthrough]];
349e5dd7070Spatrick         default:
350e5dd7070Spatrick           return ArgType::Invalid();
351e5dd7070Spatrick       }
352e5dd7070Spatrick     case ConversionSpecifier::CArg:
353e5dd7070Spatrick     case ConversionSpecifier::SArg:
354e5dd7070Spatrick       // FIXME: Mac OS X specific?
355e5dd7070Spatrick       switch (LM.getKind()) {
356e5dd7070Spatrick         case LengthModifier::None:
357e5dd7070Spatrick         case LengthModifier::AsWide:
358e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
359e5dd7070Spatrick         case LengthModifier::AsAllocate:
360e5dd7070Spatrick         case LengthModifier::AsMAllocate:
361e5dd7070Spatrick           return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
362e5dd7070Spatrick         case LengthModifier::AsShort:
363e5dd7070Spatrick           if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
364e5dd7070Spatrick             return ArgType::PtrTo(ArgType::AnyCharTy);
365*12c85518Srobert           [[fallthrough]];
366e5dd7070Spatrick         default:
367e5dd7070Spatrick           return ArgType::Invalid();
368e5dd7070Spatrick       }
369e5dd7070Spatrick 
370e5dd7070Spatrick     // Pointer.
371e5dd7070Spatrick     case ConversionSpecifier::pArg:
372e5dd7070Spatrick       return ArgType::PtrTo(ArgType::CPointerTy);
373e5dd7070Spatrick 
374e5dd7070Spatrick     // Write-back.
375e5dd7070Spatrick     case ConversionSpecifier::nArg:
376e5dd7070Spatrick       switch (LM.getKind()) {
377e5dd7070Spatrick         case LengthModifier::None:
378e5dd7070Spatrick           return ArgType::PtrTo(Ctx.IntTy);
379e5dd7070Spatrick         case LengthModifier::AsChar:
380e5dd7070Spatrick           return ArgType::PtrTo(Ctx.SignedCharTy);
381e5dd7070Spatrick         case LengthModifier::AsShort:
382e5dd7070Spatrick           return ArgType::PtrTo(Ctx.ShortTy);
383e5dd7070Spatrick         case LengthModifier::AsLong:
384e5dd7070Spatrick           return ArgType::PtrTo(Ctx.LongTy);
385e5dd7070Spatrick         case LengthModifier::AsLongLong:
386e5dd7070Spatrick         case LengthModifier::AsQuad:
387e5dd7070Spatrick           return ArgType::PtrTo(Ctx.LongLongTy);
388e5dd7070Spatrick         case LengthModifier::AsInt64:
389e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
390e5dd7070Spatrick         case LengthModifier::AsIntMax:
391e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
392e5dd7070Spatrick         case LengthModifier::AsSizeT:
393e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
394e5dd7070Spatrick         case LengthModifier::AsPtrDiff:
395e5dd7070Spatrick           return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
396e5dd7070Spatrick         case LengthModifier::AsLongDouble:
397e5dd7070Spatrick           return ArgType(); // FIXME: Is this a known extension?
398e5dd7070Spatrick         case LengthModifier::AsAllocate:
399e5dd7070Spatrick         case LengthModifier::AsMAllocate:
400e5dd7070Spatrick         case LengthModifier::AsInt32:
401e5dd7070Spatrick         case LengthModifier::AsInt3264:
402e5dd7070Spatrick         case LengthModifier::AsWide:
403e5dd7070Spatrick         case LengthModifier::AsShortLong:
404e5dd7070Spatrick           return ArgType::Invalid();
405e5dd7070Spatrick         }
406e5dd7070Spatrick 
407e5dd7070Spatrick     default:
408e5dd7070Spatrick       break;
409e5dd7070Spatrick   }
410e5dd7070Spatrick 
411e5dd7070Spatrick   return ArgType();
412e5dd7070Spatrick }
413e5dd7070Spatrick 
fixType(QualType QT,QualType RawQT,const LangOptions & LangOpt,ASTContext & Ctx)414e5dd7070Spatrick bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
415e5dd7070Spatrick                              const LangOptions &LangOpt,
416e5dd7070Spatrick                              ASTContext &Ctx) {
417e5dd7070Spatrick 
418e5dd7070Spatrick   // %n is different from other conversion specifiers; don't try to fix it.
419e5dd7070Spatrick   if (CS.getKind() == ConversionSpecifier::nArg)
420e5dd7070Spatrick     return false;
421e5dd7070Spatrick 
422e5dd7070Spatrick   if (!QT->isPointerType())
423e5dd7070Spatrick     return false;
424e5dd7070Spatrick 
425e5dd7070Spatrick   QualType PT = QT->getPointeeType();
426e5dd7070Spatrick 
427e5dd7070Spatrick   // If it's an enum, get its underlying type.
428e5dd7070Spatrick   if (const EnumType *ETy = PT->getAs<EnumType>()) {
429e5dd7070Spatrick     // Don't try to fix incomplete enums.
430e5dd7070Spatrick     if (!ETy->getDecl()->isComplete())
431e5dd7070Spatrick       return false;
432e5dd7070Spatrick     PT = ETy->getDecl()->getIntegerType();
433e5dd7070Spatrick   }
434e5dd7070Spatrick 
435e5dd7070Spatrick   const BuiltinType *BT = PT->getAs<BuiltinType>();
436e5dd7070Spatrick   if (!BT)
437e5dd7070Spatrick     return false;
438e5dd7070Spatrick 
439e5dd7070Spatrick   // Pointer to a character.
440e5dd7070Spatrick   if (PT->isAnyCharacterType()) {
441e5dd7070Spatrick     CS.setKind(ConversionSpecifier::sArg);
442e5dd7070Spatrick     if (PT->isWideCharType())
443e5dd7070Spatrick       LM.setKind(LengthModifier::AsWideChar);
444e5dd7070Spatrick     else
445e5dd7070Spatrick       LM.setKind(LengthModifier::None);
446e5dd7070Spatrick 
447e5dd7070Spatrick     // If we know the target array length, we can use it as a field width.
448e5dd7070Spatrick     if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
449e5dd7070Spatrick       if (CAT->getSizeModifier() == ArrayType::Normal)
450e5dd7070Spatrick         FieldWidth = OptionalAmount(OptionalAmount::Constant,
451e5dd7070Spatrick                                     CAT->getSize().getZExtValue() - 1,
452e5dd7070Spatrick                                     "", 0, false);
453e5dd7070Spatrick 
454e5dd7070Spatrick     }
455e5dd7070Spatrick     return true;
456e5dd7070Spatrick   }
457e5dd7070Spatrick 
458e5dd7070Spatrick   // Figure out the length modifier.
459e5dd7070Spatrick   switch (BT->getKind()) {
460e5dd7070Spatrick     // no modifier
461e5dd7070Spatrick     case BuiltinType::UInt:
462e5dd7070Spatrick     case BuiltinType::Int:
463e5dd7070Spatrick     case BuiltinType::Float:
464e5dd7070Spatrick       LM.setKind(LengthModifier::None);
465e5dd7070Spatrick       break;
466e5dd7070Spatrick 
467e5dd7070Spatrick     // hh
468e5dd7070Spatrick     case BuiltinType::Char_U:
469e5dd7070Spatrick     case BuiltinType::UChar:
470e5dd7070Spatrick     case BuiltinType::Char_S:
471e5dd7070Spatrick     case BuiltinType::SChar:
472e5dd7070Spatrick       LM.setKind(LengthModifier::AsChar);
473e5dd7070Spatrick       break;
474e5dd7070Spatrick 
475e5dd7070Spatrick     // h
476e5dd7070Spatrick     case BuiltinType::Short:
477e5dd7070Spatrick     case BuiltinType::UShort:
478e5dd7070Spatrick       LM.setKind(LengthModifier::AsShort);
479e5dd7070Spatrick       break;
480e5dd7070Spatrick 
481e5dd7070Spatrick     // l
482e5dd7070Spatrick     case BuiltinType::Long:
483e5dd7070Spatrick     case BuiltinType::ULong:
484e5dd7070Spatrick     case BuiltinType::Double:
485e5dd7070Spatrick       LM.setKind(LengthModifier::AsLong);
486e5dd7070Spatrick       break;
487e5dd7070Spatrick 
488e5dd7070Spatrick     // ll
489e5dd7070Spatrick     case BuiltinType::LongLong:
490e5dd7070Spatrick     case BuiltinType::ULongLong:
491e5dd7070Spatrick       LM.setKind(LengthModifier::AsLongLong);
492e5dd7070Spatrick       break;
493e5dd7070Spatrick 
494e5dd7070Spatrick     // L
495e5dd7070Spatrick     case BuiltinType::LongDouble:
496e5dd7070Spatrick       LM.setKind(LengthModifier::AsLongDouble);
497e5dd7070Spatrick       break;
498e5dd7070Spatrick 
499e5dd7070Spatrick     // Don't know.
500e5dd7070Spatrick     default:
501e5dd7070Spatrick       return false;
502e5dd7070Spatrick   }
503e5dd7070Spatrick 
504e5dd7070Spatrick   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
505*12c85518Srobert   if (LangOpt.C99 || LangOpt.CPlusPlus11)
506e5dd7070Spatrick     namedTypeToLengthModifier(PT, LM);
507e5dd7070Spatrick 
508e5dd7070Spatrick   // If fixing the length modifier was enough, we are done.
509e5dd7070Spatrick   if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
510e5dd7070Spatrick     const analyze_scanf::ArgType &AT = getArgType(Ctx);
511e5dd7070Spatrick     if (AT.isValid() && AT.matchesType(Ctx, QT))
512e5dd7070Spatrick       return true;
513e5dd7070Spatrick   }
514e5dd7070Spatrick 
515e5dd7070Spatrick   // Figure out the conversion specifier.
516e5dd7070Spatrick   if (PT->isRealFloatingType())
517e5dd7070Spatrick     CS.setKind(ConversionSpecifier::fArg);
518e5dd7070Spatrick   else if (PT->isSignedIntegerType())
519e5dd7070Spatrick     CS.setKind(ConversionSpecifier::dArg);
520e5dd7070Spatrick   else if (PT->isUnsignedIntegerType())
521e5dd7070Spatrick     CS.setKind(ConversionSpecifier::uArg);
522e5dd7070Spatrick   else
523e5dd7070Spatrick     llvm_unreachable("Unexpected type");
524e5dd7070Spatrick 
525e5dd7070Spatrick   return true;
526e5dd7070Spatrick }
527e5dd7070Spatrick 
toString(raw_ostream & os) const528e5dd7070Spatrick void ScanfSpecifier::toString(raw_ostream &os) const {
529e5dd7070Spatrick   os << "%";
530e5dd7070Spatrick 
531e5dd7070Spatrick   if (usesPositionalArg())
532e5dd7070Spatrick     os << getPositionalArgIndex() << "$";
533e5dd7070Spatrick   if (SuppressAssignment)
534e5dd7070Spatrick     os << "*";
535e5dd7070Spatrick 
536e5dd7070Spatrick   FieldWidth.toString(os);
537e5dd7070Spatrick   os << LM.toString();
538e5dd7070Spatrick   os << CS.toString();
539e5dd7070Spatrick }
540e5dd7070Spatrick 
ParseScanfString(FormatStringHandler & H,const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)541e5dd7070Spatrick bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
542e5dd7070Spatrick                                                     const char *I,
543e5dd7070Spatrick                                                     const char *E,
544e5dd7070Spatrick                                                     const LangOptions &LO,
545e5dd7070Spatrick                                                     const TargetInfo &Target) {
546e5dd7070Spatrick 
547e5dd7070Spatrick   unsigned argIndex = 0;
548e5dd7070Spatrick 
549e5dd7070Spatrick   // Keep looking for a format specifier until we have exhausted the string.
550e5dd7070Spatrick   while (I != E) {
551e5dd7070Spatrick     const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
552e5dd7070Spatrick                                                           LO, Target);
553e5dd7070Spatrick     // Did a fail-stop error of any kind occur when parsing the specifier?
554e5dd7070Spatrick     // If so, don't do any more processing.
555e5dd7070Spatrick     if (FSR.shouldStop())
556e5dd7070Spatrick       return true;
557e5dd7070Spatrick       // Did we exhaust the string or encounter an error that
558e5dd7070Spatrick       // we can recover from?
559e5dd7070Spatrick     if (!FSR.hasValue())
560e5dd7070Spatrick       continue;
561e5dd7070Spatrick       // We have a format specifier.  Pass it to the callback.
562e5dd7070Spatrick     if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
563e5dd7070Spatrick                                 I - FSR.getStart())) {
564e5dd7070Spatrick       return true;
565e5dd7070Spatrick     }
566e5dd7070Spatrick   }
567e5dd7070Spatrick   assert(I == E && "Format string not exhausted");
568e5dd7070Spatrick   return false;
569e5dd7070Spatrick }
570