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