diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp index a710c6ab728c2..5fceff6fc6ec6 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp @@ -619,10 +619,10 @@ bool FormatStringConverter::convertArgument(const PrintfSpecifier &FS, } /// Called for each format specifier by ParsePrintfString. -bool FormatStringConverter::HandlePrintfSpecifier(const PrintfSpecifier &FS, - const char *StartSpecifier, - unsigned SpecifierLen, - const TargetInfo &Target) { +bool FormatStringConverter::HandlePrintfSpecifier( + const PrintfSpecifier &FS, const char *StartSpecifier, + unsigned SpecifierLen, const TargetInfo &Target, + const llvm::TextEncodingConverter &) { const size_t StartSpecifierPos = StartSpecifier - PrintfFormatString.data(); assert(StartSpecifierPos + SpecifierLen <= PrintfFormatString.size()); diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.h b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.h index e413b9f4c79f0..8c799e45cbd2b 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.h +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.h @@ -106,7 +106,8 @@ class FormatStringConverter bool HandlePrintfSpecifier(const PrintfSpecifier &FS, const char *StartSpecifier, unsigned SpecifierLen, - const TargetInfo &Target) override; + const TargetInfo &Target, + const llvm::TextEncodingConverter &Conv) override; void appendFormatText(StringRef Text); void finalizeFormatText(); diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h index 2c91e18491b1e..e233879d6f6a2 100644 --- a/clang/include/clang/AST/FormatString.h +++ b/clang/include/clang/AST/FormatString.h @@ -20,6 +20,7 @@ #include "clang/AST/CanonicalType.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/TextEncoding.h" #include namespace clang { @@ -764,14 +765,15 @@ class FormatStringHandler { virtual bool HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, - unsigned specifierLen) { + unsigned specifierLen, const llvm::TextEncodingConverter &Conv) { return true; } virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen, - const TargetInfo &Target) { + const TargetInfo &Target, + const llvm::TextEncodingConverter &Conv) { return true; } @@ -780,10 +782,9 @@ class FormatStringHandler { // Scanf-specific handlers. - virtual bool - HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier &FS, - const char *startSpecifier, - unsigned specifierLen) { + virtual bool HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, + unsigned specifierLen, const llvm::TextEncodingConverter &Conv) { return true; } diff --git a/clang/include/clang/Lex/TextEncoding.h b/clang/include/clang/Lex/TextEncoding.h index 1d4ac51bb764f..c1e6b7dad3948 100644 --- a/clang/include/clang/Lex/TextEncoding.h +++ b/clang/include/clang/Lex/TextEncoding.h @@ -30,9 +30,6 @@ class TextEncoding { std::unique_ptr FromLiteralEncodingConverter; // Only non-null on z/OS, where the system default encoding is IBM-1047. - // This converts UTF-8 to IBM-1047 for asm string literals so that - // octal/hex escape sequences are interpreted as IBM-1047 code points, - // regardless of -fexec-charset. std::unique_ptr ToIBM1047Converter; std::unique_ptr FromIBM1047Converter; diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index a7569701352b3..fdd40208aaa0c 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -34,8 +34,9 @@ FormatStringHandler::~FormatStringHandler() {} // scanf format strings. //===----------------------------------------------------------------------===// -OptionalAmount clang::analyze_format_string::ParseAmount(const char *&Beg, - const char *E) { +OptionalAmount clang::analyze_format_string::ParseAmount( + const char *&Beg, const char *E, + const llvm::TextEncodingConverter &Conv) { const char *I = Beg; UpdateOnReturn UpdateBeg(Beg, I); @@ -43,10 +44,10 @@ OptionalAmount clang::analyze_format_string::ParseAmount(const char *&Beg, bool hasDigits = false; for (; I != E; ++I) { - char c = *I; - if (c >= '0' && c <= '9') { + char c = Conv.convertBasicChar(*I); + if (c >= u8'0' && c <= u8'9') { hasDigits = true; - accumulator = (accumulator * 10) + (c - '0'); + accumulator = (accumulator * 10) + (c - u8'0'); continue; } @@ -76,21 +77,23 @@ static bool ParseWidthModifier(const char *&I, const char *E, } OptionalAmount clang::analyze_format_string::ParseNonPositionAmount( - const char *&Beg, const char *E, unsigned &argIndex) { - if (*Beg == '*') { + const char *&Beg, const char *E, unsigned &argIndex, + const llvm::TextEncodingConverter &Conv) { + if (Conv.convertBasicChar(*Beg) == u8'*') { ++Beg; return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false); } - return ParseAmount(Beg, E); + return ParseAmount(Beg, E, Conv); } OptionalAmount clang::analyze_format_string::ParsePositionAmount( FormatStringHandler &H, const char *Start, const char *&Beg, const char *E, - PositionContext p) { - if (*Beg == '*') { + PositionContext p, + const llvm::TextEncodingConverter &Conv) { + if (Conv.convertBasicChar(*Beg) == u8'*') { const char *I = Beg + 1; - const OptionalAmount &Amt = ParseAmount(I, E); + const OptionalAmount &Amt = ParseAmount(I, E, Conv); if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) { H.HandleInvalidPosition(Beg, I - Beg, p); @@ -105,7 +108,7 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount( assert(Amt.getHowSpecified() == OptionalAmount::Constant); - if (*I == '$') { + if (Conv.convertBasicChar(*I) == u8'$') { // Handle positional arguments // Special case: '*0$', since this is an easy mistake. @@ -125,18 +128,21 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount( return OptionalAmount(false); } - return ParseAmount(Beg, E); + return ParseAmount(Beg, E, Conv); } bool clang::analyze_format_string::ParseFieldWidth( FormatStringHandler &H, FormatSpecifier &CS, const char *Start, - const char *&Beg, const char *E, unsigned *argIndex) { + const char *&Beg, const char *E, unsigned *argIndex, + const llvm::TextEncodingConverter &Conv) { // FIXME: Support negative field widths. if (argIndex) { - CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex)); + CS.setFieldWidth( + ParseNonPositionAmount(Beg, E, *argIndex, Conv)); } else { const OptionalAmount Amt = ParsePositionAmount( - H, Start, Beg, E, analyze_format_string::FieldWidthPos); + H, Start, Beg, E, analyze_format_string::FieldWidthPos, + Conv); if (Amt.isInvalid()) return true; @@ -145,14 +151,13 @@ bool clang::analyze_format_string::ParseFieldWidth( return false; } -bool clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H, - FormatSpecifier &FS, - const char *Start, - const char *&Beg, - const char *E) { +bool clang::analyze_format_string::ParseArgPosition( + FormatStringHandler &H, FormatSpecifier &FS, const char *Start, + const char *&Beg, const char *E, + const llvm::TextEncodingConverter &Conv) { const char *I = Beg; - const OptionalAmount &Amt = ParseAmount(I, E); + const OptionalAmount &Amt = ParseAmount(I, E, Conv); if (I == E) { // No more characters left? @@ -160,7 +165,8 @@ bool clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H, return true; } - if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') { + if (Amt.getHowSpecified() == OptionalAmount::Constant && + Conv.convertBasicChar(*(I++)) == u8'$') { // Warn that positional arguments are non-standard. H.HandlePosition(Start, I - Start); @@ -181,16 +187,15 @@ bool clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H, return false; } -bool clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H, - FormatSpecifier &FS, - const char *&I, - const char *E, - const LangOptions &LO) { +bool clang::analyze_format_string::ParseVectorModifier( + FormatStringHandler &H, FormatSpecifier &FS, const char *&I, const char *E, + const LangOptions &LO, + const llvm::TextEncodingConverter &Conv) { if (!LO.OpenCL) return false; const char *Start = I; - if (*I == 'v') { + if (Conv.convertBasicChar(*I) == u8'v') { ++I; if (I == E) { @@ -198,7 +203,7 @@ bool clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H, return true; } - OptionalAmount NumElts = ParseAmount(I, E); + OptionalAmount NumElts = ParseAmount(I, E, Conv); if (NumElts.getHowSpecified() != OptionalAmount::Constant) { H.HandleIncompleteSpecifier(Start, E - Start); return true; @@ -210,71 +215,75 @@ bool clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H, return false; } -bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, - const char *&I, - const char *E, - const LangOptions &LO, - bool IsScanf) { +bool clang::analyze_format_string::ParseLengthModifier( + FormatSpecifier &FS, const char *&I, const char *E, const LangOptions &LO, + const llvm::TextEncodingConverter &Conv, + bool IsScanf) { LengthModifier::Kind lmKind = LengthModifier::None; const char *lmPosition = I; - switch (*I) { + switch (Conv.convertBasicChar(*I)) { default: return false; - case 'h': + case u8'h': ++I; - if (I != E && *I == 'h') { + if (I != E && Conv.convertBasicChar(*I) == u8'h') { ++I; lmKind = LengthModifier::AsChar; - } else if (I != E && *I == 'l' && LO.OpenCL) { + } else if (I != E && + Conv.convertBasicChar(*I) == u8'l' && + LO.OpenCL) { ++I; lmKind = LengthModifier::AsShortLong; } else { lmKind = LengthModifier::AsShort; } break; - case 'l': + case u8'l': ++I; - if (I != E && *I == 'l') { + if (I != E && Conv.convertBasicChar(*I) == u8'l') { ++I; lmKind = LengthModifier::AsLongLong; } else { lmKind = LengthModifier::AsLong; } break; - case 'j': + case u8'j': lmKind = LengthModifier::AsIntMax; ++I; break; - case 'z': + case u8'z': lmKind = LengthModifier::AsSizeT; ++I; break; - case 't': + case u8't': lmKind = LengthModifier::AsPtrDiff; ++I; break; - case 'L': + case u8'L': lmKind = LengthModifier::AsLongDouble; ++I; break; - case 'q': + case u8'q': lmKind = LengthModifier::AsQuad; ++I; break; - case 'a': + case u8'a': if (IsScanf && !LO.C99 && !LO.CPlusPlus11) { // For scanf in C90, look at the next character to see if this should // be parsed as the GNU extension 'a' length modifier. If not, this // will be parsed as a conversion specifier. ++I; - if (I != E && (*I == 's' || *I == 'S' || *I == '[')) { + if (I != E && + (Conv.convertBasicChar(*I) == u8's' || + Conv.convertBasicChar(*I) == u8'S' || + Conv.convertBasicChar(*I) == u8'[')) { lmKind = LengthModifier::AsAllocate; break; } --I; } return false; - case 'm': + case u8'm': if (IsScanf) { lmKind = LengthModifier::AsMAllocate; ++I; @@ -283,9 +292,10 @@ bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, return false; // printf: AsInt64, AsInt32, AsInt3264 // scanf: AsInt64 - case 'I': + case u8'I': if (I + 1 != E && I + 2 != E) { - if (I[1] == '6' && I[2] == '4') { + if (Conv.convertBasicChar(I[1]) == u8'6' && + Conv.convertBasicChar(I[2]) == u8'4') { I += 3; lmKind = LengthModifier::AsInt64; break; @@ -293,7 +303,8 @@ bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, if (IsScanf) return false; - if (I[1] == '3' && I[2] == '2') { + if (Conv.convertBasicChar(I[1]) == u8'3' && + Conv.convertBasicChar(I[2]) == u8'2') { I += 3; lmKind = LengthModifier::AsInt32; break; diff --git a/clang/lib/AST/FormatStringParsing.h b/clang/lib/AST/FormatStringParsing.h index 401528481a9d6..52915387ccbfa 100644 --- a/clang/lib/AST/FormatStringParsing.h +++ b/clang/lib/AST/FormatStringParsing.h @@ -17,11 +17,29 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/FormatString.h" #include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/TextEncoding.h" namespace clang { class LangOptions; +/// Creates a TextEncodingConverter for format string character comparisons. +/// On z/OS format strings are IBM-1047 encoded, so each byte must be converted +/// to UTF-8 before comparing against ASCII specifier characters. +/// On all other targets a no-op converter is returned. +/// Create this once per format string parse and pass it through. +inline llvm::TextEncodingConverter +makeFormatStrConverter(const TargetInfo &Target) { + auto MaybeConverter = + Target.getTriple().isOSzOS() + ? llvm::TextEncodingConverter::create(llvm::TextEncoding::IBM1047, + llvm::TextEncoding::UTF8) + : llvm::TextEncodingConverter::createNoopConverter(); + assert(MaybeConverter && "Failed to create format string converter"); + return std::move(*MaybeConverter); +} + template class UpdateOnReturn { T &ValueToUpdate; const T &ValueToCopy; @@ -35,29 +53,37 @@ template class UpdateOnReturn { namespace analyze_format_string { -OptionalAmount ParseAmount(const char *&Beg, const char *E); +OptionalAmount ParseAmount(const char *&Beg, const char *E, + const llvm::TextEncodingConverter &Conv); + OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E, - unsigned &argIndex); + unsigned &argIndex, + const llvm::TextEncodingConverter &Conv); OptionalAmount ParsePositionAmount(FormatStringHandler &H, const char *Start, const char *&Beg, const char *E, - PositionContext p); + PositionContext p, + const llvm::TextEncodingConverter &Conv); bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &CS, const char *Start, const char *&Beg, const char *E, - unsigned *argIndex); + unsigned *argIndex, + const llvm::TextEncodingConverter &Conv); bool ParseArgPosition(FormatStringHandler &H, FormatSpecifier &CS, - const char *Start, const char *&Beg, const char *E); + const char *Start, const char *&Beg, const char *E, + const llvm::TextEncodingConverter &Conv); bool ParseVectorModifier(FormatStringHandler &H, FormatSpecifier &FS, - const char *&Beg, const char *E, - const LangOptions &LO); + const char *&Beg, const char *E, const LangOptions &LO, + const llvm::TextEncodingConverter &Conv); /// Returns true if a LengthModifier was parsed and installed in the /// FormatSpecifier& argument, and false otherwise. bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E, - const LangOptions &LO, bool IsScanf = false); + const LangOptions &LO, + const llvm::TextEncodingConverter &Conv, + bool IsScanf = false); /// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8 /// string; check that it won't go further than \p FmtStrEnd and write diff --git a/clang/lib/AST/OSLog.cpp b/clang/lib/AST/OSLog.cpp index 91f8410e89e86..379a611db3f9c 100644 --- a/clang/lib/AST/OSLog.cpp +++ b/clang/lib/AST/OSLog.cpp @@ -69,7 +69,8 @@ class OSLogFormatStringHandler bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, unsigned SpecifierLen, - const TargetInfo &) override { + const TargetInfo &Target, + const llvm::TextEncodingConverter &) override { if (!FS.consumesDataArgument() && FS.getConversionSpecifier().getKind() != clang::analyze_format_string::ConversionSpecifier::PrintErrno) diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index d09ed5e02dc02..1ade9b72fd1be 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -14,7 +14,6 @@ #include "FormatStringParsing.h" #include "clang/AST/FormatString.h" #include "clang/AST/OSLog.h" -#include "clang/Basic/TargetInfo.h" #include "llvm/Support/Regex.h" using clang::analyze_format_string::ArgType; @@ -35,14 +34,17 @@ typedef clang::analyze_format_string::SpecifierResult using analyze_format_string::ParseNonPositionAmount; -static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, - const char *Start, const char *&Beg, const char *E, - unsigned *argIndex) { +static bool +ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, const char *Start, + const char *&Beg, const char *E, unsigned *argIndex, + const llvm::TextEncodingConverter &FormatStrConverter) { if (argIndex) { - FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); + FS.setPrecision( + ParseNonPositionAmount(Beg, E, *argIndex, FormatStrConverter)); } else { const OptionalAmount Amt = ParsePositionAmount( - H, Start, Beg, E, analyze_format_string::PrecisionPos); + H, Start, Beg, E, analyze_format_string::PrecisionPos, + FormatStrConverter); if (Amt.isInvalid()) return true; FS.setPrecision(Amt); @@ -50,11 +52,15 @@ static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, return false; } -static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, - const char *FlagBeg, const char *E, bool Warn) { +static bool +ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, const char *FlagBeg, + const char *E, bool Warn, + const llvm::TextEncodingConverter &FormatStrConverter) { StringRef Flag(FlagBeg, E - FlagBeg); // Currently there is only one flag. - if (Flag == "tt") { + if (Flag.size() == 2 && + FormatStrConverter.convertBasicChar(FlagBeg[0]) == u8't' && + FormatStrConverter.convertBasicChar(FlagBeg[1]) == u8't') { FS.setHasObjCTechnicalTerm(FlagBeg); return false; } @@ -71,8 +77,9 @@ static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, const LangOptions &LO, - const TargetInfo &Target, bool Warn, - bool isFreeBSDKPrintf) { + const TargetInfo &Target, + const llvm::TextEncodingConverter &FormatStrConverter, + bool Warn, bool isFreeBSDKPrintf) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; @@ -89,7 +96,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, H.HandleNullChar(I); return true; } - if (c == '%') { + if (FormatStrConverter.convertBasicChar(c) == u8'%') { Start = I++; // Record the start of the format specifier. break; } @@ -107,7 +114,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, } PrintfSpecifier FS; - if (ParseArgPosition(H, FS, Start, I, E)) + if (ParseArgPosition(H, FS, Start, I, E, FormatStrConverter)) return true; if (I == E) { @@ -117,13 +124,17 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, return true; } - if (*I == '{') { + if (FormatStrConverter.convertBasicChar(*I) == u8'{') { ++I; unsigned char PrivacyFlags = 0; StringRef MatchedStr; do { - StringRef Str(I, E - I); + const char *II; + std::string S(I, E - I); + for (unsigned long i = 0; i < S.length(); ++i) + S[i] = FormatStrConverter.convertBasicChar(S[i]); + StringRef Str(S); std::string Match = "^[[:space:]]*" "(private|public|sensitive|mask\\.[^[:space:],}]*)" "[[:space:]]*(,|})"; @@ -132,25 +143,38 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, if (R.match(Str, &Matches)) { MatchedStr = Matches[1]; + II = I; I += Matches[0].size(); + while (FormatStrConverter.convertBasicChar(*II) == u8' ') + ++II; + // Set the privacy flag if the privacy annotation in the // comma-delimited segment is at least as strict as the privacy // annotations in previous comma-delimited segments. if (MatchedStr.starts_with("mask")) { - StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1); + StringRef MaskType(II + sizeof("mask.") - 1, + MatchedStr.size() - sizeof("mask.") + 1); unsigned Size = MaskType.size(); + if (Warn && (Size == 0 || Size > 8)) H.handleInvalidMaskType(MaskType); FS.setMaskType(MaskType); - } else if (MatchedStr == "sensitive") + } else if (MatchedStr == "sensitive") { + StringRef ProxyMatchedStr(II, sizeof("sensitive") - 1); + MatchedStr = ProxyMatchedStr; PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive; - else if (PrivacyFlags != - clang::analyze_os_log::OSLogBufferItem::IsSensitive && - MatchedStr == "private") + } else if (PrivacyFlags != + clang::analyze_os_log::OSLogBufferItem::IsSensitive && + MatchedStr == "private") { + StringRef ProxyMatchedStr(II, sizeof("private") - 1); + MatchedStr = ProxyMatchedStr; PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate; - else if (PrivacyFlags == 0 && MatchedStr == "public") + } else if (PrivacyFlags == 0 && MatchedStr == "public") { + StringRef ProxyMatchedStr(II, sizeof("public") - 1); + MatchedStr = ProxyMatchedStr; PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic; + } } else { size_t CommaOrBracePos = Str.find_if([](char c) { return c == ',' || c == '}'; }); @@ -165,7 +189,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, I += CommaOrBracePos + 1; } // Continue until the closing brace is found. - } while (*(I - 1) == ','); + } while (FormatStrConverter.convertBasicChar(*(I - 1)) == u8','); // Set the privacy flag. switch (PrivacyFlags) { @@ -188,7 +212,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, // Look for flags (if any). bool hasMore = true; for (; I != E; ++I) { - switch (*I) { + switch (FormatStrConverter.convertBasicChar(*I)) { default: hasMore = false; break; @@ -225,7 +249,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, // Look for the field width (if any). if (ParseFieldWidth(H, FS, Start, I, E, - FS.usesPositionalArg() ? nullptr : &argIndex)) + FS.usesPositionalArg() ? nullptr : &argIndex, + FormatStrConverter)) return true; if (I == E) { @@ -236,7 +261,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, } // Look for the precision (if any). - if (*I == '.') { + if (FormatStrConverter.convertBasicChar(*I) == u8'.') { ++I; if (I == E) { if (Warn) @@ -245,7 +270,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, } if (ParsePrecision(H, FS, Start, I, E, - FS.usesPositionalArg() ? nullptr : &argIndex)) + FS.usesPositionalArg() ? nullptr : &argIndex, + FormatStrConverter)) return true; if (I == E) { @@ -256,11 +282,11 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, } } - if (ParseVectorModifier(H, FS, I, E, LO)) + if (ParseVectorModifier(H, FS, I, E, LO, FormatStrConverter)) return true; // Look for the length modifier. - if (ParseLengthModifier(FS, I, E, LO) && I == E) { + if (ParseLengthModifier(FS, I, E, LO, FormatStrConverter) && I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); @@ -274,7 +300,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, // enables better recovery, and we don't know if // these flags are applicable until later. const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr; - if (*I == '[') { + if (FormatStrConverter.convertBasicChar(*I) == u8'[') { ObjCModifierFlagsStart = I; ++I; auto flagStart = I; @@ -286,8 +312,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, return true; } // Did we find the closing ']'? - if (*I == ']') { - if (ParseObjCFlags(H, FS, flagStart, I, Warn)) + if (FormatStrConverter.convertBasicChar(*I) == u8']') { + if (ParseObjCFlags(H, FS, flagStart, I, Warn, FormatStrConverter)) return true; ++I; break; @@ -307,139 +333,139 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, // Finally, look for the conversion specifier. const char *conversionPosition = I++; ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; - switch (*conversionPosition) { + switch (FormatStrConverter.convertBasicChar(*conversionPosition)) { default: break; // C99: 7.19.6.1 (section 8). - case '%': + case u8'%': k = ConversionSpecifier::PercentArg; break; - case 'A': + case u8'A': k = ConversionSpecifier::AArg; break; - case 'E': + case u8'E': k = ConversionSpecifier::EArg; break; - case 'F': + case u8'F': k = ConversionSpecifier::FArg; break; - case 'G': + case u8'G': k = ConversionSpecifier::GArg; break; - case 'X': + case u8'X': k = ConversionSpecifier::XArg; break; - case 'a': + case u8'a': k = ConversionSpecifier::aArg; break; - case 'c': + case u8'c': k = ConversionSpecifier::cArg; break; - case 'd': + case u8'd': k = ConversionSpecifier::dArg; break; - case 'e': + case u8'e': k = ConversionSpecifier::eArg; break; - case 'f': + case u8'f': k = ConversionSpecifier::fArg; break; - case 'g': + case u8'g': k = ConversionSpecifier::gArg; break; - case 'i': + case u8'i': k = ConversionSpecifier::iArg; break; - case 'n': + case u8'n': // Not handled, but reserved in OpenCL. if (!LO.OpenCL) k = ConversionSpecifier::nArg; break; - case 'o': + case u8'o': k = ConversionSpecifier::oArg; break; - case 'p': + case u8'p': k = ConversionSpecifier::pArg; break; - case 's': + case u8's': k = ConversionSpecifier::sArg; break; - case 'u': + case u8'u': k = ConversionSpecifier::uArg; break; - case 'x': + case u8'x': k = ConversionSpecifier::xArg; break; // C23. - case 'b': + case u8'b': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDbArg; // int followed by char * else k = ConversionSpecifier::bArg; break; - case 'B': + case u8'B': k = ConversionSpecifier::BArg; break; // POSIX specific. - case 'C': + case u8'C': k = ConversionSpecifier::CArg; break; - case 'S': + case u8'S': k = ConversionSpecifier::SArg; break; // Apple extension for os_log - case 'P': + case u8'P': k = ConversionSpecifier::PArg; break; // Objective-C. - case '@': + case u8'@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. - case 'm': + case u8'm': k = ConversionSpecifier::PrintErrno; break; - case 'r': + case u8'r': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDrArg; // int else if (LO.FixedPoint) k = ConversionSpecifier::rArg; break; - case 'y': + case u8'y': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDyArg; // int break; // Apple-specific. - case 'D': + case u8'D': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * else if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::DArg; break; - case 'O': + case u8'O': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::OArg; break; - case 'U': + case u8'U': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::UArg; break; // MS specific. - case 'Z': + case u8'Z': if (Target.getTriple().isOSMSVCRT()) k = ConversionSpecifier::ZArg; break; // ISO/IEC TR 18037 (fixed-point) specific. // NOTE: 'r' is handled up above since FreeBSD also supports %r. - case 'k': + case u8'k': if (LO.FixedPoint) k = ConversionSpecifier::kArg; break; - case 'K': + case u8'K': if (LO.FixedPoint) k = ConversionSpecifier::KArg; break; - case 'R': + case u8'R': if (LO.FixedPoint) k = ConversionSpecifier::RArg; break; @@ -470,7 +496,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, FS.setConversionSpecifier(CS); } // Assume the conversion takes one argument. - return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); + return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len, + FormatStrConverter); } return PrintfSpecifierResult(Start, FS); } @@ -480,11 +507,11 @@ bool clang::analyze_format_string::ParsePrintfString( const TargetInfo &Target, bool isFreeBSDKPrintf) { unsigned argIndex = 0; - + llvm::TextEncodingConverter Conv = makeFormatStrConverter(Target); // Keep looking for a format specifier until we have exhausted the string. while (I != E) { const PrintfSpecifierResult &FSR = ParsePrintfSpecifier( - H, I, E, argIndex, LO, Target, true, isFreeBSDKPrintf); + H, I, E, argIndex, LO, Target, Conv, true, isFreeBSDKPrintf); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) @@ -495,7 +522,7 @@ bool clang::analyze_format_string::ParsePrintfString( continue; // We have a format specifier. Pass it to the callback. if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), - I - FSR.getStart(), Target)) + I - FSR.getStart(), Target, Conv)) return true; } assert(I == E && "Format string not exhausted"); @@ -507,12 +534,12 @@ bool clang::analyze_format_string::ParseFormatStringHasSArg( const TargetInfo &Target) { unsigned argIndex = 0; - + llvm::TextEncodingConverter Conv = makeFormatStrConverter(Target); // Keep looking for a %s format specifier until we have exhausted the string. FormatStringHandler H; while (I != E) { const PrintfSpecifierResult &FSR = - ParsePrintfSpecifier(H, I, E, argIndex, LO, Target, false, false); + ParsePrintfSpecifier(H, I, E, argIndex, LO, Target, Conv, false, false); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) @@ -534,11 +561,12 @@ bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers( const char *Begin, const char *End, const LangOptions &LO, const TargetInfo &Target) { unsigned ArgIndex = 0; + llvm::TextEncodingConverter Conv = makeFormatStrConverter(Target); // Keep looking for a formatting specifier until we have exhausted the string. FormatStringHandler H; while (Begin != End) { - const PrintfSpecifierResult &FSR = - ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false); + const PrintfSpecifierResult &FSR = ParsePrintfSpecifier( + H, Begin, End, ArgIndex, LO, Target, Conv, false, false); if (FSR.shouldStop()) break; if (FSR.hasValue()) diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 5e1622e95277b..9c5132e5ff9b8 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -13,7 +13,6 @@ #include "FormatStringParsing.h" #include "clang/AST/FormatString.h" -#include "clang/Basic/TargetInfo.h" using clang::UpdateOnReturn; using clang::analyze_format_string::ArgType; @@ -71,17 +70,16 @@ static bool ParseScanList(FormatStringHandler &H, ScanfConversionSpecifier &CS, // FIXME: Much of this is copy-paste from ParsePrintfSpecifier. // We can possibly refactor. -static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, - const char *&Beg, const char *E, - unsigned &argIndex, - const LangOptions &LO, - const TargetInfo &Target) { +static ScanfSpecifierResult +ParseScanfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, + unsigned &argIndex, const LangOptions &LO, + const TargetInfo &Target, + const llvm::TextEncodingConverter &FormatStrConverter) { using namespace clang::analyze_format_string; using namespace clang::analyze_scanf; const char *I = Beg; const char *Start = nullptr; UpdateOnReturn UpdateBeg(Beg, I); - // Look for a '%' character that indicates the start of a format specifier. for (; I != E; ++I) { char c = *I; @@ -90,7 +88,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, H.HandleNullChar(I); return true; } - if (c == '%') { + if (FormatStrConverter.convertBasicChar(c) == u8'%') { Start = I++; // Record the start of the format specifier. break; } @@ -107,7 +105,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, } ScanfSpecifier FS; - if (ParseArgPosition(H, FS, Start, I, E)) + if (ParseArgPosition(H, FS, Start, I, E, FormatStrConverter)) return true; if (I == E) { @@ -117,7 +115,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, } // Look for '*' flag if it is present. - if (*I == '*') { + if (FormatStrConverter.convertBasicChar(*I) == u8'*') { FS.setSuppressAssignment(I); if (++I == E) { H.HandleIncompleteSpecifier(Start, E - Start); @@ -127,7 +125,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, // Look for the field width (if any). Unlike printf, this is either // a fixed integer or isn't present. - const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E); + const OptionalAmount &Amt = + clang::analyze_format_string::ParseAmount(I, E, FormatStrConverter); if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) { assert(Amt.getHowSpecified() == OptionalAmount::Constant); FS.setFieldWidth(Amt); @@ -140,7 +139,9 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, } // Look for the length modifier. - if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) { + if (ParseLengthModifier(FS, I, E, LO, FormatStrConverter, + /*IsScanf=*/true) && + I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; @@ -155,89 +156,89 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, // Finally, look for the conversion specifier. const char *conversionPosition = I++; ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier; - switch (*conversionPosition) { + switch (FormatStrConverter.convertBasicChar(*conversionPosition)) { default: break; - case '%': + case u8'%': k = ConversionSpecifier::PercentArg; break; - case 'b': + case u8'b': k = ConversionSpecifier::bArg; break; - case 'A': + case u8'A': k = ConversionSpecifier::AArg; break; - case 'E': + case u8'E': k = ConversionSpecifier::EArg; break; - case 'F': + case u8'F': k = ConversionSpecifier::FArg; break; - case 'G': + case u8'G': k = ConversionSpecifier::GArg; break; - case 'X': + case u8'X': k = ConversionSpecifier::XArg; break; - case 'a': + case u8'a': k = ConversionSpecifier::aArg; break; - case 'd': + case u8'd': k = ConversionSpecifier::dArg; break; - case 'e': + case u8'e': k = ConversionSpecifier::eArg; break; - case 'f': + case u8'f': k = ConversionSpecifier::fArg; break; - case 'g': + case u8'g': k = ConversionSpecifier::gArg; break; - case 'i': + case u8'i': k = ConversionSpecifier::iArg; break; - case 'n': + case u8'n': k = ConversionSpecifier::nArg; break; - case 'c': + case u8'c': k = ConversionSpecifier::cArg; break; - case 'C': + case u8'C': k = ConversionSpecifier::CArg; break; - case 'S': + case u8'S': k = ConversionSpecifier::SArg; break; - case '[': + case u8'[': k = ConversionSpecifier::ScanListArg; break; - case 'u': + case u8'u': k = ConversionSpecifier::uArg; break; - case 'x': + case u8'x': k = ConversionSpecifier::xArg; break; - case 'o': + case u8'o': k = ConversionSpecifier::oArg; break; - case 's': + case u8's': k = ConversionSpecifier::sArg; break; - case 'p': + case u8'p': k = ConversionSpecifier::pArg; break; // Apple extensions // Apple-specific - case 'D': + case u8'D': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::DArg; break; - case 'O': + case u8'O': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::OArg; break; - case 'U': + case u8'U': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::UArg; break; @@ -262,7 +263,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, FS.setConversionSpecifier(CS); } // Assume the conversion takes one argument. - return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len); + return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len, + FormatStrConverter); } return ScanfSpecifierResult(Start, FS); } @@ -610,17 +612,17 @@ void ScanfSpecifier::toString(raw_ostream &os) const { } bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H, - const char *I, - const char *E, - const LangOptions &LO, - const TargetInfo &Target) { - + const char *I, + const char *E, + const LangOptions &LO, + const TargetInfo &Target) { unsigned argIndex = 0; + llvm::TextEncodingConverter Conv = makeFormatStrConverter(Target); // Keep looking for a format specifier until we have exhausted the string. while (I != E) { const ScanfSpecifierResult &FSR = - ParseScanfSpecifier(H, I, E, argIndex, LO, Target); + ParseScanfSpecifier(H, I, E, argIndex, LO, Target, Conv); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 09f610358ca65..72dd33e31bd8e 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -1057,7 +1057,8 @@ hasUnsafeFormatOrSArg(ASTContext &Ctx, const CallExpr *Call, bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen, - const TargetInfo &Target) override { + const TargetInfo &Target, + const llvm::TextEncodingConverter &) override { if (FS.getConversionSpecifier().getKind() != analyze_printf::PrintfConversionSpecifier::sArg) return true; // continue parsing diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 406f03a17f7eb..5dddb89b9ebdc 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -104,6 +104,7 @@ #include "llvm/Support/Locale.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/TextEncoding.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/RISCVTargetParser.h" #include "llvm/TargetParser/Triple.h" @@ -936,7 +937,8 @@ class EstimateSizeFormatHandler bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *, unsigned SpecifierLen, - const TargetInfo &) override { + const TargetInfo &, + const llvm::TextEncodingConverter &) override { const size_t FieldWidth = computeFieldWidth(FS); const size_t Precision = computePrecision(FS); @@ -8312,10 +8314,10 @@ class CheckFormatHandler : public analyze_format_string::FormatStringHandler { ArrayRef Fixit = {}); protected: - bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, - const char *startSpec, - unsigned specifierLen, - const char *csStart, unsigned csLen); + bool HandleInvalidConversionSpecifier( + unsigned argIndex, SourceLocation Loc, const char *startSpec, + unsigned specifierLen, const char *csStart, unsigned csLen, + const llvm::TextEncodingConverter &Conv); void HandlePositionalNonpositionalArgs(SourceLocation Loc, const char *startSpec, @@ -8562,7 +8564,8 @@ void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall, bool CheckFormatHandler::HandleInvalidConversionSpecifier( unsigned argIndex, SourceLocation Loc, const char *startSpec, - unsigned specifierLen, const char *csStart, unsigned csLen) { + unsigned specifierLen, const char *csStart, unsigned csLen, + const llvm::TextEncodingConverter &Conv) { bool keepGoing = true; if (argIndex < NumDataArgs) { // Consider the argument coverered, even though the specifier doesn't @@ -8577,7 +8580,15 @@ bool CheckFormatHandler::HandleInvalidConversionSpecifier( keepGoing = false; } - StringRef Specifier(csStart, csLen); + // The csStart points to a character that has already been converted to the + // exec charset, so we have to reverse the conversion to allow diagnostic + // message to match an expected value when using -verify option, + SmallString<4> RS; + auto EC = Conv.convert(StringRef(csStart, csLen), RS); + if (EC) { + keepGoing = false; + } + llvm::StringRef Specifier(RS); // If the specifier in non-printable, it could be the first byte of a UTF-8 // sequence. In that case, print the UTF-8 code point. If not, print the byte @@ -8731,13 +8742,15 @@ class CheckPrintfHandler : public CheckFormatHandler { bool HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, - unsigned specifierLen) override; + unsigned specifierLen, + const llvm::TextEncodingConverter &Conv) override; void handleInvalidMaskType(StringRef MaskType) override; bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen, - const TargetInfo &Target) override; + const TargetInfo &Target, + const llvm::TextEncodingConverter &Conv) override; bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, unsigned SpecifierLen, const Expr *E); @@ -8861,23 +8874,25 @@ class DecomposePrintfHandler : public CheckPrintfHandler { FormatStringType type, bool IsObjC, bool InFunctionCall, llvm::SmallVectorImpl &Args); - virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, - const char *startSpecifier, - unsigned specifierLen, - const TargetInfo &Target) override; + virtual bool + HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, unsigned specifierLen, + const TargetInfo &Target, + const llvm::TextEncodingConverter &Conv) override; }; } // namespace bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, - unsigned specifierLen) { + unsigned specifierLen, + const llvm::TextEncodingConverter &Conv) { const analyze_printf::PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); return HandleInvalidConversionSpecifier( FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier, - specifierLen, CS.getStart(), CS.getLength()); + specifierLen, CS.getStart(), CS.getLength(), Conv); } void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) { @@ -9140,9 +9155,10 @@ bool DecomposePrintfHandler::GetSpecifiers( bool DecomposePrintfHandler::HandlePrintfSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, - unsigned specifierLen, const TargetInfo &Target) { + unsigned specifierLen, const TargetInfo &Target, + const llvm::TextEncodingConverter &Conv) { if (!CheckPrintfHandler::HandlePrintfSpecifier(FS, startSpecifier, - specifierLen, Target)) { + specifierLen, Target, Conv)) { HadError = true; return false; } @@ -9299,7 +9315,8 @@ bool CheckPrintfHandler::checkForCStrMembers( bool CheckPrintfHandler::HandlePrintfSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, - unsigned specifierLen, const TargetInfo &Target) { + unsigned specifierLen, const TargetInfo &Target, + const llvm::TextEncodingConverter &Conv) { using namespace analyze_format_string; using namespace analyze_printf; @@ -9386,14 +9403,14 @@ bool CheckPrintfHandler::HandlePrintfSpecifier( // in a non-ObjC literal. if (!allowsObjCArg() && CS.isObjCArg()) { return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, - specifierLen); + specifierLen, Conv); } // %P can only be used with os_log. if (FSType != FormatStringType::OSLog && CS.getKind() == ConversionSpecifier::PArg) { return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, - specifierLen); + specifierLen, Conv); } // %n is not allowed with os_log. @@ -9413,7 +9430,7 @@ bool CheckPrintfHandler::HandlePrintfSpecifier( CS.getKind() == ConversionSpecifier::sArg || CS.getKind() == ConversionSpecifier::ObjCObjArg)) { return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, - specifierLen); + specifierLen, Conv); } // Check for use of public/private annotation outside of os_log(). @@ -10089,10 +10106,10 @@ class CheckScanfHandler : public CheckFormatHandler { const char *startSpecifier, unsigned specifierLen) override; - bool - HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier &FS, - const char *startSpecifier, - unsigned specifierLen) override; + bool HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, + unsigned specifierLen, + const llvm::TextEncodingConverter &Conv) override; void HandleIncompleteScanList(const char *start, const char *end) override; }; @@ -10108,13 +10125,15 @@ void CheckScanfHandler::HandleIncompleteScanList(const char *start, bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, - unsigned specifierLen) { + unsigned specifierLen, + const llvm::TextEncodingConverter &Conv) { + const analyze_scanf::ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); return HandleInvalidConversionSpecifier( FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier, - specifierLen, CS.getStart(), CS.getLength()); + specifierLen, CS.getStart(), CS.getLength(), Conv); } bool CheckScanfHandler::HandleScanfSpecifier( diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index f4490c940bf61..f3c6d8758c71e 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -266,6 +266,7 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel, } return SL; } + if (DiagnoseUnexpandedParameterPack(Expr)) return ExprError(); if (Expr->getDependence() != ExprDependence::None) diff --git a/llvm/include/llvm/Support/TextEncoding.h b/llvm/include/llvm/Support/TextEncoding.h index 6e7eb95464eff..7ea1a6e1ff28b 100644 --- a/llvm/include/llvm/Support/TextEncoding.h +++ b/llvm/include/llvm/Support/TextEncoding.h @@ -59,6 +59,10 @@ class TextEncodingConverterImplBase { public: virtual ~TextEncodingConverterImplBase() = default; + /// Returns true if this converter performs no conversion (UTF-8 to + /// UTF-8). + virtual bool isNoop() const { return false; } + /// Converts a string and resets the converter to the initial state. std::error_code convert(StringRef Source, SmallVectorImpl &Result) { auto EC = convertString(Source, Result); @@ -104,6 +108,8 @@ class TextEncodingConverter { LLVM_ABI static ErrorOr create(StringRef From, StringRef To); + LLVM_ABI static ErrorOr createNoopConverter(); + TextEncodingConverter(const TextEncodingConverter &) = delete; TextEncodingConverter &operator=(const TextEncodingConverter &) = delete; @@ -134,6 +140,19 @@ class TextEncodingConverter { return std::string(Result); return EC; } + + /// Returns true if this converter performs no conversion. + bool isNoop() const { return Converter->isNoop(); } + + // This method is used in format string handling and is only intended + // to support basic charsets, not multibyte characters. + char convertBasicChar(char SingleChar) const { + SmallString<1> Result; + auto EC = Converter->convert(StringRef(&SingleChar, 1), Result); + if (!EC) + return Result[0]; + return '\0'; + } }; } // namespace llvm diff --git a/llvm/lib/Support/TextEncoding.cpp b/llvm/lib/Support/TextEncoding.cpp index c44bf78ea9fba..bf77a4369179c 100644 --- a/llvm/lib/Support/TextEncoding.cpp +++ b/llvm/lib/Support/TextEncoding.cpp @@ -357,3 +357,24 @@ ErrorOr TextEncodingConverter::create(StringRef From, return std::make_error_code(std::errc::invalid_argument); #endif } + +class TextEncodingConverterNoop final + : public details::TextEncodingConverterImplBase { + +public: + TextEncodingConverterNoop() {} + + std::error_code convertString(StringRef Source, + SmallVectorImpl &Result) override { + Result.assign(Source.begin(), Source.end()); + return std::error_code(); + } + + void reset() override {} + + bool isNoop() const override { return true; } +}; + +ErrorOr TextEncodingConverter::createNoopConverter() { + return TextEncodingConverter(std::make_unique()); +}