clang 22.0.0git
PrintfFormatString.cpp
Go to the documentation of this file.
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"
16#include "clang/AST/OSLog.h"
18#include "llvm/Support/Regex.h"
19
26
27using namespace clang;
28
31
32//===----------------------------------------------------------------------===//
33// Methods for parsing format strings.
34//===----------------------------------------------------------------------===//
35
37
39 const char *Start, const char *&Beg, const char *E,
40 unsigned *argIndex) {
41 if (argIndex) {
42 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
43 } else {
44 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
46 if (Amt.isInvalid())
47 return true;
48 FS.setPrecision(Amt);
49 }
50 return false;
51}
52
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(FlagBeg, E - FlagBeg);
65 else
66 H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg);
67 }
68 return true;
69}
70
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(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(Start, E - Start);
109 return true;
110 }
111
113 if (ParseArgPosition(H, FS, Start, I, E))
114 return true;
115
116 if (I == E) {
117 // No more characters left?
118 if (Warn)
119 H.HandleIncompleteSpecifier(Start, 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);
135
136 if (R.match(Str, &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("mask")) {
144 StringRef MaskType = MatchedStr.substr(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")
151 else if (PrivacyFlags !=
153 MatchedStr == "private")
155 else if (PrivacyFlags == 0 && MatchedStr == "public")
157 } else {
158 size_t CommaOrBracePos =
159 Str.find_if([](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(Start, 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;
178 FS.setIsPrivate(MatchedStr.data());
179 break;
181 FS.setIsPublic(MatchedStr.data());
182 break;
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?
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(Start, E - Start);
214 return true;
215 }
216
217 // Look for the field width (if any).
218 if (ParseFieldWidth(H, FS, Start, I, E,
219 FS.usesPositionalArg() ? nullptr : &argIndex))
220 return true;
221
222 if (I == E) {
223 // No more characters left?
224 if (Warn)
225 H.HandleIncompleteSpecifier(Start, 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(Start, E - Start);
235 return true;
236 }
237
238 if (ParsePrecision(H, FS, Start, I, E,
239 FS.usesPositionalArg() ? nullptr : &argIndex))
240 return true;
241
242 if (I == E) {
243 // No more characters left?
244 if (Warn)
245 H.HandleIncompleteSpecifier(Start, E - Start);
246 return true;
247 }
248 }
249
250 if (ParseVectorModifier(H, FS, I, E, LO))
251 return true;
252
253 // Look for the length modifier.
254 if (ParseLengthModifier(FS, I, E, LO) && I == E) {
255 // No more characters left?
256 if (Warn)
257 H.HandleIncompleteSpecifier(Start, 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(Start, E - Start);
278 return true;
279 }
280 // Did we find the closing ']'?
281 if (*I == ']') {
282 if (ParseObjCFlags(H, FS, flagStart, 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(I);
296 return true;
297 }
298
299 // Finally, look for the conversion specifier.
300 const char *conversionPosition = I++;
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)
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
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':
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)
351 else if (LO.FixedPoint)
353 break;
354 case 'y':
355 if (isFreeBSDKPrintf)
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())
364 break;
365 case 'O':
366 if (Target.getTriple().isOSDarwin())
368 break;
369 case 'U':
370 if (Target.getTriple().isOSDarwin())
372 break;
373 // MS specific.
374 case 'Z':
375 if (Target.getTriple().isOSMSVCRT())
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)
383 break;
384 case 'K':
385 if (LO.FixedPoint)
387 break;
388 case 'R':
389 if (LO.FixedPoint)
391 break;
392 }
393
394 // Check to see if we used the Objective-C modifier flags with
395 // a conversion specifier other than '@'.
398 ObjCModifierFlagsStart) {
399 H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
400 ObjCModifierFlagsEnd + 1,
401 conversionPosition);
402 return true;
403 }
404
405 PrintfConversionSpecifier CS(conversionPosition, k);
407 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
408 FS.setArgIndex(argIndex++);
409 // FreeBSD kernel specific.
412 argIndex++;
413
415 unsigned Len = I - Start;
416 if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
417 CS.setEndScanList(Start + Len);
419 }
420 // Assume the conversion takes one argument.
421 return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
422 }
423 return PrintfSpecifierResult(Start, FS);
424}
425
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, I, E, argIndex,
438 LO, Target, 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(FSR.getValue(), FSR.getStart(),
450 I - FSR.getStart(), Target))
451 return true;
452 }
453 assert(I == E && "Format string not exhausted");
454 return false;
455}
456
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.
466 while (I != E) {
467 const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
468 LO, Target, false,
469 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;
479 // Return true if this a %s format specifier.
481 return true;
482 }
483 return false;
484}
485
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.
492 while (Begin != End) {
493 const PrintfSpecifierResult &FSR =
494 ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, 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 {
510 switch (LM.getKind()) {
512 return Ctx.IntTy;
515 return ArgType(ArgType::WIntTy, "wint_t");
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()) {
527 // GNU extension.
528 return Ctx.LongLongTy;
531 return Ctx.IntTy;
533 return ArgType(Ctx.IntTy, "__int32");
535 return ArgType::AnyCharTy;
536 case LengthModifier::AsShort: return Ctx.ShortTy;
537 case LengthModifier::AsLong: return Ctx.LongTy;
540 return Ctx.LongLongTy;
542 return ArgType(Ctx.LongLongTy, "__int64");
544 return ArgType(Ctx.getIntMaxType(), "intmax_t");
546 return ArgType::makeSizeT(
547 ArgType(Ctx.getSignedSizeType(), "signed size_t"));
549 return Ctx.getTargetInfo().getTriple().isArch64Bit()
550 ? ArgType(Ctx.LongLongTy, "__int64")
551 : ArgType(Ctx.IntTy, "__int32");
554 ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
558 return ArgType::Invalid();
559 }
560
561 if (CS.isUIntArg())
562 switch (LM.getKind()) {
564 // GNU extension.
565 return Ctx.UnsignedLongLongTy;
568 return Ctx.UnsignedIntTy;
570 return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
571 case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
573 case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
576 return Ctx.UnsignedLongLongTy;
578 return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
580 return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
582 return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
584 return Ctx.getTargetInfo().getTriple().isArch64Bit()
585 ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
586 : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
589 ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
593 return ArgType::Invalid();
594 }
595
596 if (CS.isDoubleArg()) {
597 if (!VectorNumElts.isInvalid()) {
598 switch (LM.getKind()) {
600 return Ctx.HalfTy;
602 return Ctx.FloatTy;
604 default:
605 return Ctx.DoubleTy;
606 }
607 }
608
609 if (LM.getKind() == LengthModifier::AsLongDouble)
610 return Ctx.LongDoubleTy;
611 return Ctx.DoubleTy;
612 }
613
614 if (CS.getKind() == ConversionSpecifier::nArg) {
615 switch (LM.getKind()) {
617 return ArgType::PtrTo(Ctx.IntTy);
619 return ArgType::PtrTo(Ctx.SignedCharTy);
621 return ArgType::PtrTo(Ctx.ShortTy);
623 return ArgType::PtrTo(Ctx.LongTy);
626 return ArgType::PtrTo(Ctx.LongLongTy);
628 return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
631 ArgType(Ctx.getSignedSizeType(), "signed size_t")));
634 ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));
636 return ArgType(); // FIXME: Is this a known extension?
643 return ArgType::Invalid();
645 llvm_unreachable("only used for OpenCL which doesn not handle nArg");
646 }
647 }
648
649 if (CS.isFixedPointArg() && !Ctx.getLangOpts().FixedPoint)
650 return ArgType::Invalid();
651
652 switch (CS.getKind()) {
654 if (LM.getKind() == LengthModifier::AsWideChar) {
655 if (IsObjCLiteral)
656 return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
657 "const unichar *");
658 return ArgType(ArgType::WCStrTy, "wchar_t *");
659 }
660 if (LM.getKind() == LengthModifier::AsWide)
661 return ArgType(ArgType::WCStrTy, "wchar_t *");
662 return ArgType::CStrTy;
664 if (IsObjCLiteral)
665 return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
666 "const unichar *");
667 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
668 LM.getKind() == LengthModifier::AsShort)
669 return ArgType::CStrTy;
670 return ArgType(ArgType::WCStrTy, "wchar_t *");
672 if (IsObjCLiteral)
673 return ArgType(Ctx.UnsignedShortTy, "unichar");
674 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
675 LM.getKind() == LengthModifier::AsShort)
676 return Ctx.IntTy;
677 return ArgType(Ctx.WideCharTy, "wchar_t");
680 return ArgType::CPointerTy;
684 switch (LM.getKind()) {
686 return Ctx.AccumTy;
688 return Ctx.ShortAccumTy;
690 return Ctx.LongAccumTy;
691 default:
692 return ArgType::Invalid();
693 }
695 switch (LM.getKind()) {
697 return Ctx.UnsignedAccumTy;
699 return Ctx.UnsignedShortAccumTy;
701 return Ctx.UnsignedLongAccumTy;
702 default:
703 return ArgType::Invalid();
704 }
706 switch (LM.getKind()) {
708 return Ctx.FractTy;
710 return Ctx.ShortFractTy;
712 return Ctx.LongFractTy;
713 default:
714 return ArgType::Invalid();
715 }
717 switch (LM.getKind()) {
719 return Ctx.UnsignedFractTy;
721 return Ctx.UnsignedShortFractTy;
723 return Ctx.UnsignedLongFractTy;
724 default:
725 return ArgType::Invalid();
726 }
727 default:
728 break;
729 }
730
731 // FIXME: Handle other cases.
732 return ArgType();
733}
734
735
737 bool IsObjCLiteral) const {
739
740 if (!CS.consumesDataArgument())
741 return ArgType::Invalid();
742
743 ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
744 if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
745 return ScalarTy;
746
747 return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());
748}
749
751 ASTContext &Ctx, bool IsObjCLiteral) {
752 // %n is different from other conversion specifiers; don't try to fix it.
753 if (CS.getKind() == ConversionSpecifier::nArg)
754 return false;
755
756 // Handle Objective-C objects first. Note that while the '%@' specifier will
757 // not warn for structure pointer or void pointer arguments (because that's
758 // how CoreFoundation objects are implemented), we only show a fixit for '%@'
759 // if we know it's an object (block, id, class, or __attribute__((NSObject))).
760 if (QT->isObjCRetainableType()) {
761 if (!IsObjCLiteral)
762 return false;
763
765
766 // Disable irrelevant flags
767 HasThousandsGrouping = false;
768 HasPlusPrefix = false;
769 HasSpacePrefix = false;
770 HasAlternativeForm = false;
771 HasLeadingZeroes = false;
772 Precision.setHowSpecified(OptionalAmount::NotSpecified);
773 LM.setKind(LengthModifier::None);
774
775 return true;
776 }
777
778 // Handle strings next (char *, wchar_t *)
779 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
781
782 // Disable irrelevant flags
783 HasAlternativeForm = false;
784 HasLeadingZeroes = false;
785
786 // Set the long length modifier for wide characters
787 if (QT->getPointeeType()->isWideCharType())
789 else
790 LM.setKind(LengthModifier::None);
791
792 return true;
793 }
794
795 // If it's an enum, get its underlying type.
796 if (const auto *ED = QT->getAsEnumDecl())
797 QT = ED->getIntegerType();
798
799 const BuiltinType *BT = QT->getAs<BuiltinType>();
800 if (!BT) {
801 const VectorType *VT = QT->getAs<VectorType>();
802 if (VT) {
803 QT = VT->getElementType();
804 BT = QT->getAs<BuiltinType>();
806 }
807 }
808
809 // We can only work with builtin types.
810 if (!BT)
811 return false;
812
813 // Set length modifier
814 switch (BT->getKind()) {
815 case BuiltinType::Bool:
816 case BuiltinType::WChar_U:
817 case BuiltinType::WChar_S:
818 case BuiltinType::Char8: // FIXME: Treat like 'char'?
819 case BuiltinType::Char16:
820 case BuiltinType::Char32:
821 case BuiltinType::UInt128:
822 case BuiltinType::Int128:
823 case BuiltinType::Half:
824 case BuiltinType::BFloat16:
825 case BuiltinType::Float16:
826 case BuiltinType::Float128:
827 case BuiltinType::Ibm128:
828 case BuiltinType::ShortAccum:
829 case BuiltinType::Accum:
830 case BuiltinType::LongAccum:
831 case BuiltinType::UShortAccum:
832 case BuiltinType::UAccum:
833 case BuiltinType::ULongAccum:
834 case BuiltinType::ShortFract:
835 case BuiltinType::Fract:
836 case BuiltinType::LongFract:
837 case BuiltinType::UShortFract:
838 case BuiltinType::UFract:
839 case BuiltinType::ULongFract:
840 case BuiltinType::SatShortAccum:
841 case BuiltinType::SatAccum:
842 case BuiltinType::SatLongAccum:
843 case BuiltinType::SatUShortAccum:
844 case BuiltinType::SatUAccum:
845 case BuiltinType::SatULongAccum:
846 case BuiltinType::SatShortFract:
847 case BuiltinType::SatFract:
848 case BuiltinType::SatLongFract:
849 case BuiltinType::SatUShortFract:
850 case BuiltinType::SatUFract:
851 case BuiltinType::SatULongFract:
852 // Various types which are non-trivial to correct.
853 return false;
854
855#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
856 case BuiltinType::Id:
857#include "clang/Basic/OpenCLImageTypes.def"
858#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
859 case BuiltinType::Id:
860#include "clang/Basic/OpenCLExtensionTypes.def"
861#define SVE_TYPE(Name, Id, SingletonId) \
862 case BuiltinType::Id:
863#include "clang/Basic/AArch64ACLETypes.def"
864#define PPC_VECTOR_TYPE(Name, Id, Size) \
865 case BuiltinType::Id:
866#include "clang/Basic/PPCTypes.def"
867#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
868#include "clang/Basic/RISCVVTypes.def"
869#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
870#include "clang/Basic/WebAssemblyReferenceTypes.def"
871#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
872#include "clang/Basic/AMDGPUTypes.def"
873#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
874#include "clang/Basic/HLSLIntangibleTypes.def"
875#define SIGNED_TYPE(Id, SingletonId)
876#define UNSIGNED_TYPE(Id, SingletonId)
877#define FLOATING_TYPE(Id, SingletonId)
878#define BUILTIN_TYPE(Id, SingletonId) \
879 case BuiltinType::Id:
880#include "clang/AST/BuiltinTypes.def"
881 // Misc other stuff which doesn't make sense here.
882 return false;
883
884 case BuiltinType::UInt:
885 case BuiltinType::Int:
886 case BuiltinType::Float:
887 LM.setKind(VectorNumElts.isInvalid() ?
889 break;
890 case BuiltinType::Double:
891 LM.setKind(VectorNumElts.isInvalid() ?
893 break;
894 case BuiltinType::Char_U:
895 case BuiltinType::UChar:
896 case BuiltinType::Char_S:
897 case BuiltinType::SChar:
898 LM.setKind(LengthModifier::AsChar);
899 break;
900
901 case BuiltinType::Short:
902 case BuiltinType::UShort:
904 break;
905
906 case BuiltinType::Long:
907 case BuiltinType::ULong:
908 LM.setKind(LengthModifier::AsLong);
909 break;
910
911 case BuiltinType::LongLong:
912 case BuiltinType::ULongLong:
914 break;
915
916 case BuiltinType::LongDouble:
918 break;
919 }
920
921 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
922 if (LangOpt.C99 || LangOpt.CPlusPlus11)
924
925 // If fixing the length modifier was enough, we might be done.
926 if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
927 // If we're going to offer a fix anyway, make sure the sign matches.
928 switch (CS.getKind()) {
931 if (QT->isSignedIntegerType())
933 break;
937 if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
939 break;
940 default:
941 // Other specifiers do not have signed/unsigned variants.
942 break;
943 }
944
945 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
946 if (ATR.isValid() && ATR.matchesType(Ctx, QT))
947 return true;
948 }
949
950 // Set conversion specifier and disable any flags which do not apply to it.
951 // Let typedefs to char fall through to int, as %c is silly for uint8_t.
952 if (!QT->getAs<TypedefType>() && QT->isCharType()) {
954 LM.setKind(LengthModifier::None);
955 Precision.setHowSpecified(OptionalAmount::NotSpecified);
956 HasAlternativeForm = false;
957 HasLeadingZeroes = false;
958 HasPlusPrefix = false;
959 }
960 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
961 else if (QT->isRealFloatingType()) {
963 } else if (QT->isSignedIntegerType()) {
965 HasAlternativeForm = false;
966 } else if (QT->isUnsignedIntegerType()) {
968 HasAlternativeForm = false;
969 HasPlusPrefix = false;
970 } else {
971 llvm_unreachable("Unexpected type");
972 }
973
974 return true;
975}
976
977void PrintfSpecifier::toString(raw_ostream &os) const {
978 // Whilst some features have no defined order, we are using the order
979 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
980 os << "%";
981
982 // Positional args
983 if (usesPositionalArg()) {
984 os << getPositionalArgIndex() << "$";
985 }
986
987 // Conversion flags
988 if (IsLeftJustified) os << "-";
989 if (HasPlusPrefix) os << "+";
990 if (HasSpacePrefix) os << " ";
991 if (HasAlternativeForm) os << "#";
992 if (HasLeadingZeroes) os << "0";
993
994 // Minimum field width
995 FieldWidth.toString(os);
996 // Precision
997 Precision.toString(os);
998
999 // Vector modifier
1000 if (!VectorNumElts.isInvalid())
1001 os << 'v' << VectorNumElts.getConstantAmount();
1002
1003 // Length modifier
1004 os << LM.toString();
1005 // Conversion specifier
1006 os << CS.toString();
1007}
1008
1010 if (!HasPlusPrefix)
1011 return true;
1012
1013 // The plus prefix only makes sense for signed conversions
1014 switch (CS.getKind()) {
1030 return true;
1031
1032 default:
1033 return false;
1034 }
1035}
1036
1038 if (!HasAlternativeForm)
1039 return true;
1040
1041 // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
1042 switch (CS.getKind()) {
1063 return true;
1064
1065 default:
1066 return false;
1067 }
1068}
1069
1071 if (!HasLeadingZeroes)
1072 return true;
1073
1074 // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
1075 switch (CS.getKind()) {
1101 return true;
1102
1103 default:
1104 return false;
1105 }
1106}
1107
1109 if (!HasSpacePrefix)
1110 return true;
1111
1112 // The space prefix only makes sense for signed conversions
1113 switch (CS.getKind()) {
1129 return true;
1130
1131 default:
1132 return false;
1133 }
1134}
1135
1137 if (!IsLeftJustified)
1138 return true;
1139
1140 // The left justified flag is valid for all conversions except n
1141 switch (CS.getKind()) {
1143 return false;
1144
1145 default:
1146 return true;
1147 }
1148}
1149
1151 if (!HasThousandsGrouping)
1152 return true;
1153
1154 switch (CS.getKind()) {
1164 return true;
1165 default:
1166 return false;
1167 }
1168}
1169
1171 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1172 return true;
1173
1174 // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
1175 switch (CS.getKind()) {
1203 return true;
1204
1205 default:
1206 return false;
1207 }
1208}
1210 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1211 return true;
1212
1213 // The field width is valid for all conversions except n
1214 switch (CS.getKind()) {
1216 return false;
1217
1218 default:
1219 return true;
1220 }
1221}
llvm::MachO::Target Target
Definition MachO.h:51
clang::analyze_format_string::SpecifierResult< PrintfSpecifier > PrintfSpecifierResult
static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, const char *Start, const char *&Beg, const char *E, unsigned *argIndex)
static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, const LangOptions &LO, const TargetInfo &Target, bool Warn, bool isFreeBSDKPrintf)
static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, const char *FlagBeg, const char *E, bool Warn)
__device__ __2f16 float c
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:188
CanQualType AccumTy
CanQualType LongTy
CanQualType UnsignedShortAccumTy
QualType getUnsignedPointerDiffType() const
Return the unique unsigned counterpart of "ptrdiff_t" integer type.
CanQualType ShortAccumTy
CanQualType FloatTy
CanQualType DoubleTy
CanQualType getIntMaxType() const
Return the unique type for "intmax_t" (C99 7.18.1.5), defined in <stdint.h>.
CanQualType LongDoubleTy
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
CanQualType UnsignedLongFractTy
CanQualType WideCharTy
const LangOptions & getLangOpts() const
Definition ASTContext.h:891
QualType getPointerDiffType() const
Return the unique type for "ptrdiff_t" (C99 7.17) defined in <stddef.h>.
CanQualType UnsignedFractTy
CanQualType UnsignedLongTy
CanQualType UnsignedLongAccumTy
CanQualType ShortFractTy
CanQualType IntTy
CanQualType SignedCharTy
CanQualType UnsignedCharTy
CanQualType UnsignedShortFractTy
CanQualType UnsignedIntTy
CanQualType UnsignedLongLongTy
CanQualType UnsignedShortTy
CanQualType ShortTy
CanQualType FractTy
CanQualType LongAccumTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:856
CanQualType LongFractTy
QualType getSignedSizeType() const
Return the unique signed counterpart of the integer type corresponding to size_t.
CanQualType LongLongTy
CanQualType getUIntMaxType() const
Return the unique type for "uintmax_t" (C99 7.18.1.5), defined in <stdint.h>.
CanQualType HalfTy
CanQualType UnsignedAccumTy
This class is used for builtin types like 'int'.
Definition TypeBase.h:3164
Kind getKind() const
Definition TypeBase.h:3212
QualType withConst() const
Retrieves a version of this type with const applied.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
A (possibly-)qualified type.
Definition TypeBase.h:937
Exposes information about the current target.
Definition TargetInfo.h:226
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2205
bool isCharType() const
Definition Type.cpp:2132
bool isPointerType() const
Definition TypeBase.h:8522
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:752
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
Definition Type.cpp:2168
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
Definition Type.h:53
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2320
bool isWideCharType() const
Definition Type.cpp:2141
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition Type.cpp:2253
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9101
bool isObjCRetainableType() const
Definition Type.cpp:5291
Represents a GCC generic vector type.
Definition TypeBase.h:4173
unsigned getNumElements() const
Definition TypeBase.h:4188
QualType getElementType() const
Definition TypeBase.h:4187
ArgType makeVectorType(ASTContext &C, unsigned NumElts) const
MatchKind matchesType(ASTContext &C, QualType argTy) const
static bool namedTypeToLengthModifier(ASTContext &Ctx, QualType QT, LengthModifier &LM)
For a TypedefType QT, if it is a named integer type such as size_t, assign the appropriate value to L...
bool hasValidLengthModifier(const TargetInfo &Target, const LangOptions &LO) const
virtual bool HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen)
virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, const char *flagsEnd, const char *conversionPosition)
virtual void HandleInvalidObjCModifierFlag(const char *startFlag, unsigned flagLen)
virtual void HandleNullChar(const char *nullCharacter)
virtual void handleInvalidMaskType(StringRef MaskType)
Handle mask types whose sizes are not between one and eight bytes.
virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen, const TargetInfo &Target)
virtual void HandleEmptyObjCModifierFlag(const char *startFlags, unsigned flagsLen)
virtual void HandleIncompleteSpecifier(const char *startSpecifier, unsigned specifierLen)
Represents the length modifier in a format string in scanf/printf.
static ArgType makePtrdiffT(const ArgType &A)
Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t type.
static ArgType PtrTo(const ArgType &A)
Create an ArgType which corresponds to the type pointer to A.
static ArgType makeSizeT(const ArgType &A)
Create an ArgType which corresponds to the size_t/ssize_t type.
void setHasAlternativeForm(const char *position)
void setIsSensitive(const char *position)
void setHasSpacePrefix(const char *position)
void setHasThousandsGrouping(const char *position)
void setIsLeftJustified(const char *position)
bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, bool IsObjCLiteral)
Changes the specifier and length according to a QualType, retaining any flags or options.
void setHasPlusPrefix(const char *position)
void setIsPrivate(const char *position)
const PrintfConversionSpecifier & getConversionSpecifier() const
void setHasLeadingZeros(const char *position)
ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const
Returns the builtin type that a data argument paired with this format specifier should have.
void setIsPublic(const char *position)
void setPrecision(const OptionalAmount &Amt)
void setHasObjCTechnicalTerm(const char *position)
void setConversionSpecifier(const PrintfConversionSpecifier &cs)
Defines the clang::TargetInfo interface.
Common components of both fprintf and fscanf format strings.
bool parseFormatStringHasFormattingSpecifiers(const char *Begin, const char *End, const LangOptions &LO, const TargetInfo &Target)
Return true if the given string has at least one formatting specifier.
bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &CS, const char *Start, const char *&Beg, const char *E, unsigned *argIndex)
OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E, unsigned &argIndex)
bool ParsePrintfString(FormatStringHandler &H, const char *beg, const char *end, const LangOptions &LO, const TargetInfo &Target, bool isFreeBSDKPrintf)
bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E, const LangOptions &LO, bool IsScanf=false)
Returns true if a LengthModifier was parsed and installed in the FormatSpecifier& argument,...
bool ParseArgPosition(FormatStringHandler &H, FormatSpecifier &CS, const char *Start, const char *&Beg, const char *E)
bool ParseVectorModifier(FormatStringHandler &H, FormatSpecifier &FS, const char *&Beg, const char *E, const LangOptions &LO)
bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO, const TargetInfo &Target)
bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len)
Returns true if the invalid specifier in SpecifierBegin is a UTF-8 string; check that it won't go fur...
Pieces specific to fprintf format strings.
The JSON file list parser is used to communicate input to InstallAPI.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
Definition Sema.h:816