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 SPIRV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
961#include "clang/Basic/SPIRVTypes.def"
962
963#define SIGNED_TYPE(Id, SingletonId)
964#define UNSIGNED_TYPE(Id, SingletonId)
965#define FLOATING_TYPE(Id, SingletonId)
966#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
967#include "clang/AST/BuiltinTypes.def"
968
969 // Misc other stuff which doesn't make sense here.
970 return false;
971
972 case BuiltinType::UInt:
973 case BuiltinType::Int:
974 case BuiltinType::Float:
975 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
977 break;
978 case BuiltinType::Double:
979 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
981 break;
982 case BuiltinType::Char_U:
983 case BuiltinType::UChar:
984 case BuiltinType::Char_S:
985 case BuiltinType::SChar:
986 LM.setKind(LengthModifier::AsChar);
987 break;
988
989 case BuiltinType::Short:
990 case BuiltinType::UShort:
992 break;
993
994 case BuiltinType::Long:
995 case BuiltinType::ULong:
996 LM.setKind(LengthModifier::AsLong);
997 break;
998
999 case BuiltinType::LongLong:
1000 case BuiltinType::ULongLong:
1002 break;
1003
1004 case BuiltinType::LongDouble:
1006 break;
1007 }
1008
1009 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
1010 if (LangOpt.C99 || LangOpt.CPlusPlus11)
1011 namedTypeToLengthModifier(Ctx, QT, LM);
1012
1013 // If fixing the length modifier was enough, we might be done.
1014 if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
1015 // If we're going to offer a fix anyway, make sure the sign matches.
1016 switch (CS.getKind()) {
1019 if (QT->isSignedIntegerType())
1021 break;
1025 if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
1027 break;
1028 default:
1029 // Other specifiers do not have signed/unsigned variants.
1030 break;
1031 }
1032
1033 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
1034 if (ATR.isValid() && ATR.matchesType(Ctx, QT))
1035 return true;
1036 }
1037
1038 // Set conversion specifier and disable any flags which do not apply to it.
1039 // Let typedefs to char fall through to int, as %c is silly for uint8_t.
1040 if (!QT->getAs<TypedefType>() && QT->isCharType()) {
1042 LM.setKind(LengthModifier::None);
1043 Precision.setHowSpecified(OptionalAmount::NotSpecified);
1044 HasAlternativeForm = false;
1045 HasLeadingZeroes = false;
1046 HasPlusPrefix = false;
1047 }
1048 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
1049 else if (QT->isRealFloatingType()) {
1051 } else if (QT->isSignedIntegerType()) {
1053 HasAlternativeForm = false;
1054 } else if (QT->isUnsignedIntegerType()) {
1056 HasAlternativeForm = false;
1057 HasPlusPrefix = false;
1058 } else {
1059 llvm_unreachable("Unexpected type");
1060 }
1061
1062 return true;
1063}
1064
1065void PrintfSpecifier::toString(raw_ostream &os) const {
1066 // Whilst some features have no defined order, we are using the order
1067 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
1068 os << "%";
1069
1070 // Positional args
1071 if (usesPositionalArg()) {
1072 os << getPositionalArgIndex() << "$";
1073 }
1074
1075 // Conversion flags
1076 if (IsLeftJustified)
1077 os << "-";
1078 if (HasPlusPrefix)
1079 os << "+";
1080 if (HasSpacePrefix)
1081 os << " ";
1082 if (HasAlternativeForm)
1083 os << "#";
1084 if (HasLeadingZeroes)
1085 os << "0";
1086
1087 // Minimum field width
1088 FieldWidth.toString(os);
1089 // Precision
1090 Precision.toString(os);
1091
1092 // Vector modifier
1093 if (!VectorNumElts.isInvalid())
1094 os << 'v' << VectorNumElts.getConstantAmount();
1095
1096 // Length modifier
1097 os << LM.toString();
1098 // Conversion specifier
1099 os << CS.toString();
1100}
1101
1103 if (!HasPlusPrefix)
1104 return true;
1105
1106 // The plus prefix only makes sense for signed conversions
1107 switch (CS.getKind()) {
1123 return true;
1124
1125 default:
1126 return false;
1127 }
1128}
1129
1131 if (!HasAlternativeForm)
1132 return true;
1133
1134 // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
1135 switch (CS.getKind()) {
1156 return true;
1157
1158 default:
1159 return false;
1160 }
1161}
1162
1164 if (!HasLeadingZeroes)
1165 return true;
1166
1167 // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
1168 switch (CS.getKind()) {
1194 return true;
1195
1196 default:
1197 return false;
1198 }
1199}
1200
1202 if (!HasSpacePrefix)
1203 return true;
1204
1205 // The space prefix only makes sense for signed conversions
1206 switch (CS.getKind()) {
1222 return true;
1223
1224 default:
1225 return false;
1226 }
1227}
1228
1230 if (!IsLeftJustified)
1231 return true;
1232
1233 // The left justified flag is valid for all conversions except n
1234 switch (CS.getKind()) {
1236 return false;
1237
1238 default:
1239 return true;
1240 }
1241}
1242
1244 if (!HasThousandsGrouping)
1245 return true;
1246
1247 switch (CS.getKind()) {
1257 return true;
1258 default:
1259 return false;
1260 }
1261}
1262
1264 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1265 return true;
1266
1267 // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
1268 switch (CS.getKind()) {
1296 return true;
1297
1298 default:
1299 return false;
1300 }
1301}
1303 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1304 return true;
1305
1306 // The field width is valid for all conversions except n
1307 switch (CS.getKind()) {
1309 return false;
1310
1311 default:
1312 return true;
1313 }
1314}
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:965
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:927
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:3238
Kind getKind() const
Definition TypeBase.h:3289
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: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:2270
bool isCharType() const
Definition Type.cpp:2197
bool isPointerType() const
Definition TypeBase.h:8738
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
Definition Type.cpp:2233
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
Definition Type.h:53
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2409
bool isWideCharType() const
Definition Type.cpp:2206
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:2336
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9337
bool isObjCRetainableType() const
Definition Type.cpp:5441
Represents a GCC generic vector type.
Definition TypeBase.h:4286
unsigned getNumElements() const
Definition TypeBase.h:4301
QualType getElementType() const
Definition TypeBase.h:4300
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:836