1287 lines · cpp
1// FormatString.cpp - Common stuff for handling printf/scanf formats -*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// Shared details for processing format strings of printf and scanf10// (and friends).11//12//===----------------------------------------------------------------------===//13 14#include "FormatStringParsing.h"15#include "clang/Basic/LangOptions.h"16#include "clang/Basic/TargetInfo.h"17#include "llvm/Support/ConvertUTF.h"18#include <optional>19 20using clang::analyze_format_string::ArgType;21using clang::analyze_format_string::FormatStringHandler;22using clang::analyze_format_string::FormatSpecifier;23using clang::analyze_format_string::LengthModifier;24using clang::analyze_format_string::OptionalAmount;25using clang::analyze_format_string::ConversionSpecifier;26using namespace clang;27 28// Key function to FormatStringHandler.29FormatStringHandler::~FormatStringHandler() {}30 31//===----------------------------------------------------------------------===//32// Functions for parsing format strings components in both printf and33// scanf format strings.34//===----------------------------------------------------------------------===//35 36OptionalAmount37clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {38 const char *I = Beg;39 UpdateOnReturn <const char*> UpdateBeg(Beg, I);40 41 unsigned accumulator = 0;42 bool hasDigits = false;43 44 for ( ; I != E; ++I) {45 char c = *I;46 if (c >= '0' && c <= '9') {47 hasDigits = true;48 accumulator = (accumulator * 10) + (c - '0');49 continue;50 }51 52 if (hasDigits)53 return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,54 false);55 56 break;57 }58 59 return OptionalAmount();60}61 62OptionalAmount63clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,64 const char *E,65 unsigned &argIndex) {66 if (*Beg == '*') {67 ++Beg;68 return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);69 }70 71 return ParseAmount(Beg, E);72}73 74OptionalAmount75clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,76 const char *Start,77 const char *&Beg,78 const char *E,79 PositionContext p) {80 if (*Beg == '*') {81 const char *I = Beg + 1;82 const OptionalAmount &Amt = ParseAmount(I, E);83 84 if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {85 H.HandleInvalidPosition(Beg, I - Beg, p);86 return OptionalAmount(false);87 }88 89 if (I == E) {90 // No more characters left?91 H.HandleIncompleteSpecifier(Start, E - Start);92 return OptionalAmount(false);93 }94 95 assert(Amt.getHowSpecified() == OptionalAmount::Constant);96 97 if (*I == '$') {98 // Handle positional arguments99 100 // Special case: '*0$', since this is an easy mistake.101 if (Amt.getConstantAmount() == 0) {102 H.HandleZeroPosition(Beg, I - Beg + 1);103 return OptionalAmount(false);104 }105 106 const char *Tmp = Beg;107 Beg = ++I;108 109 return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,110 Tmp, 0, true);111 }112 113 H.HandleInvalidPosition(Beg, I - Beg, p);114 return OptionalAmount(false);115 }116 117 return ParseAmount(Beg, E);118}119 120 121bool122clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,123 FormatSpecifier &CS,124 const char *Start,125 const char *&Beg, const char *E,126 unsigned *argIndex) {127 // FIXME: Support negative field widths.128 if (argIndex) {129 CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));130 }131 else {132 const OptionalAmount Amt =133 ParsePositionAmount(H, Start, Beg, E,134 analyze_format_string::FieldWidthPos);135 136 if (Amt.isInvalid())137 return true;138 CS.setFieldWidth(Amt);139 }140 return false;141}142 143bool144clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,145 FormatSpecifier &FS,146 const char *Start,147 const char *&Beg,148 const char *E) {149 const char *I = Beg;150 151 const OptionalAmount &Amt = ParseAmount(I, E);152 153 if (I == E) {154 // No more characters left?155 H.HandleIncompleteSpecifier(Start, E - Start);156 return true;157 }158 159 if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {160 // Warn that positional arguments are non-standard.161 H.HandlePosition(Start, I - Start);162 163 // Special case: '%0$', since this is an easy mistake.164 if (Amt.getConstantAmount() == 0) {165 H.HandleZeroPosition(Start, I - Start);166 return true;167 }168 169 FS.setArgIndex(Amt.getConstantAmount() - 1);170 FS.setUsesPositionalArg();171 // Update the caller's pointer if we decided to consume172 // these characters.173 Beg = I;174 return false;175 }176 177 return false;178}179 180bool181clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,182 FormatSpecifier &FS,183 const char *&I,184 const char *E,185 const LangOptions &LO) {186 if (!LO.OpenCL)187 return false;188 189 const char *Start = I;190 if (*I == 'v') {191 ++I;192 193 if (I == E) {194 H.HandleIncompleteSpecifier(Start, E - Start);195 return true;196 }197 198 OptionalAmount NumElts = ParseAmount(I, E);199 if (NumElts.getHowSpecified() != OptionalAmount::Constant) {200 H.HandleIncompleteSpecifier(Start, E - Start);201 return true;202 }203 204 FS.setVectorNumElts(NumElts);205 }206 207 return false;208}209 210bool211clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,212 const char *&I,213 const char *E,214 const LangOptions &LO,215 bool IsScanf) {216 LengthModifier::Kind lmKind = LengthModifier::None;217 const char *lmPosition = I;218 switch (*I) {219 default:220 return false;221 case 'h':222 ++I;223 if (I != E && *I == 'h') {224 ++I;225 lmKind = LengthModifier::AsChar;226 } else if (I != E && *I == 'l' && LO.OpenCL) {227 ++I;228 lmKind = LengthModifier::AsShortLong;229 } else {230 lmKind = LengthModifier::AsShort;231 }232 break;233 case 'l':234 ++I;235 if (I != E && *I == 'l') {236 ++I;237 lmKind = LengthModifier::AsLongLong;238 } else {239 lmKind = LengthModifier::AsLong;240 }241 break;242 case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;243 case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;244 case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;245 case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;246 case 'q': lmKind = LengthModifier::AsQuad; ++I; break;247 case 'a':248 if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {249 // For scanf in C90, look at the next character to see if this should250 // be parsed as the GNU extension 'a' length modifier. If not, this251 // will be parsed as a conversion specifier.252 ++I;253 if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {254 lmKind = LengthModifier::AsAllocate;255 break;256 }257 --I;258 }259 return false;260 case 'm':261 if (IsScanf) {262 lmKind = LengthModifier::AsMAllocate;263 ++I;264 break;265 }266 return false;267 // printf: AsInt64, AsInt32, AsInt3264268 // scanf: AsInt64269 case 'I':270 if (I + 1 != E && I + 2 != E) {271 if (I[1] == '6' && I[2] == '4') {272 I += 3;273 lmKind = LengthModifier::AsInt64;274 break;275 }276 if (IsScanf)277 return false;278 279 if (I[1] == '3' && I[2] == '2') {280 I += 3;281 lmKind = LengthModifier::AsInt32;282 break;283 }284 }285 ++I;286 lmKind = LengthModifier::AsInt3264;287 break;288 case 'w':289 lmKind = LengthModifier::AsWide; ++I; break;290 }291 LengthModifier lm(lmPosition, lmKind);292 FS.setLengthModifier(lm);293 return true;294}295 296bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(297 const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {298 if (SpecifierBegin + 1 >= FmtStrEnd)299 return false;300 301 const llvm::UTF8 *SB =302 reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);303 const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);304 const char FirstByte = *SB;305 306 // If the invalid specifier is a multibyte UTF-8 string, return the307 // total length accordingly so that the conversion specifier can be308 // properly updated to reflect a complete UTF-8 specifier.309 unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);310 if (NumBytes == 1)311 return false;312 if (SB + NumBytes > SE)313 return false;314 315 Len = NumBytes + 1;316 return true;317}318 319//===----------------------------------------------------------------------===//320// Methods on ArgType.321//===----------------------------------------------------------------------===//322 323static bool namedTypeToLengthModifierKind(ASTContext &Ctx, QualType QT,324 LengthModifier::Kind &K) {325 if (!Ctx.getLangOpts().C99 && !Ctx.getLangOpts().CPlusPlus)326 return false;327 for (/**/; const auto *TT = QT->getAs<TypedefType>(); QT = TT->desugar()) {328 const auto *TD = TT->getDecl();329 const auto *DC = TT->getDecl()->getDeclContext();330 if (DC->isTranslationUnit() || DC->isStdNamespace()) {331 StringRef Name = TD->getIdentifier()->getName();332 if (Name == "size_t") {333 K = LengthModifier::AsSizeT;334 return true;335 } else if (Name == "ssize_t" /*Not C99, but common in Unix.*/) {336 K = LengthModifier::AsSizeT;337 return true;338 } else if (Name == "ptrdiff_t") {339 K = LengthModifier::AsPtrDiff;340 return true;341 } else if (Name == "intmax_t") {342 K = LengthModifier::AsIntMax;343 return true;344 } else if (Name == "uintmax_t") {345 K = LengthModifier::AsIntMax;346 return true;347 }348 }349 }350 if (const auto *PST = QT->getAs<PredefinedSugarType>()) {351 using Kind = PredefinedSugarType::Kind;352 switch (PST->getKind()) {353 case Kind::SizeT:354 case Kind::SignedSizeT:355 K = LengthModifier::AsSizeT;356 return true;357 case Kind::PtrdiffT:358 K = LengthModifier::AsPtrDiff;359 return true;360 }361 llvm_unreachable("unexpected kind");362 }363 return false;364}365 366// Check whether T and E are compatible size_t/ptrdiff_t types. E must be367// consistent with LE.368// T is the type of the actual expression in the code to be checked, and E is369// the expected type parsed from the format string.370static clang::analyze_format_string::ArgType::MatchKind371matchesSizeTPtrdiffT(ASTContext &C, QualType T, QualType E) {372 using MatchKind = clang::analyze_format_string::ArgType::MatchKind;373 374 if (!T->isIntegerType())375 return MatchKind::NoMatch;376 377 if (C.hasSameType(T, E))378 return MatchKind::Match;379 380 if (C.getCorrespondingSignedType(T.getCanonicalType()) !=381 C.getCorrespondingSignedType(E.getCanonicalType()))382 return MatchKind::NoMatch;383 384 return MatchKind::NoMatchSignedness;385}386 387clang::analyze_format_string::ArgType::MatchKind388ArgType::matchesType(ASTContext &C, QualType argTy) const {389 // When using the format attribute in C++, you can receive a function or an390 // array that will necessarily decay to a pointer when passed to the final391 // format consumer. Apply decay before type comparison.392 if (argTy->canDecayToPointerType())393 argTy = C.getDecayedType(argTy);394 395 if (Ptr) {396 // It has to be a pointer.397 const PointerType *PT = argTy->getAs<PointerType>();398 if (!PT)399 return NoMatch;400 401 // We cannot write through a const qualified pointer.402 if (PT->getPointeeType().isConstQualified())403 return NoMatch;404 405 argTy = PT->getPointeeType();406 }407 408 switch (K) {409 case InvalidTy:410 llvm_unreachable("ArgType must be valid");411 412 case UnknownTy:413 return Match;414 415 case AnyCharTy: {416 if (const auto *ED = argTy->getAsEnumDecl()) {417 // If the enum is incomplete we know nothing about the underlying type.418 // Assume that it's 'int'. Do not use the underlying type for a scoped419 // enumeration.420 if (!ED->isComplete())421 return NoMatch;422 if (!ED->isScoped())423 argTy = ED->getIntegerType();424 }425 426 if (const auto *BT = argTy->getAs<BuiltinType>()) {427 // The types are perfectly matched?428 switch (BT->getKind()) {429 default:430 break;431 case BuiltinType::Char_S:432 case BuiltinType::SChar:433 case BuiltinType::UChar:434 case BuiltinType::Char_U:435 return Match;436 case BuiltinType::Bool:437 if (!Ptr)438 return Match;439 break;440 }441 // "Partially matched" because of promotions?442 if (!Ptr) {443 switch (BT->getKind()) {444 default:445 break;446 case BuiltinType::Int:447 case BuiltinType::UInt:448 return MatchPromotion;449 case BuiltinType::Short:450 case BuiltinType::UShort:451 case BuiltinType::WChar_S:452 case BuiltinType::WChar_U:453 return NoMatchPromotionTypeConfusion;454 }455 }456 }457 return NoMatch;458 }459 460 case SpecificTy: {461 if (TK != TypeKind::DontCare) {462 return matchesSizeTPtrdiffT(C, argTy, T);463 }464 465 if (const auto *ED = argTy->getAsEnumDecl()) {466 // If the enum is incomplete we know nothing about the underlying type.467 // Assume that it's 'int'. Do not use the underlying type for a scoped468 // enumeration as that needs an exact match.469 if (!ED->isComplete())470 argTy = C.IntTy;471 else if (!ED->isScoped())472 argTy = ED->getIntegerType();473 }474 475 if (argTy->isSaturatedFixedPointType())476 argTy = C.getCorrespondingUnsaturatedType(argTy);477 478 argTy = C.getCanonicalType(argTy).getUnqualifiedType();479 480 if (T == argTy)481 return Match;482 if (const auto *BT = argTy->getAs<BuiltinType>()) {483 // Check if the only difference between them is signed vs unsigned484 // if true, return match signedness.485 switch (BT->getKind()) {486 default:487 break;488 case BuiltinType::Bool:489 if (Ptr && (T == C.UnsignedCharTy || T == C.SignedCharTy))490 return NoMatch;491 [[fallthrough]];492 case BuiltinType::Char_S:493 case BuiltinType::SChar:494 if (T == C.UnsignedShortTy || T == C.ShortTy)495 return NoMatchTypeConfusion;496 if (T == C.UnsignedCharTy)497 return NoMatchSignedness;498 if (T == C.SignedCharTy)499 return Match;500 break;501 case BuiltinType::Char_U:502 case BuiltinType::UChar:503 if (T == C.UnsignedShortTy || T == C.ShortTy)504 return NoMatchTypeConfusion;505 if (T == C.UnsignedCharTy)506 return Match;507 if (T == C.SignedCharTy)508 return NoMatchSignedness;509 break;510 case BuiltinType::Short:511 if (T == C.UnsignedShortTy)512 return NoMatchSignedness;513 break;514 case BuiltinType::UShort:515 if (T == C.ShortTy)516 return NoMatchSignedness;517 break;518 case BuiltinType::Int:519 if (T == C.UnsignedIntTy)520 return NoMatchSignedness;521 break;522 case BuiltinType::UInt:523 if (T == C.IntTy)524 return NoMatchSignedness;525 break;526 case BuiltinType::Long:527 if (T == C.UnsignedLongTy)528 return NoMatchSignedness;529 break;530 case BuiltinType::ULong:531 if (T == C.LongTy)532 return NoMatchSignedness;533 break;534 case BuiltinType::LongLong:535 if (T == C.UnsignedLongLongTy)536 return NoMatchSignedness;537 break;538 case BuiltinType::ULongLong:539 if (T == C.LongLongTy)540 return NoMatchSignedness;541 break;542 }543 // "Partially matched" because of promotions?544 if (!Ptr) {545 switch (BT->getKind()) {546 default:547 break;548 case BuiltinType::Bool:549 if (T == C.IntTy || T == C.UnsignedIntTy)550 return MatchPromotion;551 break;552 case BuiltinType::Int:553 case BuiltinType::UInt:554 if (T == C.SignedCharTy || T == C.UnsignedCharTy ||555 T == C.ShortTy || T == C.UnsignedShortTy || T == C.WCharTy ||556 T == C.WideCharTy)557 return MatchPromotion;558 break;559 case BuiltinType::Char_U:560 if (T == C.UnsignedIntTy)561 return MatchPromotion;562 if (T == C.UnsignedShortTy)563 return NoMatchPromotionTypeConfusion;564 break;565 case BuiltinType::Char_S:566 if (T == C.IntTy)567 return MatchPromotion;568 if (T == C.ShortTy)569 return NoMatchPromotionTypeConfusion;570 break;571 case BuiltinType::Half:572 case BuiltinType::Float:573 if (T == C.DoubleTy)574 return MatchPromotion;575 break;576 case BuiltinType::Short:577 case BuiltinType::UShort:578 if (T == C.SignedCharTy || T == C.UnsignedCharTy)579 return NoMatchPromotionTypeConfusion;580 break;581 case BuiltinType::WChar_U:582 case BuiltinType::WChar_S:583 if (T != C.WCharTy && T != C.WideCharTy)584 return NoMatchPromotionTypeConfusion;585 }586 }587 }588 return NoMatch;589 }590 591 case CStrTy:592 if (const auto *PT = argTy->getAs<PointerType>();593 PT && PT->getPointeeType()->isCharType())594 return Match;595 return NoMatch;596 597 case WCStrTy:598 if (const auto *PT = argTy->getAs<PointerType>();599 PT &&600 C.hasSameUnqualifiedType(PT->getPointeeType(), C.getWideCharType()))601 return Match;602 return NoMatch;603 604 case WIntTy: {605 QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();606 607 if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)608 return Match;609 610 QualType PromoArg = C.isPromotableIntegerType(argTy)611 ? C.getPromotedIntegerType(argTy)612 : argTy;613 PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();614 615 // If the promoted argument is the corresponding signed type of the616 // wint_t type, then it should match.617 if (PromoArg->hasSignedIntegerRepresentation() &&618 C.getCorrespondingUnsignedType(PromoArg) == WInt)619 return Match;620 621 return WInt == PromoArg ? Match : NoMatch;622 }623 624 case CPointerTy:625 if (const auto *PT = argTy->getAs<PointerType>()) {626 QualType PointeeTy = PT->getPointeeType();627 if (PointeeTy->isVoidType() || (!Ptr && PointeeTy->isCharType()))628 return Match;629 return NoMatchPedantic;630 }631 632 // nullptr_t* is not a double pointer, so reject when something like633 // void** is expected.634 // In C++, nullptr is promoted to void*. In C23, va_arg(ap, void*) is not635 // undefined when the next argument is of type nullptr_t.636 if (!Ptr && argTy->isNullPtrType())637 return C.getLangOpts().CPlusPlus ? MatchPromotion : Match;638 639 if (argTy->isObjCObjectPointerType() || argTy->isBlockPointerType())640 return NoMatchPedantic;641 642 return NoMatch;643 644 case ObjCPointerTy: {645 if (argTy->getAs<ObjCObjectPointerType>() ||646 argTy->getAs<BlockPointerType>())647 return Match;648 649 // Handle implicit toll-free bridging.650 if (const PointerType *PT = argTy->getAs<PointerType>()) {651 // Things such as CFTypeRef are really just opaque pointers652 // to C structs representing CF types that can often be bridged653 // to Objective-C objects. Since the compiler doesn't know which654 // structs can be toll-free bridged, we just accept them all.655 QualType pointee = PT->getPointeeType();656 if (pointee->isStructureType() || pointee->isVoidType())657 return Match;658 }659 return NoMatch;660 }661 }662 663 llvm_unreachable("Invalid ArgType Kind!");664}665 666static analyze_format_string::ArgType::MatchKind667integerTypeMatch(ASTContext &C, QualType A, QualType B, bool CheckSign) {668 using MK = analyze_format_string::ArgType::MatchKind;669 670 uint64_t IntSize = C.getTypeSize(C.IntTy);671 uint64_t ASize = C.getTypeSize(A);672 uint64_t BSize = C.getTypeSize(B);673 if (std::max(ASize, IntSize) != std::max(BSize, IntSize))674 return MK::NoMatch;675 if (CheckSign && A->isSignedIntegerType() != B->isSignedIntegerType())676 return MK::NoMatchSignedness;677 if (ASize != BSize)678 return MK::MatchPromotion;679 return MK::Match;680}681 682analyze_format_string::ArgType::MatchKind683ArgType::matchesArgType(ASTContext &C, const ArgType &Other) const {684 using AK = analyze_format_string::ArgType::Kind;685 686 // Per matchesType.687 if (K == AK::InvalidTy || Other.K == AK::InvalidTy)688 return NoMatch;689 if (K == AK::UnknownTy || Other.K == AK::UnknownTy)690 return Match;691 692 // Handle whether either (or both, or neither) sides has Ptr set,693 // in addition to whether either (or both, or neither) sides is a SpecificTy694 // that is a pointer.695 ArgType Left = *this;696 bool LeftWasPointer = false;697 ArgType Right = Other;698 bool RightWasPointer = false;699 if (Left.Ptr) {700 Left.Ptr = false;701 LeftWasPointer = true;702 } else if (Left.K == AK::SpecificTy && Left.T->isPointerType()) {703 Left.T = Left.T->getPointeeType();704 LeftWasPointer = true;705 }706 if (Right.Ptr) {707 Right.Ptr = false;708 RightWasPointer = true;709 } else if (Right.K == AK::SpecificTy && Right.T->isPointerType()) {710 Right.T = Right.T->getPointeeType();711 RightWasPointer = true;712 }713 714 if (LeftWasPointer != RightWasPointer)715 return NoMatch;716 717 // Ensure that if at least one side is a SpecificTy, then Left is a718 // SpecificTy.719 if (Right.K == AK::SpecificTy)720 std::swap(Left, Right);721 722 if (Left.K == AK::SpecificTy) {723 if (Right.K == AK::SpecificTy) {724 if (Left.TK != TypeKind::DontCare) {725 return matchesSizeTPtrdiffT(C, Right.T, Left.T);726 } else if (Right.TK != TypeKind::DontCare) {727 return matchesSizeTPtrdiffT(C, Left.T, Right.T);728 }729 730 auto Canon1 = C.getCanonicalType(Left.T);731 auto Canon2 = C.getCanonicalType(Right.T);732 if (Canon1 == Canon2)733 return Match;734 735 auto *BT1 = QualType(Canon1)->getAs<BuiltinType>();736 auto *BT2 = QualType(Canon2)->getAs<BuiltinType>();737 if (BT1 == nullptr || BT2 == nullptr)738 return NoMatch;739 if (BT1 == BT2)740 return Match;741 742 if (!LeftWasPointer && BT1->isInteger() && BT2->isInteger())743 return integerTypeMatch(C, Canon1, Canon2, true);744 return NoMatch;745 } else if (Right.K == AK::AnyCharTy) {746 if (!LeftWasPointer && Left.T->isIntegerType())747 return integerTypeMatch(C, Left.T, C.CharTy, false);748 return NoMatch;749 } else if (Right.K == AK::WIntTy) {750 if (!LeftWasPointer && Left.T->isIntegerType())751 return integerTypeMatch(C, Left.T, C.WIntTy, true);752 return NoMatch;753 }754 // It's hypothetically possible to create an AK::SpecificTy ArgType755 // that matches another kind of ArgType, but in practice Clang doesn't756 // do that, so ignore that case.757 return NoMatch;758 }759 760 return Left.K == Right.K ? Match : NoMatch;761}762 763ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {764 // Check for valid vector element types.765 if (T.isNull())766 return ArgType::Invalid();767 768 QualType Vec = C.getExtVectorType(T, NumElts);769 return ArgType(Vec, Name);770}771 772QualType ArgType::getRepresentativeType(ASTContext &C) const {773 QualType Res;774 switch (K) {775 case InvalidTy:776 llvm_unreachable("No representative type for Invalid ArgType");777 case UnknownTy:778 llvm_unreachable("No representative type for Unknown ArgType");779 case AnyCharTy:780 Res = C.CharTy;781 break;782 case SpecificTy:783 if (TK == TypeKind::PtrdiffT || TK == TypeKind::SizeT)784 // Using Name as name, so no need to show the uglified name.785 Res = T->getCanonicalTypeInternal();786 else787 Res = T;788 break;789 case CStrTy:790 Res = C.getPointerType(C.CharTy);791 break;792 case WCStrTy:793 Res = C.getPointerType(C.getWideCharType());794 break;795 case ObjCPointerTy:796 Res = C.ObjCBuiltinIdTy;797 break;798 case CPointerTy:799 Res = C.VoidPtrTy;800 break;801 case WIntTy: {802 Res = C.getWIntType();803 break;804 }805 }806 807 if (Ptr)808 Res = C.getPointerType(Res);809 return Res;810}811 812std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {813 std::string S = getRepresentativeType(C).getAsString(C.getPrintingPolicy());814 std::string Alias;815 if (Name) {816 // Use a specific name for this type, e.g. "size_t".817 Alias = Name;818 if (Ptr) {819 // If ArgType is actually a pointer to T, append an asterisk.820 Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";821 }822 // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.823 if (S == Alias)824 Alias.clear();825 }826 827 if (!Alias.empty())828 return std::string("'") + Alias + "' (aka '" + S + "')";829 return std::string("'") + S + "'";830}831 832 833//===----------------------------------------------------------------------===//834// Methods on OptionalAmount.835//===----------------------------------------------------------------------===//836 837ArgType838analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {839 return Ctx.IntTy;840}841 842//===----------------------------------------------------------------------===//843// Methods on LengthModifier.844//===----------------------------------------------------------------------===//845 846const char *847analyze_format_string::LengthModifier::toString() const {848 switch (kind) {849 case AsChar:850 return "hh";851 case AsShort:852 return "h";853 case AsShortLong:854 return "hl";855 case AsLong: // or AsWideChar856 return "l";857 case AsLongLong:858 return "ll";859 case AsQuad:860 return "q";861 case AsIntMax:862 return "j";863 case AsSizeT:864 return "z";865 case AsPtrDiff:866 return "t";867 case AsInt32:868 return "I32";869 case AsInt3264:870 return "I";871 case AsInt64:872 return "I64";873 case AsLongDouble:874 return "L";875 case AsAllocate:876 return "a";877 case AsMAllocate:878 return "m";879 case AsWide:880 return "w";881 case None:882 return "";883 }884 return nullptr;885}886 887//===----------------------------------------------------------------------===//888// Methods on ConversionSpecifier.889//===----------------------------------------------------------------------===//890 891const char *ConversionSpecifier::toString() const {892 switch (kind) {893 case bArg: return "b";894 case BArg: return "B";895 case dArg: return "d";896 case DArg: return "D";897 case iArg: return "i";898 case oArg: return "o";899 case OArg: return "O";900 case uArg: return "u";901 case UArg: return "U";902 case xArg: return "x";903 case XArg: return "X";904 case fArg: return "f";905 case FArg: return "F";906 case eArg: return "e";907 case EArg: return "E";908 case gArg: return "g";909 case GArg: return "G";910 case aArg: return "a";911 case AArg: return "A";912 case cArg: return "c";913 case sArg: return "s";914 case pArg: return "p";915 case PArg:916 return "P";917 case nArg: return "n";918 case PercentArg: return "%";919 case ScanListArg: return "[";920 case InvalidSpecifier: return nullptr;921 922 // POSIX unicode extensions.923 case CArg: return "C";924 case SArg: return "S";925 926 // Objective-C specific specifiers.927 case ObjCObjArg: return "@";928 929 // FreeBSD kernel specific specifiers.930 case FreeBSDbArg: return "b";931 case FreeBSDDArg: return "D";932 case FreeBSDrArg: return "r";933 case FreeBSDyArg: return "y";934 935 // GlibC specific specifiers.936 case PrintErrno: return "m";937 938 // MS specific specifiers.939 case ZArg: return "Z";940 941 // ISO/IEC TR 18037 (fixed-point) specific specifiers.942 case rArg:943 return "r";944 case RArg:945 return "R";946 case kArg:947 return "k";948 case KArg:949 return "K";950 }951 return nullptr;952}953 954std::optional<ConversionSpecifier>955ConversionSpecifier::getStandardSpecifier() const {956 ConversionSpecifier::Kind NewKind;957 958 switch (getKind()) {959 default:960 return std::nullopt;961 case DArg:962 NewKind = dArg;963 break;964 case UArg:965 NewKind = uArg;966 break;967 case OArg:968 NewKind = oArg;969 break;970 }971 972 ConversionSpecifier FixedCS(*this);973 FixedCS.setKind(NewKind);974 return FixedCS;975}976 977//===----------------------------------------------------------------------===//978// Methods on OptionalAmount.979//===----------------------------------------------------------------------===//980 981void OptionalAmount::toString(raw_ostream &os) const {982 switch (hs) {983 case Invalid:984 case NotSpecified:985 return;986 case Arg:987 if (UsesDotPrefix)988 os << ".";989 if (usesPositionalArg())990 os << "*" << getPositionalArgIndex() << "$";991 else992 os << "*";993 break;994 case Constant:995 if (UsesDotPrefix)996 os << ".";997 os << amt;998 break;999 }1000}1001 1002bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,1003 const LangOptions &LO) const {1004 switch (LM.getKind()) {1005 case LengthModifier::None:1006 return true;1007 1008 // Handle most integer flags1009 case LengthModifier::AsShort:1010 // Length modifier only applies to FP vectors.1011 if (LO.OpenCL && CS.isDoubleArg())1012 return !VectorNumElts.isInvalid();1013 1014 if (CS.isFixedPointArg())1015 return true;1016 1017 if (Target.getTriple().isOSMSVCRT()) {1018 switch (CS.getKind()) {1019 case ConversionSpecifier::cArg:1020 case ConversionSpecifier::CArg:1021 case ConversionSpecifier::sArg:1022 case ConversionSpecifier::SArg:1023 case ConversionSpecifier::ZArg:1024 return true;1025 default:1026 break;1027 }1028 }1029 [[fallthrough]];1030 case LengthModifier::AsChar:1031 case LengthModifier::AsLongLong:1032 case LengthModifier::AsQuad:1033 case LengthModifier::AsIntMax:1034 case LengthModifier::AsSizeT:1035 case LengthModifier::AsPtrDiff:1036 switch (CS.getKind()) {1037 case ConversionSpecifier::bArg:1038 case ConversionSpecifier::BArg:1039 case ConversionSpecifier::dArg:1040 case ConversionSpecifier::DArg:1041 case ConversionSpecifier::iArg:1042 case ConversionSpecifier::oArg:1043 case ConversionSpecifier::OArg:1044 case ConversionSpecifier::uArg:1045 case ConversionSpecifier::UArg:1046 case ConversionSpecifier::xArg:1047 case ConversionSpecifier::XArg:1048 case ConversionSpecifier::nArg:1049 return true;1050 case ConversionSpecifier::FreeBSDrArg:1051 case ConversionSpecifier::FreeBSDyArg:1052 return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();1053 default:1054 return false;1055 }1056 1057 case LengthModifier::AsShortLong:1058 return LO.OpenCL && !VectorNumElts.isInvalid();1059 1060 // Handle 'l' flag1061 case LengthModifier::AsLong: // or AsWideChar1062 if (CS.isDoubleArg()) {1063 // Invalid for OpenCL FP scalars.1064 if (LO.OpenCL && VectorNumElts.isInvalid())1065 return false;1066 return true;1067 }1068 1069 if (CS.isFixedPointArg())1070 return true;1071 1072 switch (CS.getKind()) {1073 case ConversionSpecifier::bArg:1074 case ConversionSpecifier::BArg:1075 case ConversionSpecifier::dArg:1076 case ConversionSpecifier::DArg:1077 case ConversionSpecifier::iArg:1078 case ConversionSpecifier::oArg:1079 case ConversionSpecifier::OArg:1080 case ConversionSpecifier::uArg:1081 case ConversionSpecifier::UArg:1082 case ConversionSpecifier::xArg:1083 case ConversionSpecifier::XArg:1084 case ConversionSpecifier::nArg:1085 case ConversionSpecifier::cArg:1086 case ConversionSpecifier::sArg:1087 case ConversionSpecifier::ScanListArg:1088 case ConversionSpecifier::ZArg:1089 return true;1090 case ConversionSpecifier::FreeBSDrArg:1091 case ConversionSpecifier::FreeBSDyArg:1092 return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();1093 default:1094 return false;1095 }1096 1097 case LengthModifier::AsLongDouble:1098 switch (CS.getKind()) {1099 case ConversionSpecifier::aArg:1100 case ConversionSpecifier::AArg:1101 case ConversionSpecifier::fArg:1102 case ConversionSpecifier::FArg:1103 case ConversionSpecifier::eArg:1104 case ConversionSpecifier::EArg:1105 case ConversionSpecifier::gArg:1106 case ConversionSpecifier::GArg:1107 return true;1108 // GNU libc extension.1109 case ConversionSpecifier::dArg:1110 case ConversionSpecifier::iArg:1111 case ConversionSpecifier::oArg:1112 case ConversionSpecifier::uArg:1113 case ConversionSpecifier::xArg:1114 case ConversionSpecifier::XArg:1115 return !Target.getTriple().isOSDarwin() &&1116 !Target.getTriple().isOSWindows();1117 default:1118 return false;1119 }1120 1121 case LengthModifier::AsAllocate:1122 switch (CS.getKind()) {1123 case ConversionSpecifier::sArg:1124 case ConversionSpecifier::SArg:1125 case ConversionSpecifier::ScanListArg:1126 return true;1127 default:1128 return false;1129 }1130 1131 case LengthModifier::AsMAllocate:1132 switch (CS.getKind()) {1133 case ConversionSpecifier::cArg:1134 case ConversionSpecifier::CArg:1135 case ConversionSpecifier::sArg:1136 case ConversionSpecifier::SArg:1137 case ConversionSpecifier::ScanListArg:1138 return true;1139 default:1140 return false;1141 }1142 case LengthModifier::AsInt32:1143 case LengthModifier::AsInt3264:1144 case LengthModifier::AsInt64:1145 switch (CS.getKind()) {1146 case ConversionSpecifier::dArg:1147 case ConversionSpecifier::iArg:1148 case ConversionSpecifier::oArg:1149 case ConversionSpecifier::uArg:1150 case ConversionSpecifier::xArg:1151 case ConversionSpecifier::XArg:1152 return Target.getTriple().isOSMSVCRT();1153 default:1154 return false;1155 }1156 case LengthModifier::AsWide:1157 switch (CS.getKind()) {1158 case ConversionSpecifier::cArg:1159 case ConversionSpecifier::CArg:1160 case ConversionSpecifier::sArg:1161 case ConversionSpecifier::SArg:1162 case ConversionSpecifier::ZArg:1163 return Target.getTriple().isOSMSVCRT();1164 default:1165 return false;1166 }1167 }1168 llvm_unreachable("Invalid LengthModifier Kind!");1169}1170 1171bool FormatSpecifier::hasStandardLengthModifier() const {1172 switch (LM.getKind()) {1173 case LengthModifier::None:1174 case LengthModifier::AsChar:1175 case LengthModifier::AsShort:1176 case LengthModifier::AsLong:1177 case LengthModifier::AsLongLong:1178 case LengthModifier::AsIntMax:1179 case LengthModifier::AsSizeT:1180 case LengthModifier::AsPtrDiff:1181 case LengthModifier::AsLongDouble:1182 return true;1183 case LengthModifier::AsAllocate:1184 case LengthModifier::AsMAllocate:1185 case LengthModifier::AsQuad:1186 case LengthModifier::AsInt32:1187 case LengthModifier::AsInt3264:1188 case LengthModifier::AsInt64:1189 case LengthModifier::AsWide:1190 case LengthModifier::AsShortLong: // ???1191 return false;1192 }1193 llvm_unreachable("Invalid LengthModifier Kind!");1194}1195 1196bool FormatSpecifier::hasStandardConversionSpecifier(1197 const LangOptions &LangOpt) const {1198 switch (CS.getKind()) {1199 case ConversionSpecifier::bArg:1200 case ConversionSpecifier::BArg:1201 case ConversionSpecifier::cArg:1202 case ConversionSpecifier::dArg:1203 case ConversionSpecifier::iArg:1204 case ConversionSpecifier::oArg:1205 case ConversionSpecifier::uArg:1206 case ConversionSpecifier::xArg:1207 case ConversionSpecifier::XArg:1208 case ConversionSpecifier::fArg:1209 case ConversionSpecifier::FArg:1210 case ConversionSpecifier::eArg:1211 case ConversionSpecifier::EArg:1212 case ConversionSpecifier::gArg:1213 case ConversionSpecifier::GArg:1214 case ConversionSpecifier::aArg:1215 case ConversionSpecifier::AArg:1216 case ConversionSpecifier::sArg:1217 case ConversionSpecifier::pArg:1218 case ConversionSpecifier::nArg:1219 case ConversionSpecifier::ObjCObjArg:1220 case ConversionSpecifier::ScanListArg:1221 case ConversionSpecifier::PercentArg:1222 case ConversionSpecifier::PArg:1223 return true;1224 case ConversionSpecifier::CArg:1225 case ConversionSpecifier::SArg:1226 return LangOpt.ObjC;1227 case ConversionSpecifier::InvalidSpecifier:1228 case ConversionSpecifier::FreeBSDbArg:1229 case ConversionSpecifier::FreeBSDDArg:1230 case ConversionSpecifier::FreeBSDrArg:1231 case ConversionSpecifier::FreeBSDyArg:1232 case ConversionSpecifier::PrintErrno:1233 case ConversionSpecifier::DArg:1234 case ConversionSpecifier::OArg:1235 case ConversionSpecifier::UArg:1236 case ConversionSpecifier::ZArg:1237 return false;1238 case ConversionSpecifier::rArg:1239 case ConversionSpecifier::RArg:1240 case ConversionSpecifier::kArg:1241 case ConversionSpecifier::KArg:1242 return LangOpt.FixedPoint;1243 }1244 llvm_unreachable("Invalid ConversionSpecifier Kind!");1245}1246 1247bool FormatSpecifier::hasStandardLengthConversionCombination() const {1248 if (LM.getKind() == LengthModifier::AsLongDouble) {1249 switch(CS.getKind()) {1250 case ConversionSpecifier::dArg:1251 case ConversionSpecifier::iArg:1252 case ConversionSpecifier::oArg:1253 case ConversionSpecifier::uArg:1254 case ConversionSpecifier::xArg:1255 case ConversionSpecifier::XArg:1256 return false;1257 default:1258 return true;1259 }1260 }1261 return true;1262}1263 1264std::optional<LengthModifier>1265FormatSpecifier::getCorrectedLengthModifier() const {1266 if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {1267 if (LM.getKind() == LengthModifier::AsLongDouble ||1268 LM.getKind() == LengthModifier::AsQuad) {1269 LengthModifier FixedLM(LM);1270 FixedLM.setKind(LengthModifier::AsLongLong);1271 return FixedLM;1272 }1273 }1274 1275 return std::nullopt;1276}1277 1278bool FormatSpecifier::namedTypeToLengthModifier(ASTContext &Ctx, QualType QT,1279 LengthModifier &LM) {1280 if (LengthModifier::Kind Out = LengthModifier::Kind::None;1281 namedTypeToLengthModifierKind(Ctx, QT, Out)) {1282 LM.setKind(Out);1283 return true;1284 }1285 return false;1286}1287