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