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