clang 24.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 HLSL_PACKED_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
961#include "clang/Basic/HLSLPackedTypes.def"
962
963#define SPIRV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
964#include "clang/Basic/SPIRVTypes.def"
965
966#define SIGNED_TYPE(Id, SingletonId)
967#define UNSIGNED_TYPE(Id, SingletonId)
968#define FLOATING_TYPE(Id, SingletonId)
969#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
970#include "clang/AST/BuiltinTypes.def"
971
972 // Misc other stuff which doesn't make sense here.
973 return false;
974
975 case BuiltinType::UInt:
976 case BuiltinType::Int:
977 case BuiltinType::Float:
978 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
980 break;
981 case BuiltinType::Double:
982 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
984 break;
985 case BuiltinType::Char_U:
986 case BuiltinType::UChar:
987 case BuiltinType::Char_S:
988 case BuiltinType::SChar:
989 LM.setKind(LengthModifier::AsChar);
990 break;
991
992 case BuiltinType::Short:
993 case BuiltinType::UShort:
995 break;
996
997 case BuiltinType::Long:
998 case BuiltinType::ULong:
999 LM.setKind(LengthModifier::AsLong);
1000 break;
1001
1002 case BuiltinType::LongLong:
1003 case BuiltinType::ULongLong:
1005 break;
1006
1007 case BuiltinType::LongDouble:
1009 break;
1010 }
1011
1012 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
1013 if (LangOpt.C99 || LangOpt.CPlusPlus11)
1014 namedTypeToLengthModifier(Ctx, QT, LM);
1015
1016 // If fixing the length modifier was enough, we might be done.
1017 if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
1018 // If we're going to offer a fix anyway, make sure the sign matches.
1019 switch (CS.getKind()) {
1022 if (QT->isSignedIntegerType())
1024 break;
1028 if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
1030 break;
1031 default:
1032 // Other specifiers do not have signed/unsigned variants.
1033 break;
1034 }
1035
1036 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
1037 if (ATR.isValid() && ATR.matchesType(Ctx, QT))
1038 return true;
1039 }
1040
1041 // Set conversion specifier and disable any flags which do not apply to it.
1042 // Let typedefs to char fall through to int, as %c is silly for uint8_t.
1043 if (!QT->getAs<TypedefType>() && QT->isCharType()) {
1045 LM.setKind(LengthModifier::None);
1046 Precision.setHowSpecified(OptionalAmount::NotSpecified);
1047 HasAlternativeForm = false;
1048 HasLeadingZeroes = false;
1049 HasPlusPrefix = false;
1050 }
1051 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
1052 else if (QT->isRealFloatingType()) {
1054 } else if (QT->isSignedIntegerType()) {
1056 HasAlternativeForm = false;
1057 } else if (QT->isUnsignedIntegerType()) {
1059 HasAlternativeForm = false;
1060 HasPlusPrefix = false;
1061 } else {
1062 llvm_unreachable("Unexpected type");
1063 }
1064
1065 return true;
1066}
1067
1068void PrintfSpecifier::toString(raw_ostream &os) const {
1069 // Whilst some features have no defined order, we are using the order
1070 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
1071 os << "%";
1072
1073 // Positional args
1074 if (usesPositionalArg()) {
1075 os << getPositionalArgIndex() << "$";
1076 }
1077
1078 // Conversion flags
1079 if (IsLeftJustified)
1080 os << "-";
1081 if (HasPlusPrefix)
1082 os << "+";
1083 if (HasSpacePrefix)
1084 os << " ";
1085 if (HasAlternativeForm)
1086 os << "#";
1087 if (HasLeadingZeroes)
1088 os << "0";
1089
1090 // Minimum field width
1091 FieldWidth.toString(os);
1092 // Precision
1093 Precision.toString(os);
1094
1095 // Vector modifier
1096 if (!VectorNumElts.isInvalid())
1097 os << 'v' << VectorNumElts.getConstantAmount();
1098
1099 // Length modifier
1100 os << LM.toString();
1101 // Conversion specifier
1102 os << CS.toString();
1103}
1104
1106 if (!HasPlusPrefix)
1107 return true;
1108
1109 // The plus prefix only makes sense for signed conversions
1110 switch (CS.getKind()) {
1126 return true;
1127
1128 default:
1129 return false;
1130 }
1131}
1132
1134 if (!HasAlternativeForm)
1135 return true;
1136
1137 // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
1138 switch (CS.getKind()) {
1159 return true;
1160
1161 default:
1162 return false;
1163 }
1164}
1165
1167 if (!HasLeadingZeroes)
1168 return true;
1169
1170 // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
1171 switch (CS.getKind()) {
1197 return true;
1198
1199 default:
1200 return false;
1201 }
1202}
1203
1205 if (!HasSpacePrefix)
1206 return true;
1207
1208 // The space prefix only makes sense for signed conversions
1209 switch (CS.getKind()) {
1225 return true;
1226
1227 default:
1228 return false;
1229 }
1230}
1231
1233 if (!IsLeftJustified)
1234 return true;
1235
1236 // The left justified flag is valid for all conversions except n
1237 switch (CS.getKind()) {
1239 return false;
1240
1241 default:
1242 return true;
1243 }
1244}
1245
1247 if (!HasThousandsGrouping)
1248 return true;
1249
1250 switch (CS.getKind()) {
1260 return true;
1261 default:
1262 return false;
1263 }
1264}
1265
1267 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1268 return true;
1269
1270 // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
1271 switch (CS.getKind()) {
1299 return true;
1300
1301 default:
1302 return false;
1303 }
1304}
1306 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1307 return true;
1308
1309 // The field width is valid for all conversions except n
1310 switch (CS.getKind()) {
1312 return false;
1313
1314 default:
1315 return true;
1316 }
1317}
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:239
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
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:969
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:3245
Kind getKind() const
Definition TypeBase.h:3299
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:938
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:2392
bool isCharType() const
Definition Type.cpp:2319
bool isPointerType() const
Definition TypeBase.h:8683
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
Definition Type.cpp:2355
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
Definition Type.h:53
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2533
bool isWideCharType() const
Definition Type.cpp:2328
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:2460
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9299
bool isObjCRetainableType() const
Definition Type.cpp:5611
Represents a GCC generic vector type.
Definition TypeBase.h:4273
unsigned getNumElements() const
Definition TypeBase.h:4288
QualType getElementType() const
Definition TypeBase.h:4287
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.
Top level wrappers for InstallAPI frontend operations.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
Definition Sema.h:824