1//== PrintfFormatString.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 printf and friends. The structure of format
10// strings for fprintf() are described in C99 7.19.6.1.
11//
12//===----------------------------------------------------------------------===//
13
14#include "FormatStringParsing.h"
15#include "clang/AST/FormatString.h"
16#include "clang/AST/OSLog.h"
17#include "clang/Basic/TargetInfo.h"
18#include "llvm/Support/Regex.h"
19
20using clang::analyze_format_string::ArgType;
21using clang::analyze_format_string::FormatStringHandler;
22using clang::analyze_format_string::LengthModifier;
23using clang::analyze_format_string::OptionalAmount;
24using clang::analyze_format_string::ConversionSpecifier;
25using clang::analyze_printf::PrintfSpecifier;
26
27using namespace clang;
28
29typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
30 PrintfSpecifierResult;
31
32//===----------------------------------------------------------------------===//
33// Methods for parsing format strings.
34//===----------------------------------------------------------------------===//
35
36using analyze_format_string::ParseNonPositionAmount;
37
38static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
39 const char *Start, const char *&Beg, const char *E,
40 unsigned *argIndex) {
41 if (argIndex) {
42 FS.setPrecision(ParseNonPositionAmount(Beg, E, argIndex&: *argIndex));
43 } else {
44 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
45 p: analyze_format_string::PrecisionPos);
46 if (Amt.isInvalid())
47 return true;
48 FS.setPrecision(Amt);
49 }
50 return false;
51}
52
53static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
54 const char *FlagBeg, const char *E, bool Warn) {
55 StringRef Flag(FlagBeg, E - FlagBeg);
56 // Currently there is only one flag.
57 if (Flag == "tt") {
58 FS.setHasObjCTechnicalTerm(FlagBeg);
59 return false;
60 }
61 // Handle either the case of no flag or an invalid flag.
62 if (Warn) {
63 if (Flag == "")
64 H.HandleEmptyObjCModifierFlag(startFlags: FlagBeg, flagsLen: E - FlagBeg);
65 else
66 H.HandleInvalidObjCModifierFlag(startFlag: FlagBeg, flagLen: E - FlagBeg);
67 }
68 return true;
69}
70
71static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
72 const char *&Beg,
73 const char *E,
74 unsigned &argIndex,
75 const LangOptions &LO,
76 const TargetInfo &Target,
77 bool Warn,
78 bool isFreeBSDKPrintf) {
79
80 using namespace clang::analyze_format_string;
81 using namespace clang::analyze_printf;
82
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(nullCharacter: 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 if (Warn)
108 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
109 return true;
110 }
111
112 PrintfSpecifier FS;
113 if (ParseArgPosition(H, CS&: FS, Start, Beg&: I, E))
114 return true;
115
116 if (I == E) {
117 // No more characters left?
118 if (Warn)
119 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
120 return true;
121 }
122
123 if (*I == '{') {
124 ++I;
125 unsigned char PrivacyFlags = 0;
126 StringRef MatchedStr;
127
128 do {
129 StringRef Str(I, E - I);
130 std::string Match = "^[[:space:]]*"
131 "(private|public|sensitive|mask\\.[^[:space:],}]*)"
132 "[[:space:]]*(,|})";
133 llvm::Regex R(Match);
134 SmallVector<StringRef, 2> Matches;
135
136 if (R.match(String: Str, Matches: &Matches)) {
137 MatchedStr = Matches[1];
138 I += Matches[0].size();
139
140 // Set the privacy flag if the privacy annotation in the
141 // comma-delimited segment is at least as strict as the privacy
142 // annotations in previous comma-delimited segments.
143 if (MatchedStr.starts_with(Prefix: "mask")) {
144 StringRef MaskType = MatchedStr.substr(Start: sizeof("mask.") - 1);
145 unsigned Size = MaskType.size();
146 if (Warn && (Size == 0 || Size > 8))
147 H.handleInvalidMaskType(MaskType);
148 FS.setMaskType(MaskType);
149 } else if (MatchedStr == "sensitive")
150 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;
151 else if (PrivacyFlags !=
152 clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
153 MatchedStr == "private")
154 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
155 else if (PrivacyFlags == 0 && MatchedStr == "public")
156 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
157 } else {
158 size_t CommaOrBracePos =
159 Str.find_if(F: [](char c) { return c == ',' || c == '}'; });
160
161 if (CommaOrBracePos == StringRef::npos) {
162 // Neither a comma nor the closing brace was found.
163 if (Warn)
164 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
165 return true;
166 }
167
168 I += CommaOrBracePos + 1;
169 }
170 // Continue until the closing brace is found.
171 } while (*(I - 1) == ',');
172
173 // Set the privacy flag.
174 switch (PrivacyFlags) {
175 case 0:
176 break;
177 case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
178 FS.setIsPrivate(MatchedStr.data());
179 break;
180 case clang::analyze_os_log::OSLogBufferItem::IsPublic:
181 FS.setIsPublic(MatchedStr.data());
182 break;
183 case clang::analyze_os_log::OSLogBufferItem::IsSensitive:
184 FS.setIsSensitive(MatchedStr.data());
185 break;
186 default:
187 llvm_unreachable("Unexpected privacy flag value");
188 }
189 }
190
191 // Look for flags (if any).
192 bool hasMore = true;
193 for ( ; I != E; ++I) {
194 switch (*I) {
195 default: hasMore = false; break;
196 case '\'':
197 // FIXME: POSIX specific. Always accept?
198 FS.setHasThousandsGrouping(I);
199 break;
200 case '-': FS.setIsLeftJustified(I); break;
201 case '+': FS.setHasPlusPrefix(I); break;
202 case ' ': FS.setHasSpacePrefix(I); break;
203 case '#': FS.setHasAlternativeForm(I); break;
204 case '0': FS.setHasLeadingZeros(I); break;
205 }
206 if (!hasMore)
207 break;
208 }
209
210 if (I == E) {
211 // No more characters left?
212 if (Warn)
213 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
214 return true;
215 }
216
217 // Look for the field width (if any).
218 if (ParseFieldWidth(H, CS&: FS, Start, Beg&: I, E,
219 argIndex: FS.usesPositionalArg() ? nullptr : &argIndex))
220 return true;
221
222 if (I == E) {
223 // No more characters left?
224 if (Warn)
225 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
226 return true;
227 }
228
229 // Look for the precision (if any).
230 if (*I == '.') {
231 ++I;
232 if (I == E) {
233 if (Warn)
234 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
235 return true;
236 }
237
238 if (ParsePrecision(H, FS, Start, Beg&: I, E,
239 argIndex: FS.usesPositionalArg() ? nullptr : &argIndex))
240 return true;
241
242 if (I == E) {
243 // No more characters left?
244 if (Warn)
245 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
246 return true;
247 }
248 }
249
250 if (ParseVectorModifier(H, FS, Beg&: I, E, LO))
251 return true;
252
253 // Look for the length modifier.
254 if (ParseLengthModifier(FS, Beg&: I, E, LO) && I == E) {
255 // No more characters left?
256 if (Warn)
257 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
258 return true;
259 }
260
261 // Look for the Objective-C modifier flags, if any.
262 // We parse these here, even if they don't apply to
263 // the conversion specifier, and then emit an error
264 // later if the conversion specifier isn't '@'. This
265 // enables better recovery, and we don't know if
266 // these flags are applicable until later.
267 const char *ObjCModifierFlagsStart = nullptr,
268 *ObjCModifierFlagsEnd = nullptr;
269 if (*I == '[') {
270 ObjCModifierFlagsStart = I;
271 ++I;
272 auto flagStart = I;
273 for (;; ++I) {
274 ObjCModifierFlagsEnd = I;
275 if (I == E) {
276 if (Warn)
277 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
278 return true;
279 }
280 // Did we find the closing ']'?
281 if (*I == ']') {
282 if (ParseObjCFlags(H, FS, FlagBeg: flagStart, E: I, Warn))
283 return true;
284 ++I;
285 break;
286 }
287 // There are no separators defined yet for multiple
288 // Objective-C modifier flags. When those are
289 // defined, this is the place to check.
290 }
291 }
292
293 if (*I == '\0') {
294 // Detect spurious null characters, which are likely errors.
295 H.HandleNullChar(nullCharacter: I);
296 return true;
297 }
298
299 // Finally, look for the conversion specifier.
300 const char *conversionPosition = I++;
301 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
302 switch (*conversionPosition) {
303 default:
304 break;
305 // C99: 7.19.6.1 (section 8).
306 case '%': k = ConversionSpecifier::PercentArg; break;
307 case 'A': k = ConversionSpecifier::AArg; break;
308 case 'E': k = ConversionSpecifier::EArg; break;
309 case 'F': k = ConversionSpecifier::FArg; break;
310 case 'G': k = ConversionSpecifier::GArg; break;
311 case 'X': k = ConversionSpecifier::XArg; break;
312 case 'a': k = ConversionSpecifier::aArg; break;
313 case 'c': k = ConversionSpecifier::cArg; break;
314 case 'd': k = ConversionSpecifier::dArg; break;
315 case 'e': k = ConversionSpecifier::eArg; break;
316 case 'f': k = ConversionSpecifier::fArg; break;
317 case 'g': k = ConversionSpecifier::gArg; break;
318 case 'i': k = ConversionSpecifier::iArg; break;
319 case 'n':
320 // Not handled, but reserved in OpenCL.
321 if (!LO.OpenCL)
322 k = ConversionSpecifier::nArg;
323 break;
324 case 'o': k = ConversionSpecifier::oArg; break;
325 case 'p': k = ConversionSpecifier::pArg; break;
326 case 's': k = ConversionSpecifier::sArg; break;
327 case 'u': k = ConversionSpecifier::uArg; break;
328 case 'x': k = ConversionSpecifier::xArg; break;
329 // C23.
330 case 'b':
331 if (isFreeBSDKPrintf)
332 k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
333 else
334 k = ConversionSpecifier::bArg;
335 break;
336 case 'B': k = ConversionSpecifier::BArg; break;
337 // POSIX specific.
338 case 'C': k = ConversionSpecifier::CArg; break;
339 case 'S': k = ConversionSpecifier::SArg; break;
340 // Apple extension for os_log
341 case 'P':
342 k = ConversionSpecifier::PArg;
343 break;
344 // Objective-C.
345 case '@': k = ConversionSpecifier::ObjCObjArg; break;
346 // Glibc specific.
347 case 'm': k = ConversionSpecifier::PrintErrno; break;
348 case 'r':
349 if (isFreeBSDKPrintf)
350 k = ConversionSpecifier::FreeBSDrArg; // int
351 else if (LO.FixedPoint)
352 k = ConversionSpecifier::rArg;
353 break;
354 case 'y':
355 if (isFreeBSDKPrintf)
356 k = ConversionSpecifier::FreeBSDyArg; // int
357 break;
358 // Apple-specific.
359 case 'D':
360 if (isFreeBSDKPrintf)
361 k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
362 else if (Target.getTriple().isOSDarwin())
363 k = ConversionSpecifier::DArg;
364 break;
365 case 'O':
366 if (Target.getTriple().isOSDarwin())
367 k = ConversionSpecifier::OArg;
368 break;
369 case 'U':
370 if (Target.getTriple().isOSDarwin())
371 k = ConversionSpecifier::UArg;
372 break;
373 // MS specific.
374 case 'Z':
375 if (Target.getTriple().isOSMSVCRT())
376 k = ConversionSpecifier::ZArg;
377 break;
378 // ISO/IEC TR 18037 (fixed-point) specific.
379 // NOTE: 'r' is handled up above since FreeBSD also supports %r.
380 case 'k':
381 if (LO.FixedPoint)
382 k = ConversionSpecifier::kArg;
383 break;
384 case 'K':
385 if (LO.FixedPoint)
386 k = ConversionSpecifier::KArg;
387 break;
388 case 'R':
389 if (LO.FixedPoint)
390 k = ConversionSpecifier::RArg;
391 break;
392 }
393
394 // Check to see if we used the Objective-C modifier flags with
395 // a conversion specifier other than '@'.
396 if (k != ConversionSpecifier::ObjCObjArg &&
397 k != ConversionSpecifier::InvalidSpecifier &&
398 ObjCModifierFlagsStart) {
399 H.HandleObjCFlagsWithNonObjCConversion(flagsStart: ObjCModifierFlagsStart,
400 flagsEnd: ObjCModifierFlagsEnd + 1,
401 conversionPosition);
402 return true;
403 }
404
405 PrintfConversionSpecifier CS(conversionPosition, k);
406 FS.setConversionSpecifier(CS);
407 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
408 FS.setArgIndex(argIndex++);
409 // FreeBSD kernel specific.
410 if (k == ConversionSpecifier::FreeBSDbArg ||
411 k == ConversionSpecifier::FreeBSDDArg)
412 argIndex++;
413
414 if (k == ConversionSpecifier::InvalidSpecifier) {
415 unsigned Len = I - Start;
416 if (ParseUTF8InvalidSpecifier(SpecifierBegin: Start, FmtStrEnd: E, Len)) {
417 CS.setEndScanList(Start + Len);
418 FS.setConversionSpecifier(CS);
419 }
420 // Assume the conversion takes one argument.
421 return !H.HandleInvalidPrintfConversionSpecifier(FS, startSpecifier: Start, specifierLen: Len);
422 }
423 return PrintfSpecifierResult(Start, FS);
424}
425
426bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
427 const char *I,
428 const char *E,
429 const LangOptions &LO,
430 const TargetInfo &Target,
431 bool isFreeBSDKPrintf) {
432
433 unsigned argIndex = 0;
434
435 // Keep looking for a format specifier until we have exhausted the string.
436 while (I != E) {
437 const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, Beg&: I, E, argIndex,
438 LO, Target, Warn: true,
439 isFreeBSDKPrintf);
440 // Did a fail-stop error of any kind occur when parsing the specifier?
441 // If so, don't do any more processing.
442 if (FSR.shouldStop())
443 return true;
444 // Did we exhaust the string or encounter an error that
445 // we can recover from?
446 if (!FSR.hasValue())
447 continue;
448 // We have a format specifier. Pass it to the callback.
449 if (!H.HandlePrintfSpecifier(FS: FSR.getValue(), startSpecifier: FSR.getStart(),
450 specifierLen: I - FSR.getStart(), Target))
451 return true;
452 }
453 assert(I == E && "Format string not exhausted");
454 return false;
455}
456
457bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
458 const char *E,
459 const LangOptions &LO,
460 const TargetInfo &Target) {
461
462 unsigned argIndex = 0;
463
464 // Keep looking for a %s format specifier until we have exhausted the string.
465 FormatStringHandler H;
466 while (I != E) {
467 const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, Beg&: I, E, argIndex,
468 LO, Target, Warn: false,
469 isFreeBSDKPrintf: false);
470 // Did a fail-stop error of any kind occur when parsing the specifier?
471 // If so, don't do any more processing.
472 if (FSR.shouldStop())
473 return false;
474 // Did we exhaust the string or encounter an error that
475 // we can recover from?
476 if (!FSR.hasValue())
477 continue;
478 const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
479 // Return true if this a %s format specifier.
480 if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
481 return true;
482 }
483 return false;
484}
485
486bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
487 const char *Begin, const char *End, const LangOptions &LO,
488 const TargetInfo &Target) {
489 unsigned ArgIndex = 0;
490 // Keep looking for a formatting specifier until we have exhausted the string.
491 FormatStringHandler H;
492 while (Begin != End) {
493 const PrintfSpecifierResult &FSR =
494 ParsePrintfSpecifier(H, Beg&: Begin, E: End, argIndex&: ArgIndex, LO, Target, Warn: false, isFreeBSDKPrintf: false);
495 if (FSR.shouldStop())
496 break;
497 if (FSR.hasValue())
498 return true;
499 }
500 return false;
501}
502
503//===----------------------------------------------------------------------===//
504// Methods on PrintfSpecifier.
505//===----------------------------------------------------------------------===//
506
507ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
508 bool IsObjCLiteral) const {
509 if (CS.getKind() == ConversionSpecifier::cArg)
510 switch (LM.getKind()) {
511 case LengthModifier::None:
512 return Ctx.IntTy;
513 case LengthModifier::AsLong:
514 case LengthModifier::AsWide:
515 return ArgType(ArgType::WIntTy, "wint_t");
516 case LengthModifier::AsShort:
517 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
518 return Ctx.IntTy;
519 [[fallthrough]];
520 default:
521 return ArgType::Invalid();
522 }
523
524 if (CS.isIntArg())
525 switch (LM.getKind()) {
526 case LengthModifier::AsLongDouble:
527 // GNU extension.
528 return Ctx.LongLongTy;
529 case LengthModifier::None:
530 case LengthModifier::AsShortLong:
531 return Ctx.IntTy;
532 case LengthModifier::AsInt32:
533 return ArgType(Ctx.IntTy, "__int32");
534 case LengthModifier::AsChar:
535 return ArgType::AnyCharTy;
536 case LengthModifier::AsShort: return Ctx.ShortTy;
537 case LengthModifier::AsLong: return Ctx.LongTy;
538 case LengthModifier::AsLongLong:
539 case LengthModifier::AsQuad:
540 return Ctx.LongLongTy;
541 case LengthModifier::AsInt64:
542 return ArgType(Ctx.LongLongTy, "__int64");
543 case LengthModifier::AsIntMax:
544 return ArgType(Ctx.getIntMaxType(), "intmax_t");
545 case LengthModifier::AsSizeT:
546 return ArgType::makeSizeT(A: ArgType(Ctx.getSignedSizeType(), "ssize_t"));
547 case LengthModifier::AsInt3264:
548 return Ctx.getTargetInfo().getTriple().isArch64Bit()
549 ? ArgType(Ctx.LongLongTy, "__int64")
550 : ArgType(Ctx.IntTy, "__int32");
551 case LengthModifier::AsPtrDiff:
552 return ArgType::makePtrdiffT(
553 A: ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
554 case LengthModifier::AsAllocate:
555 case LengthModifier::AsMAllocate:
556 case LengthModifier::AsWide:
557 return ArgType::Invalid();
558 }
559
560 if (CS.isUIntArg())
561 switch (LM.getKind()) {
562 case LengthModifier::AsLongDouble:
563 // GNU extension.
564 return Ctx.UnsignedLongLongTy;
565 case LengthModifier::None:
566 case LengthModifier::AsShortLong:
567 return Ctx.UnsignedIntTy;
568 case LengthModifier::AsInt32:
569 return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
570 case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
571 case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
572 case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
573 case LengthModifier::AsLongLong:
574 case LengthModifier::AsQuad:
575 return Ctx.UnsignedLongLongTy;
576 case LengthModifier::AsInt64:
577 return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
578 case LengthModifier::AsIntMax:
579 return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
580 case LengthModifier::AsSizeT:
581 return ArgType::makeSizeT(A: ArgType(Ctx.getSizeType(), "size_t"));
582 case LengthModifier::AsInt3264:
583 return Ctx.getTargetInfo().getTriple().isArch64Bit()
584 ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
585 : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
586 case LengthModifier::AsPtrDiff:
587 return ArgType::makePtrdiffT(
588 A: ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
589 case LengthModifier::AsAllocate:
590 case LengthModifier::AsMAllocate:
591 case LengthModifier::AsWide:
592 return ArgType::Invalid();
593 }
594
595 if (CS.isDoubleArg()) {
596 if (!VectorNumElts.isInvalid()) {
597 switch (LM.getKind()) {
598 case LengthModifier::AsShort:
599 return Ctx.HalfTy;
600 case LengthModifier::AsShortLong:
601 return Ctx.FloatTy;
602 case LengthModifier::AsLong:
603 default:
604 return Ctx.DoubleTy;
605 }
606 }
607
608 if (LM.getKind() == LengthModifier::AsLongDouble)
609 return Ctx.LongDoubleTy;
610 return Ctx.DoubleTy;
611 }
612
613 if (CS.getKind() == ConversionSpecifier::nArg) {
614 switch (LM.getKind()) {
615 case LengthModifier::None:
616 return ArgType::PtrTo(A: Ctx.IntTy);
617 case LengthModifier::AsChar:
618 return ArgType::PtrTo(A: Ctx.SignedCharTy);
619 case LengthModifier::AsShort:
620 return ArgType::PtrTo(A: Ctx.ShortTy);
621 case LengthModifier::AsLong:
622 return ArgType::PtrTo(A: Ctx.LongTy);
623 case LengthModifier::AsLongLong:
624 case LengthModifier::AsQuad:
625 return ArgType::PtrTo(A: Ctx.LongLongTy);
626 case LengthModifier::AsIntMax:
627 return ArgType::PtrTo(A: ArgType(Ctx.getIntMaxType(), "intmax_t"));
628 case LengthModifier::AsSizeT:
629 return ArgType::PtrTo(A: ArgType(Ctx.getSignedSizeType(), "ssize_t"));
630 case LengthModifier::AsPtrDiff:
631 return ArgType::PtrTo(A: ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
632 case LengthModifier::AsLongDouble:
633 return ArgType(); // FIXME: Is this a known extension?
634 case LengthModifier::AsAllocate:
635 case LengthModifier::AsMAllocate:
636 case LengthModifier::AsInt32:
637 case LengthModifier::AsInt3264:
638 case LengthModifier::AsInt64:
639 case LengthModifier::AsWide:
640 return ArgType::Invalid();
641 case LengthModifier::AsShortLong:
642 llvm_unreachable("only used for OpenCL which doesn not handle nArg");
643 }
644 }
645
646 if (CS.isFixedPointArg() && !Ctx.getLangOpts().FixedPoint)
647 return ArgType::Invalid();
648
649 switch (CS.getKind()) {
650 case ConversionSpecifier::sArg:
651 if (LM.getKind() == LengthModifier::AsWideChar) {
652 if (IsObjCLiteral)
653 return ArgType(Ctx.getPointerType(T: Ctx.UnsignedShortTy.withConst()),
654 "const unichar *");
655 return ArgType(ArgType::WCStrTy, "wchar_t *");
656 }
657 if (LM.getKind() == LengthModifier::AsWide)
658 return ArgType(ArgType::WCStrTy, "wchar_t *");
659 return ArgType::CStrTy;
660 case ConversionSpecifier::SArg:
661 if (IsObjCLiteral)
662 return ArgType(Ctx.getPointerType(T: Ctx.UnsignedShortTy.withConst()),
663 "const unichar *");
664 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
665 LM.getKind() == LengthModifier::AsShort)
666 return ArgType::CStrTy;
667 return ArgType(ArgType::WCStrTy, "wchar_t *");
668 case ConversionSpecifier::CArg:
669 if (IsObjCLiteral)
670 return ArgType(Ctx.UnsignedShortTy, "unichar");
671 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
672 LM.getKind() == LengthModifier::AsShort)
673 return Ctx.IntTy;
674 return ArgType(Ctx.WideCharTy, "wchar_t");
675 case ConversionSpecifier::pArg:
676 case ConversionSpecifier::PArg:
677 return ArgType::CPointerTy;
678 case ConversionSpecifier::ObjCObjArg:
679 return ArgType::ObjCPointerTy;
680 case ConversionSpecifier::kArg:
681 switch (LM.getKind()) {
682 case LengthModifier::None:
683 return Ctx.AccumTy;
684 case LengthModifier::AsShort:
685 return Ctx.ShortAccumTy;
686 case LengthModifier::AsLong:
687 return Ctx.LongAccumTy;
688 default:
689 return ArgType::Invalid();
690 }
691 case ConversionSpecifier::KArg:
692 switch (LM.getKind()) {
693 case LengthModifier::None:
694 return Ctx.UnsignedAccumTy;
695 case LengthModifier::AsShort:
696 return Ctx.UnsignedShortAccumTy;
697 case LengthModifier::AsLong:
698 return Ctx.UnsignedLongAccumTy;
699 default:
700 return ArgType::Invalid();
701 }
702 case ConversionSpecifier::rArg:
703 switch (LM.getKind()) {
704 case LengthModifier::None:
705 return Ctx.FractTy;
706 case LengthModifier::AsShort:
707 return Ctx.ShortFractTy;
708 case LengthModifier::AsLong:
709 return Ctx.LongFractTy;
710 default:
711 return ArgType::Invalid();
712 }
713 case ConversionSpecifier::RArg:
714 switch (LM.getKind()) {
715 case LengthModifier::None:
716 return Ctx.UnsignedFractTy;
717 case LengthModifier::AsShort:
718 return Ctx.UnsignedShortFractTy;
719 case LengthModifier::AsLong:
720 return Ctx.UnsignedLongFractTy;
721 default:
722 return ArgType::Invalid();
723 }
724 default:
725 break;
726 }
727
728 // FIXME: Handle other cases.
729 return ArgType();
730}
731
732
733ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
734 bool IsObjCLiteral) const {
735 const PrintfConversionSpecifier &CS = getConversionSpecifier();
736
737 if (!CS.consumesDataArgument())
738 return ArgType::Invalid();
739
740 ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
741 if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
742 return ScalarTy;
743
744 return ScalarTy.makeVectorType(C&: Ctx, NumElts: VectorNumElts.getConstantAmount());
745}
746
747bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
748 ASTContext &Ctx, bool IsObjCLiteral) {
749 // %n is different from other conversion specifiers; don't try to fix it.
750 if (CS.getKind() == ConversionSpecifier::nArg)
751 return false;
752
753 // Handle Objective-C objects first. Note that while the '%@' specifier will
754 // not warn for structure pointer or void pointer arguments (because that's
755 // how CoreFoundation objects are implemented), we only show a fixit for '%@'
756 // if we know it's an object (block, id, class, or __attribute__((NSObject))).
757 if (QT->isObjCRetainableType()) {
758 if (!IsObjCLiteral)
759 return false;
760
761 CS.setKind(ConversionSpecifier::ObjCObjArg);
762
763 // Disable irrelevant flags
764 HasThousandsGrouping = false;
765 HasPlusPrefix = false;
766 HasSpacePrefix = false;
767 HasAlternativeForm = false;
768 HasLeadingZeroes = false;
769 Precision.setHowSpecified(OptionalAmount::NotSpecified);
770 LM.setKind(LengthModifier::None);
771
772 return true;
773 }
774
775 // Handle strings next (char *, wchar_t *)
776 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
777 CS.setKind(ConversionSpecifier::sArg);
778
779 // Disable irrelevant flags
780 HasAlternativeForm = false;
781 HasLeadingZeroes = false;
782
783 // Set the long length modifier for wide characters
784 if (QT->getPointeeType()->isWideCharType())
785 LM.setKind(LengthModifier::AsWideChar);
786 else
787 LM.setKind(LengthModifier::None);
788
789 return true;
790 }
791
792 // If it's an enum, get its underlying type.
793 if (const EnumType *ETy = QT->getAs<EnumType>())
794 QT = ETy->getDecl()->getIntegerType();
795
796 const BuiltinType *BT = QT->getAs<BuiltinType>();
797 if (!BT) {
798 const VectorType *VT = QT->getAs<VectorType>();
799 if (VT) {
800 QT = VT->getElementType();
801 BT = QT->getAs<BuiltinType>();
802 VectorNumElts = OptionalAmount(VT->getNumElements());
803 }
804 }
805
806 // We can only work with builtin types.
807 if (!BT)
808 return false;
809
810 // Set length modifier
811 switch (BT->getKind()) {
812 case BuiltinType::Bool:
813 case BuiltinType::WChar_U:
814 case BuiltinType::WChar_S:
815 case BuiltinType::Char8: // FIXME: Treat like 'char'?
816 case BuiltinType::Char16:
817 case BuiltinType::Char32:
818 case BuiltinType::UInt128:
819 case BuiltinType::Int128:
820 case BuiltinType::Half:
821 case BuiltinType::BFloat16:
822 case BuiltinType::Float16:
823 case BuiltinType::Float128:
824 case BuiltinType::Ibm128:
825 case BuiltinType::ShortAccum:
826 case BuiltinType::Accum:
827 case BuiltinType::LongAccum:
828 case BuiltinType::UShortAccum:
829 case BuiltinType::UAccum:
830 case BuiltinType::ULongAccum:
831 case BuiltinType::ShortFract:
832 case BuiltinType::Fract:
833 case BuiltinType::LongFract:
834 case BuiltinType::UShortFract:
835 case BuiltinType::UFract:
836 case BuiltinType::ULongFract:
837 case BuiltinType::SatShortAccum:
838 case BuiltinType::SatAccum:
839 case BuiltinType::SatLongAccum:
840 case BuiltinType::SatUShortAccum:
841 case BuiltinType::SatUAccum:
842 case BuiltinType::SatULongAccum:
843 case BuiltinType::SatShortFract:
844 case BuiltinType::SatFract:
845 case BuiltinType::SatLongFract:
846 case BuiltinType::SatUShortFract:
847 case BuiltinType::SatUFract:
848 case BuiltinType::SatULongFract:
849 // Various types which are non-trivial to correct.
850 return false;
851
852#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
853 case BuiltinType::Id:
854#include "clang/Basic/OpenCLImageTypes.def"
855#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
856 case BuiltinType::Id:
857#include "clang/Basic/OpenCLExtensionTypes.def"
858#define SVE_TYPE(Name, Id, SingletonId) \
859 case BuiltinType::Id:
860#include "clang/Basic/AArch64SVEACLETypes.def"
861#define PPC_VECTOR_TYPE(Name, Id, Size) \
862 case BuiltinType::Id:
863#include "clang/Basic/PPCTypes.def"
864#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
865#include "clang/Basic/RISCVVTypes.def"
866#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
867#include "clang/Basic/WebAssemblyReferenceTypes.def"
868#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
869#include "clang/Basic/AMDGPUTypes.def"
870#define SIGNED_TYPE(Id, SingletonId)
871#define UNSIGNED_TYPE(Id, SingletonId)
872#define FLOATING_TYPE(Id, SingletonId)
873#define BUILTIN_TYPE(Id, SingletonId) \
874 case BuiltinType::Id:
875#include "clang/AST/BuiltinTypes.def"
876 // Misc other stuff which doesn't make sense here.
877 return false;
878
879 case BuiltinType::UInt:
880 case BuiltinType::Int:
881 case BuiltinType::Float:
882 LM.setKind(VectorNumElts.isInvalid() ?
883 LengthModifier::None : LengthModifier::AsShortLong);
884 break;
885 case BuiltinType::Double:
886 LM.setKind(VectorNumElts.isInvalid() ?
887 LengthModifier::None : LengthModifier::AsLong);
888 break;
889 case BuiltinType::Char_U:
890 case BuiltinType::UChar:
891 case BuiltinType::Char_S:
892 case BuiltinType::SChar:
893 LM.setKind(LengthModifier::AsChar);
894 break;
895
896 case BuiltinType::Short:
897 case BuiltinType::UShort:
898 LM.setKind(LengthModifier::AsShort);
899 break;
900
901 case BuiltinType::Long:
902 case BuiltinType::ULong:
903 LM.setKind(LengthModifier::AsLong);
904 break;
905
906 case BuiltinType::LongLong:
907 case BuiltinType::ULongLong:
908 LM.setKind(LengthModifier::AsLongLong);
909 break;
910
911 case BuiltinType::LongDouble:
912 LM.setKind(LengthModifier::AsLongDouble);
913 break;
914 }
915
916 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
917 if (LangOpt.C99 || LangOpt.CPlusPlus11)
918 namedTypeToLengthModifier(QT, LM);
919
920 // If fixing the length modifier was enough, we might be done.
921 if (hasValidLengthModifier(Target: Ctx.getTargetInfo(), LO: LangOpt)) {
922 // If we're going to offer a fix anyway, make sure the sign matches.
923 switch (CS.getKind()) {
924 case ConversionSpecifier::uArg:
925 case ConversionSpecifier::UArg:
926 if (QT->isSignedIntegerType())
927 CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
928 break;
929 case ConversionSpecifier::dArg:
930 case ConversionSpecifier::DArg:
931 case ConversionSpecifier::iArg:
932 if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
933 CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
934 break;
935 default:
936 // Other specifiers do not have signed/unsigned variants.
937 break;
938 }
939
940 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
941 if (ATR.isValid() && ATR.matchesType(C&: Ctx, argTy: QT))
942 return true;
943 }
944
945 // Set conversion specifier and disable any flags which do not apply to it.
946 // Let typedefs to char fall through to int, as %c is silly for uint8_t.
947 if (!QT->getAs<TypedefType>() && QT->isCharType()) {
948 CS.setKind(ConversionSpecifier::cArg);
949 LM.setKind(LengthModifier::None);
950 Precision.setHowSpecified(OptionalAmount::NotSpecified);
951 HasAlternativeForm = false;
952 HasLeadingZeroes = false;
953 HasPlusPrefix = false;
954 }
955 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
956 else if (QT->isRealFloatingType()) {
957 CS.setKind(ConversionSpecifier::fArg);
958 } else if (QT->isSignedIntegerType()) {
959 CS.setKind(ConversionSpecifier::dArg);
960 HasAlternativeForm = false;
961 } else if (QT->isUnsignedIntegerType()) {
962 CS.setKind(ConversionSpecifier::uArg);
963 HasAlternativeForm = false;
964 HasPlusPrefix = false;
965 } else {
966 llvm_unreachable("Unexpected type");
967 }
968
969 return true;
970}
971
972void PrintfSpecifier::toString(raw_ostream &os) const {
973 // Whilst some features have no defined order, we are using the order
974 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
975 os << "%";
976
977 // Positional args
978 if (usesPositionalArg()) {
979 os << getPositionalArgIndex() << "$";
980 }
981
982 // Conversion flags
983 if (IsLeftJustified) os << "-";
984 if (HasPlusPrefix) os << "+";
985 if (HasSpacePrefix) os << " ";
986 if (HasAlternativeForm) os << "#";
987 if (HasLeadingZeroes) os << "0";
988
989 // Minimum field width
990 FieldWidth.toString(os);
991 // Precision
992 Precision.toString(os);
993
994 // Vector modifier
995 if (!VectorNumElts.isInvalid())
996 os << 'v' << VectorNumElts.getConstantAmount();
997
998 // Length modifier
999 os << LM.toString();
1000 // Conversion specifier
1001 os << CS.toString();
1002}
1003
1004bool PrintfSpecifier::hasValidPlusPrefix() const {
1005 if (!HasPlusPrefix)
1006 return true;
1007
1008 // The plus prefix only makes sense for signed conversions
1009 switch (CS.getKind()) {
1010 case ConversionSpecifier::dArg:
1011 case ConversionSpecifier::DArg:
1012 case ConversionSpecifier::iArg:
1013 case ConversionSpecifier::fArg:
1014 case ConversionSpecifier::FArg:
1015 case ConversionSpecifier::eArg:
1016 case ConversionSpecifier::EArg:
1017 case ConversionSpecifier::gArg:
1018 case ConversionSpecifier::GArg:
1019 case ConversionSpecifier::aArg:
1020 case ConversionSpecifier::AArg:
1021 case ConversionSpecifier::FreeBSDrArg:
1022 case ConversionSpecifier::FreeBSDyArg:
1023 case ConversionSpecifier::rArg:
1024 case ConversionSpecifier::kArg:
1025 return true;
1026
1027 default:
1028 return false;
1029 }
1030}
1031
1032bool PrintfSpecifier::hasValidAlternativeForm() const {
1033 if (!HasAlternativeForm)
1034 return true;
1035
1036 // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
1037 switch (CS.getKind()) {
1038 case ConversionSpecifier::bArg:
1039 case ConversionSpecifier::BArg:
1040 case ConversionSpecifier::oArg:
1041 case ConversionSpecifier::OArg:
1042 case ConversionSpecifier::xArg:
1043 case ConversionSpecifier::XArg:
1044 case ConversionSpecifier::aArg:
1045 case ConversionSpecifier::AArg:
1046 case ConversionSpecifier::eArg:
1047 case ConversionSpecifier::EArg:
1048 case ConversionSpecifier::fArg:
1049 case ConversionSpecifier::FArg:
1050 case ConversionSpecifier::gArg:
1051 case ConversionSpecifier::GArg:
1052 case ConversionSpecifier::FreeBSDrArg:
1053 case ConversionSpecifier::FreeBSDyArg:
1054 case ConversionSpecifier::rArg:
1055 case ConversionSpecifier::RArg:
1056 case ConversionSpecifier::kArg:
1057 case ConversionSpecifier::KArg:
1058 return true;
1059
1060 default:
1061 return false;
1062 }
1063}
1064
1065bool PrintfSpecifier::hasValidLeadingZeros() const {
1066 if (!HasLeadingZeroes)
1067 return true;
1068
1069 // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
1070 switch (CS.getKind()) {
1071 case ConversionSpecifier::bArg:
1072 case ConversionSpecifier::BArg:
1073 case ConversionSpecifier::dArg:
1074 case ConversionSpecifier::DArg:
1075 case ConversionSpecifier::iArg:
1076 case ConversionSpecifier::oArg:
1077 case ConversionSpecifier::OArg:
1078 case ConversionSpecifier::uArg:
1079 case ConversionSpecifier::UArg:
1080 case ConversionSpecifier::xArg:
1081 case ConversionSpecifier::XArg:
1082 case ConversionSpecifier::aArg:
1083 case ConversionSpecifier::AArg:
1084 case ConversionSpecifier::eArg:
1085 case ConversionSpecifier::EArg:
1086 case ConversionSpecifier::fArg:
1087 case ConversionSpecifier::FArg:
1088 case ConversionSpecifier::gArg:
1089 case ConversionSpecifier::GArg:
1090 case ConversionSpecifier::FreeBSDrArg:
1091 case ConversionSpecifier::FreeBSDyArg:
1092 case ConversionSpecifier::rArg:
1093 case ConversionSpecifier::RArg:
1094 case ConversionSpecifier::kArg:
1095 case ConversionSpecifier::KArg:
1096 return true;
1097
1098 default:
1099 return false;
1100 }
1101}
1102
1103bool PrintfSpecifier::hasValidSpacePrefix() const {
1104 if (!HasSpacePrefix)
1105 return true;
1106
1107 // The space prefix only makes sense for signed conversions
1108 switch (CS.getKind()) {
1109 case ConversionSpecifier::dArg:
1110 case ConversionSpecifier::DArg:
1111 case ConversionSpecifier::iArg:
1112 case ConversionSpecifier::fArg:
1113 case ConversionSpecifier::FArg:
1114 case ConversionSpecifier::eArg:
1115 case ConversionSpecifier::EArg:
1116 case ConversionSpecifier::gArg:
1117 case ConversionSpecifier::GArg:
1118 case ConversionSpecifier::aArg:
1119 case ConversionSpecifier::AArg:
1120 case ConversionSpecifier::FreeBSDrArg:
1121 case ConversionSpecifier::FreeBSDyArg:
1122 case ConversionSpecifier::rArg:
1123 case ConversionSpecifier::kArg:
1124 return true;
1125
1126 default:
1127 return false;
1128 }
1129}
1130
1131bool PrintfSpecifier::hasValidLeftJustified() const {
1132 if (!IsLeftJustified)
1133 return true;
1134
1135 // The left justified flag is valid for all conversions except n
1136 switch (CS.getKind()) {
1137 case ConversionSpecifier::nArg:
1138 return false;
1139
1140 default:
1141 return true;
1142 }
1143}
1144
1145bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
1146 if (!HasThousandsGrouping)
1147 return true;
1148
1149 switch (CS.getKind()) {
1150 case ConversionSpecifier::dArg:
1151 case ConversionSpecifier::DArg:
1152 case ConversionSpecifier::iArg:
1153 case ConversionSpecifier::uArg:
1154 case ConversionSpecifier::UArg:
1155 case ConversionSpecifier::fArg:
1156 case ConversionSpecifier::FArg:
1157 case ConversionSpecifier::gArg:
1158 case ConversionSpecifier::GArg:
1159 return true;
1160 default:
1161 return false;
1162 }
1163}
1164
1165bool PrintfSpecifier::hasValidPrecision() const {
1166 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1167 return true;
1168
1169 // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
1170 switch (CS.getKind()) {
1171 case ConversionSpecifier::bArg:
1172 case ConversionSpecifier::BArg:
1173 case ConversionSpecifier::dArg:
1174 case ConversionSpecifier::DArg:
1175 case ConversionSpecifier::iArg:
1176 case ConversionSpecifier::oArg:
1177 case ConversionSpecifier::OArg:
1178 case ConversionSpecifier::uArg:
1179 case ConversionSpecifier::UArg:
1180 case ConversionSpecifier::xArg:
1181 case ConversionSpecifier::XArg:
1182 case ConversionSpecifier::aArg:
1183 case ConversionSpecifier::AArg:
1184 case ConversionSpecifier::eArg:
1185 case ConversionSpecifier::EArg:
1186 case ConversionSpecifier::fArg:
1187 case ConversionSpecifier::FArg:
1188 case ConversionSpecifier::gArg:
1189 case ConversionSpecifier::GArg:
1190 case ConversionSpecifier::sArg:
1191 case ConversionSpecifier::FreeBSDrArg:
1192 case ConversionSpecifier::FreeBSDyArg:
1193 case ConversionSpecifier::PArg:
1194 case ConversionSpecifier::rArg:
1195 case ConversionSpecifier::RArg:
1196 case ConversionSpecifier::kArg:
1197 case ConversionSpecifier::KArg:
1198 return true;
1199
1200 default:
1201 return false;
1202 }
1203}
1204bool PrintfSpecifier::hasValidFieldWidth() const {
1205 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1206 return true;
1207
1208 // The field width is valid for all conversions except n
1209 switch (CS.getKind()) {
1210 case ConversionSpecifier::nArg:
1211 return false;
1212
1213 default:
1214 return true;
1215 }
1216}
1217