clang 23.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(
45 H, Start, Beg, E, analyze_format_string::PrecisionPos);
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
72ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
73 unsigned &argIndex, const LangOptions &LO,
74 const TargetInfo &Target, bool Warn,
75 bool isFreeBSDKPrintf) {
76
77 using namespace clang::analyze_format_string;
78 using namespace clang::analyze_printf;
79
80 const char *I = Beg;
81 const char *Start = nullptr;
82 UpdateOnReturn<const char *> UpdateBeg(Beg, I);
83
84 // Look for a '%' character that indicates the start of a format specifier.
85 for (; I != E; ++I) {
86 char c = *I;
87 if (c == '\0') {
88 // Detect spurious null characters, which are likely errors.
89 H.HandleNullChar(I);
90 return true;
91 }
92 if (c == '%') {
93 Start = I++; // Record the start of the format specifier.
94 break;
95 }
96 }
97
98 // No format specifier found?
99 if (!Start)
100 return false;
101
102 if (I == E) {
103 // No more characters left?
104 if (Warn)
105 H.HandleIncompleteSpecifier(Start, E - Start);
106 return true;
107 }
108
110 if (ParseArgPosition(H, FS, Start, I, E))
111 return true;
112
113 if (I == E) {
114 // No more characters left?
115 if (Warn)
116 H.HandleIncompleteSpecifier(Start, E - Start);
117 return true;
118 }
119
120 if (*I == '{') {
121 ++I;
122 unsigned char PrivacyFlags = 0;
123 StringRef MatchedStr;
124
125 do {
126 StringRef Str(I, E - I);
127 std::string Match = "^[[:space:]]*"
128 "(private|public|sensitive|mask\\.[^[:space:],}]*)"
129 "[[:space:]]*(,|})";
130 llvm::Regex R(Match);
132
133 if (R.match(Str, &Matches)) {
134 MatchedStr = Matches[1];
135 I += Matches[0].size();
136
137 // Set the privacy flag if the privacy annotation in the
138 // comma-delimited segment is at least as strict as the privacy
139 // annotations in previous comma-delimited segments.
140 if (MatchedStr.starts_with("mask")) {
141 StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
142 unsigned Size = MaskType.size();
143 if (Warn && (Size == 0 || Size > 8))
144 H.handleInvalidMaskType(MaskType);
145 FS.setMaskType(MaskType);
146 } else if (MatchedStr == "sensitive")
148 else if (PrivacyFlags !=
150 MatchedStr == "private")
152 else if (PrivacyFlags == 0 && MatchedStr == "public")
154 } else {
155 size_t CommaOrBracePos =
156 Str.find_if([](char c) { return c == ',' || c == '}'; });
157
158 if (CommaOrBracePos == StringRef::npos) {
159 // Neither a comma nor the closing brace was found.
160 if (Warn)
161 H.HandleIncompleteSpecifier(Start, E - Start);
162 return true;
163 }
164
165 I += CommaOrBracePos + 1;
166 }
167 // Continue until the closing brace is found.
168 } while (*(I - 1) == ',');
169
170 // Set the privacy flag.
171 switch (PrivacyFlags) {
172 case 0:
173 break;
175 FS.setIsPrivate(MatchedStr.data());
176 break;
178 FS.setIsPublic(MatchedStr.data());
179 break;
181 FS.setIsSensitive(MatchedStr.data());
182 break;
183 default:
184 llvm_unreachable("Unexpected privacy flag value");
185 }
186 }
187
188 // Look for flags (if any).
189 bool hasMore = true;
190 for (; I != E; ++I) {
191 switch (*I) {
192 default:
193 hasMore = false;
194 break;
195 case '\'':
196 // FIXME: POSIX specific. Always accept?
198 break;
199 case '-':
200 FS.setIsLeftJustified(I);
201 break;
202 case '+':
203 FS.setHasPlusPrefix(I);
204 break;
205 case ' ':
206 FS.setHasSpacePrefix(I);
207 break;
208 case '#':
210 break;
211 case '0':
212 FS.setHasLeadingZeros(I);
213 break;
214 }
215 if (!hasMore)
216 break;
217 }
218
219 if (I == E) {
220 // No more characters left?
221 if (Warn)
222 H.HandleIncompleteSpecifier(Start, E - Start);
223 return true;
224 }
225
226 // Look for the field width (if any).
227 if (ParseFieldWidth(H, FS, Start, I, E,
228 FS.usesPositionalArg() ? nullptr : &argIndex))
229 return true;
230
231 if (I == E) {
232 // No more characters left?
233 if (Warn)
234 H.HandleIncompleteSpecifier(Start, E - Start);
235 return true;
236 }
237
238 // Look for the precision (if any).
239 if (*I == '.') {
240 ++I;
241 if (I == E) {
242 if (Warn)
243 H.HandleIncompleteSpecifier(Start, E - Start);
244 return true;
245 }
246
247 if (ParsePrecision(H, FS, Start, I, E,
248 FS.usesPositionalArg() ? nullptr : &argIndex))
249 return true;
250
251 if (I == E) {
252 // No more characters left?
253 if (Warn)
254 H.HandleIncompleteSpecifier(Start, E - Start);
255 return true;
256 }
257 }
258
259 if (ParseVectorModifier(H, FS, I, E, LO))
260 return true;
261
262 // Look for the length modifier.
263 if (ParseLengthModifier(FS, I, E, LO) && I == E) {
264 // No more characters left?
265 if (Warn)
266 H.HandleIncompleteSpecifier(Start, E - Start);
267 return true;
268 }
269
270 // Look for the Objective-C modifier flags, if any.
271 // We parse these here, even if they don't apply to
272 // the conversion specifier, and then emit an error
273 // later if the conversion specifier isn't '@'. This
274 // enables better recovery, and we don't know if
275 // these flags are applicable until later.
276 const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr;
277 if (*I == '[') {
278 ObjCModifierFlagsStart = I;
279 ++I;
280 auto flagStart = I;
281 for (;; ++I) {
282 ObjCModifierFlagsEnd = I;
283 if (I == E) {
284 if (Warn)
285 H.HandleIncompleteSpecifier(Start, E - Start);
286 return true;
287 }
288 // Did we find the closing ']'?
289 if (*I == ']') {
290 if (ParseObjCFlags(H, FS, flagStart, I, Warn))
291 return true;
292 ++I;
293 break;
294 }
295 // There are no separators defined yet for multiple
296 // Objective-C modifier flags. When those are
297 // defined, this is the place to check.
298 }
299 }
300
301 if (*I == '\0') {
302 // Detect spurious null characters, which are likely errors.
303 H.HandleNullChar(I);
304 return true;
305 }
306
307 // Finally, look for the conversion specifier.
308 const char *conversionPosition = I++;
310 switch (*conversionPosition) {
311 default:
312 break;
313 // C99: 7.19.6.1 (section 8).
314 case '%':
316 break;
317 case 'A':
319 break;
320 case 'E':
322 break;
323 case 'F':
325 break;
326 case 'G':
328 break;
329 case 'X':
331 break;
332 case 'a':
334 break;
335 case 'c':
337 break;
338 case 'd':
340 break;
341 case 'e':
343 break;
344 case 'f':
346 break;
347 case 'g':
349 break;
350 case 'i':
352 break;
353 case 'n':
354 // Not handled, but reserved in OpenCL.
355 if (!LO.OpenCL)
357 break;
358 case 'o':
360 break;
361 case 'p':
363 break;
364 case 's':
366 break;
367 case 'u':
369 break;
370 case 'x':
372 break;
373 // C23.
374 case 'b':
375 if (isFreeBSDKPrintf)
376 k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
377 else
379 break;
380 case 'B':
382 break;
383 // POSIX specific.
384 case 'C':
386 break;
387 case 'S':
389 break;
390 // Apple extension for os_log
391 case 'P':
393 break;
394 // Objective-C.
395 case '@':
397 break;
398 // Glibc specific.
399 case 'm':
401 break;
402 case 'r':
403 if (isFreeBSDKPrintf)
405 else if (LO.FixedPoint)
407 break;
408 case 'y':
409 if (isFreeBSDKPrintf)
411 break;
412 // Apple-specific.
413 case 'D':
414 if (isFreeBSDKPrintf)
415 k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
416 else if (Target.getTriple().isOSDarwin())
418 break;
419 case 'O':
420 if (Target.getTriple().isOSDarwin())
422 break;
423 case 'U':
424 if (Target.getTriple().isOSDarwin())
426 break;
427 // MS specific.
428 case 'Z':
429 if (Target.getTriple().isOSMSVCRT())
431 break;
432 // ISO/IEC TR 18037 (fixed-point) specific.
433 // NOTE: 'r' is handled up above since FreeBSD also supports %r.
434 case 'k':
435 if (LO.FixedPoint)
437 break;
438 case 'K':
439 if (LO.FixedPoint)
441 break;
442 case 'R':
443 if (LO.FixedPoint)
445 break;
446 }
447
448 // Check to see if we used the Objective-C modifier flags with
449 // a conversion specifier other than '@'.
451 k != ConversionSpecifier::InvalidSpecifier && ObjCModifierFlagsStart) {
453 ObjCModifierFlagsStart, ObjCModifierFlagsEnd + 1, conversionPosition);
454 return true;
455 }
456
457 PrintfConversionSpecifier CS(conversionPosition, k);
459 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
460 FS.setArgIndex(argIndex++);
461 // FreeBSD kernel specific.
464 argIndex++;
465
467 unsigned Len = I - Start;
468 if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
469 CS.setEndScanList(Start + Len);
471 }
472 // Assume the conversion takes one argument.
473 return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
474 }
475 return PrintfSpecifierResult(Start, FS);
476}
477
479 FormatStringHandler &H, const char *I, const char *E, const LangOptions &LO,
480 const TargetInfo &Target, bool isFreeBSDKPrintf) {
481
482 unsigned argIndex = 0;
483
484 // Keep looking for a format specifier until we have exhausted the string.
485 while (I != E) {
487 H, I, E, argIndex, LO, Target, true, isFreeBSDKPrintf);
488 // Did a fail-stop error of any kind occur when parsing the specifier?
489 // If so, don't do any more processing.
490 if (FSR.shouldStop())
491 return true;
492 // Did we exhaust the string or encounter an error that
493 // we can recover from?
494 if (!FSR.hasValue())
495 continue;
496 // We have a format specifier. Pass it to the callback.
497 if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
498 I - FSR.getStart(), Target))
499 return true;
500 }
501 assert(I == E && "Format string not exhausted");
502 return false;
503}
504
506 const char *I, const char *E, const LangOptions &LO,
507 const TargetInfo &Target) {
508
509 unsigned argIndex = 0;
510
511 // Keep looking for a %s format specifier until we have exhausted the string.
513 while (I != E) {
514 const PrintfSpecifierResult &FSR =
515 ParsePrintfSpecifier(H, I, E, argIndex, LO, Target, false, false);
516 // Did a fail-stop error of any kind occur when parsing the specifier?
517 // If so, don't do any more processing.
518 if (FSR.shouldStop())
519 return false;
520 // Did we exhaust the string or encounter an error that
521 // we can recover from?
522 if (!FSR.hasValue())
523 continue;
525 // Return true if this a %s format specifier.
526 if (FS.getConversionSpecifier().getKind() ==
528 return true;
529 }
530 return false;
531}
532
534 const char *Begin, const char *End, const LangOptions &LO,
535 const TargetInfo &Target) {
536 unsigned ArgIndex = 0;
537 // Keep looking for a formatting specifier until we have exhausted the string.
539 while (Begin != End) {
540 const PrintfSpecifierResult &FSR =
541 ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
542 if (FSR.shouldStop())
543 break;
544 if (FSR.hasValue())
545 return true;
546 }
547 return false;
548}
549
550//===----------------------------------------------------------------------===//
551// Methods on PrintfSpecifier.
552//===----------------------------------------------------------------------===//
553
554ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
555 bool IsObjCLiteral) const {
557 switch (LM.getKind()) {
559 return Ctx.IntTy;
562 return ArgType(ArgType::WIntTy, "wint_t");
564 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
565 return Ctx.IntTy;
566 [[fallthrough]];
567 default:
568 return ArgType::Invalid();
569 }
570
571 if (CS.isIntArg())
572 switch (LM.getKind()) {
574 // GNU extension.
575 return Ctx.LongLongTy;
578 return Ctx.IntTy;
580 return ArgType(Ctx.IntTy, "__int32");
582 return ArgType::AnyCharTy;
584 return Ctx.ShortTy;
586 return Ctx.LongTy;
589 return Ctx.LongLongTy;
591 return ArgType(Ctx.LongLongTy, "__int64");
593 return ArgType(Ctx.getIntMaxType(), "intmax_t");
595 return ArgType::makeSizeT(
596 ArgType(Ctx.getSignedSizeType(), "signed size_t"));
598 return Ctx.getTargetInfo().getTriple().isArch64Bit()
599 ? ArgType(Ctx.LongLongTy, "__int64")
600 : ArgType(Ctx.IntTy, "__int32");
603 ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
606 return ArgType::makeIntNType(Ctx, LM,
608 CS.getKind() !=
616 return ArgType::Invalid();
617 }
618
619 if (CS.isUIntArg())
620 switch (LM.getKind()) {
622 // GNU extension.
623 return Ctx.UnsignedLongLongTy;
626 return Ctx.UnsignedIntTy;
628 return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
630 return Ctx.UnsignedCharTy;
632 return Ctx.UnsignedShortTy;
634 return Ctx.UnsignedLongTy;
637 return Ctx.UnsignedLongLongTy;
639 return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
641 return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
643 return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
645 return Ctx.getTargetInfo().getTriple().isArch64Bit()
646 ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
647 : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
650 ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
653 return ArgType::makeIntNType(Ctx, LM, /*Signed=*/false);
660 return ArgType::Invalid();
661 }
662
663 if (CS.isDoubleArg()) {
664 if (!VectorNumElts.isInvalid()) {
665 switch (LM.getKind()) {
667 return Ctx.HalfTy;
669 return Ctx.FloatTy;
671 default:
672 return Ctx.DoubleTy;
673 }
674 }
675
676 switch (LM.getKind()) {
678 return Ctx.LongDoubleTy;
680 return ArgType::Unsupported("_Decimal32");
682 return ArgType::Unsupported("_Decimal64");
684 return ArgType::Unsupported("_Decimal128");
685 default:
686 return Ctx.DoubleTy;
687 }
688 }
689
690 if (CS.getKind() == ConversionSpecifier::nArg) {
691 switch (LM.getKind()) {
693 return ArgType::PtrTo(Ctx.IntTy);
695 return ArgType::PtrTo(Ctx.SignedCharTy);
697 return ArgType::PtrTo(Ctx.ShortTy);
699 return ArgType::PtrTo(Ctx.LongTy);
702 return ArgType::PtrTo(Ctx.LongLongTy);
704 return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
707 ArgType(Ctx.getSignedSizeType(), "signed size_t")));
710 ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));
713 return ArgType::PtrTo(ArgType::makeIntNType(Ctx, LM, /*Signed=*/true));
715 return ArgType(); // FIXME: Is this a known extension?
725 return ArgType::Invalid();
727 llvm_unreachable("only used for OpenCL which doesn not handle nArg");
728 }
729 }
730
731 if (CS.isFixedPointArg() && !Ctx.getLangOpts().FixedPoint)
732 return ArgType::Invalid();
733
734 switch (CS.getKind()) {
736 if (LM.getKind() == LengthModifier::AsWideChar) {
737 if (IsObjCLiteral)
738 return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
739 "const unichar *");
740 return ArgType(ArgType::WCStrTy, "wchar_t *");
741 }
742 if (LM.getKind() == LengthModifier::AsWide)
743 return ArgType(ArgType::WCStrTy, "wchar_t *");
744 return ArgType::CStrTy;
746 if (IsObjCLiteral)
747 return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
748 "const unichar *");
749 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
750 LM.getKind() == LengthModifier::AsShort)
751 return ArgType::CStrTy;
752 return ArgType(ArgType::WCStrTy, "wchar_t *");
754 if (IsObjCLiteral)
755 return ArgType(Ctx.UnsignedShortTy, "unichar");
756 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
757 LM.getKind() == LengthModifier::AsShort)
758 return Ctx.IntTy;
759 return ArgType(Ctx.WideCharTy, "wchar_t");
762 return ArgType::CPointerTy;
766 switch (LM.getKind()) {
768 return Ctx.AccumTy;
770 return Ctx.ShortAccumTy;
772 return Ctx.LongAccumTy;
773 default:
774 return ArgType::Invalid();
775 }
777 switch (LM.getKind()) {
779 return Ctx.UnsignedAccumTy;
781 return Ctx.UnsignedShortAccumTy;
783 return Ctx.UnsignedLongAccumTy;
784 default:
785 return ArgType::Invalid();
786 }
788 switch (LM.getKind()) {
790 return Ctx.FractTy;
792 return Ctx.ShortFractTy;
794 return Ctx.LongFractTy;
795 default:
796 return ArgType::Invalid();
797 }
799 switch (LM.getKind()) {
801 return Ctx.UnsignedFractTy;
803 return Ctx.UnsignedShortFractTy;
805 return Ctx.UnsignedLongFractTy;
806 default:
807 return ArgType::Invalid();
808 }
809 default:
810 break;
811 }
812
813 // FIXME: Handle other cases.
814 return ArgType();
815}
816
817ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, bool IsObjCLiteral) const {
819
820 if (!CS.consumesDataArgument())
821 return ArgType::Invalid();
822
823 ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
824 if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
825 return ScalarTy;
826
827 return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());
828}
829
831 ASTContext &Ctx, bool IsObjCLiteral) {
832 // %n is different from other conversion specifiers; don't try to fix it.
833 if (CS.getKind() == ConversionSpecifier::nArg)
834 return false;
835
836 // Handle Objective-C objects first. Note that while the '%@' specifier will
837 // not warn for structure pointer or void pointer arguments (because that's
838 // how CoreFoundation objects are implemented), we only show a fixit for '%@'
839 // if we know it's an object (block, id, class, or __attribute__((NSObject))).
840 if (QT->isObjCRetainableType()) {
841 if (!IsObjCLiteral)
842 return false;
843
845
846 // Disable irrelevant flags
847 HasThousandsGrouping = false;
848 HasPlusPrefix = false;
849 HasSpacePrefix = false;
850 HasAlternativeForm = false;
851 HasLeadingZeroes = false;
852 Precision.setHowSpecified(OptionalAmount::NotSpecified);
853 LM.setKind(LengthModifier::None);
854
855 return true;
856 }
857
858 // Handle strings next (char *, wchar_t *)
859 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
861
862 // Disable irrelevant flags
863 HasAlternativeForm = false;
864 HasLeadingZeroes = false;
865
866 // Set the long length modifier for wide characters
867 if (QT->getPointeeType()->isWideCharType())
869 else
870 LM.setKind(LengthModifier::None);
871
872 return true;
873 }
874
875 // If it's an enum, get its underlying type.
876 if (const auto *ED = QT->getAsEnumDecl())
877 QT = ED->getIntegerType();
878
879 const BuiltinType *BT = QT->getAs<BuiltinType>();
880 if (!BT) {
881 const VectorType *VT = QT->getAs<VectorType>();
882 if (VT) {
883 QT = VT->getElementType();
884 BT = QT->getAs<BuiltinType>();
886 }
887 }
888
889 // We can only work with builtin types.
890 if (!BT)
891 return false;
892
893 // Set length modifier
894 switch (BT->getKind()) {
895 case BuiltinType::Bool:
896 case BuiltinType::WChar_U:
897 case BuiltinType::WChar_S:
898 case BuiltinType::Char8: // FIXME: Treat like 'char'?
899 case BuiltinType::Char16:
900 case BuiltinType::Char32:
901 case BuiltinType::UInt128:
902 case BuiltinType::Int128:
903 case BuiltinType::Half:
904 case BuiltinType::BFloat16:
905 case BuiltinType::Float16:
906 case BuiltinType::Float128:
907 case BuiltinType::Ibm128:
908 case BuiltinType::ShortAccum:
909 case BuiltinType::Accum:
910 case BuiltinType::LongAccum:
911 case BuiltinType::UShortAccum:
912 case BuiltinType::UAccum:
913 case BuiltinType::ULongAccum:
914 case BuiltinType::ShortFract:
915 case BuiltinType::Fract:
916 case BuiltinType::LongFract:
917 case BuiltinType::UShortFract:
918 case BuiltinType::UFract:
919 case BuiltinType::ULongFract:
920 case BuiltinType::SatShortAccum:
921 case BuiltinType::SatAccum:
922 case BuiltinType::SatLongAccum:
923 case BuiltinType::SatUShortAccum:
924 case BuiltinType::SatUAccum:
925 case BuiltinType::SatULongAccum:
926 case BuiltinType::SatShortFract:
927 case BuiltinType::SatFract:
928 case BuiltinType::SatLongFract:
929 case BuiltinType::SatUShortFract:
930 case BuiltinType::SatUFract:
931 case BuiltinType::SatULongFract:
932 // Various types which are non-trivial to correct.
933 return false;
934
935#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
936 case BuiltinType::Id:
937#include "clang/Basic/OpenCLImageTypes.def"
938
939#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
940#include "clang/Basic/OpenCLExtensionTypes.def"
941
942#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
943#include "clang/Basic/AArch64ACLETypes.def"
944
945#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
946#include "clang/Basic/PPCTypes.def"
947
948#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
949#include "clang/Basic/RISCVVTypes.def"
950
951#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
952#include "clang/Basic/WebAssemblyReferenceTypes.def"
953
954#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
955#include "clang/Basic/AMDGPUTypes.def"
956
957#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
958#include "clang/Basic/HLSLIntangibleTypes.def"
959
960#define SIGNED_TYPE(Id, SingletonId)
961#define UNSIGNED_TYPE(Id, SingletonId)
962#define FLOATING_TYPE(Id, SingletonId)
963#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
964#include "clang/AST/BuiltinTypes.def"
965
966 // Misc other stuff which doesn't make sense here.
967 return false;
968
969 case BuiltinType::UInt:
970 case BuiltinType::Int:
971 case BuiltinType::Float:
972 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
974 break;
975 case BuiltinType::Double:
976 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
978 break;
979 case BuiltinType::Char_U:
980 case BuiltinType::UChar:
981 case BuiltinType::Char_S:
982 case BuiltinType::SChar:
983 LM.setKind(LengthModifier::AsChar);
984 break;
985
986 case BuiltinType::Short:
987 case BuiltinType::UShort:
989 break;
990
991 case BuiltinType::Long:
992 case BuiltinType::ULong:
993 LM.setKind(LengthModifier::AsLong);
994 break;
995
996 case BuiltinType::LongLong:
997 case BuiltinType::ULongLong:
999 break;
1000
1001 case BuiltinType::LongDouble:
1003 break;
1004 }
1005
1006 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
1007 if (LangOpt.C99 || LangOpt.CPlusPlus11)
1008 namedTypeToLengthModifier(Ctx, QT, LM);
1009
1010 // If fixing the length modifier was enough, we might be done.
1011 if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
1012 // If we're going to offer a fix anyway, make sure the sign matches.
1013 switch (CS.getKind()) {
1016 if (QT->isSignedIntegerType())
1018 break;
1022 if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
1024 break;
1025 default:
1026 // Other specifiers do not have signed/unsigned variants.
1027 break;
1028 }
1029
1030 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
1031 if (ATR.isValid() && ATR.matchesType(Ctx, QT))
1032 return true;
1033 }
1034
1035 // Set conversion specifier and disable any flags which do not apply to it.
1036 // Let typedefs to char fall through to int, as %c is silly for uint8_t.
1037 if (!QT->getAs<TypedefType>() && QT->isCharType()) {
1039 LM.setKind(LengthModifier::None);
1040 Precision.setHowSpecified(OptionalAmount::NotSpecified);
1041 HasAlternativeForm = false;
1042 HasLeadingZeroes = false;
1043 HasPlusPrefix = false;
1044 }
1045 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
1046 else if (QT->isRealFloatingType()) {
1048 } else if (QT->isSignedIntegerType()) {
1050 HasAlternativeForm = false;
1051 } else if (QT->isUnsignedIntegerType()) {
1053 HasAlternativeForm = false;
1054 HasPlusPrefix = false;
1055 } else {
1056 llvm_unreachable("Unexpected type");
1057 }
1058
1059 return true;
1060}
1061
1062void PrintfSpecifier::toString(raw_ostream &os) const {
1063 // Whilst some features have no defined order, we are using the order
1064 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
1065 os << "%";
1066
1067 // Positional args
1068 if (usesPositionalArg()) {
1069 os << getPositionalArgIndex() << "$";
1070 }
1071
1072 // Conversion flags
1073 if (IsLeftJustified)
1074 os << "-";
1075 if (HasPlusPrefix)
1076 os << "+";
1077 if (HasSpacePrefix)
1078 os << " ";
1079 if (HasAlternativeForm)
1080 os << "#";
1081 if (HasLeadingZeroes)
1082 os << "0";
1083
1084 // Minimum field width
1085 FieldWidth.toString(os);
1086 // Precision
1087 Precision.toString(os);
1088
1089 // Vector modifier
1090 if (!VectorNumElts.isInvalid())
1091 os << 'v' << VectorNumElts.getConstantAmount();
1092
1093 // Length modifier
1094 os << LM.toString();
1095 // Conversion specifier
1096 os << CS.toString();
1097}
1098
1100 if (!HasPlusPrefix)
1101 return true;
1102
1103 // The plus prefix only makes sense for signed conversions
1104 switch (CS.getKind()) {
1120 return true;
1121
1122 default:
1123 return false;
1124 }
1125}
1126
1128 if (!HasAlternativeForm)
1129 return true;
1130
1131 // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
1132 switch (CS.getKind()) {
1153 return true;
1154
1155 default:
1156 return false;
1157 }
1158}
1159
1161 if (!HasLeadingZeroes)
1162 return true;
1163
1164 // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
1165 switch (CS.getKind()) {
1191 return true;
1192
1193 default:
1194 return false;
1195 }
1196}
1197
1199 if (!HasSpacePrefix)
1200 return true;
1201
1202 // The space prefix only makes sense for signed conversions
1203 switch (CS.getKind()) {
1219 return true;
1220
1221 default:
1222 return false;
1223 }
1224}
1225
1227 if (!IsLeftJustified)
1228 return true;
1229
1230 // The left justified flag is valid for all conversions except n
1231 switch (CS.getKind()) {
1233 return false;
1234
1235 default:
1236 return true;
1237 }
1238}
1239
1241 if (!HasThousandsGrouping)
1242 return true;
1243
1244 switch (CS.getKind()) {
1254 return true;
1255 default:
1256 return false;
1257 }
1258}
1259
1261 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1262 return true;
1263
1264 // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
1265 switch (CS.getKind()) {
1293 return true;
1294
1295 default:
1296 return false;
1297 }
1298}
1300 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1301 return true;
1302
1303 // The field width is valid for all conversions except n
1304 switch (CS.getKind()) {
1306 return false;
1307
1308 default:
1309 return true;
1310 }
1311}
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)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
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:959
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:921
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:3226
Kind getKind() const
Definition TypeBase.h:3274
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:227
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:2267
bool isCharType() const
Definition Type.cpp:2194
bool isPointerType() const
Definition TypeBase.h:8677
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:790
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
Definition Type.cpp:2230
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
Definition Type.h:53
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2406
bool isWideCharType() const
Definition Type.cpp:2203
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:2333
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9270
bool isObjCRetainableType() const
Definition Type.cpp:5428
Represents a GCC generic vector type.
Definition TypeBase.h:4237
unsigned getNumElements() const
Definition TypeBase.h:4252
QualType getElementType() const
Definition TypeBase.h:4251
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 Unsupported(const char *N)
static ArgType makeIntNType(ASTContext &Ctx, const LengthModifier &LengthMod, bool Signed)
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:830