diff options
Diffstat (limited to 'contrib/llvm/patches/patch-01-freebsd-kprintf.diff')
-rw-r--r-- | contrib/llvm/patches/patch-01-freebsd-kprintf.diff | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/contrib/llvm/patches/patch-01-freebsd-kprintf.diff b/contrib/llvm/patches/patch-01-freebsd-kprintf.diff new file mode 100644 index 0000000..cc203c4 --- /dev/null +++ b/contrib/llvm/patches/patch-01-freebsd-kprintf.diff @@ -0,0 +1,382 @@ +This patch adds support for the FreeBSD kernel specific printf format +specifiers: %b, %D, %r and %y, via a new __freebsd_kprintf__ format +string type. + +Sent upstream as http://reviews.llvm.org/D7154 + +Index: tools/clang/include/clang/Analysis/Analyses/FormatString.h +=================================================================== +--- tools/clang/include/clang/Analysis/Analyses/FormatString.h ++++ tools/clang/include/clang/Analysis/Analyses/FormatString.h +@@ -161,6 +161,12 @@ class ConversionSpecifier { + ObjCObjArg, // '@' + ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, + ++ // FreeBSD kernel specific specifiers. ++ FreeBSDbArg, ++ FreeBSDDArg, ++ FreeBSDrArg, ++ FreeBSDyArg, ++ + // GlibC specific specifiers. + PrintErrno, // 'm' + +@@ -203,8 +209,8 @@ class ConversionSpecifier { + unsigned getLength() const { + return EndScanList ? EndScanList - Position : 1; + } +- +- bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; } ++ bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) || ++ kind == FreeBSDrArg || kind == FreeBSDyArg; } + bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } + bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } + const char *toString() const; +@@ -646,7 +652,7 @@ class FormatStringHandler { + + bool ParsePrintfString(FormatStringHandler &H, + const char *beg, const char *end, const LangOptions &LO, +- const TargetInfo &Target); ++ const TargetInfo &Target, bool isFreeBSDKPrintf); + + bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO, + const TargetInfo &Target); +Index: tools/clang/include/clang/Sema/Sema.h +=================================================================== +--- tools/clang/include/clang/Sema/Sema.h ++++ tools/clang/include/clang/Sema/Sema.h +@@ -8572,6 +8572,7 @@ class Sema { + FST_Strftime, + FST_Strfmon, + FST_Kprintf, ++ FST_FreeBSDKPrintf, + FST_Unknown + }; + static FormatStringType GetFormatStringType(const FormatAttr *Format); +Index: tools/clang/lib/Analysis/FormatString.cpp +=================================================================== +--- tools/clang/lib/Analysis/FormatString.cpp ++++ tools/clang/lib/Analysis/FormatString.cpp +@@ -552,6 +552,12 @@ const char *ConversionSpecifier::toString() const + // Objective-C specific specifiers. + case ObjCObjArg: return "@"; + ++ // FreeBSD kernel specific specifiers. ++ case FreeBSDbArg: return "b"; ++ case FreeBSDDArg: return "D"; ++ case FreeBSDrArg: return "r"; ++ case FreeBSDyArg: return "y"; ++ + // GlibC specific specifiers. + case PrintErrno: return "m"; + +@@ -647,6 +653,9 @@ bool FormatSpecifier::hasValidLengthModifier(const + case ConversionSpecifier::XArg: + case ConversionSpecifier::nArg: + return true; ++ case ConversionSpecifier::FreeBSDrArg: ++ case ConversionSpecifier::FreeBSDyArg: ++ return Target.getTriple().isOSFreeBSD(); + default: + return false; + } +@@ -677,6 +686,9 @@ bool FormatSpecifier::hasValidLengthModifier(const + case ConversionSpecifier::ScanListArg: + case ConversionSpecifier::ZArg: + return true; ++ case ConversionSpecifier::FreeBSDrArg: ++ case ConversionSpecifier::FreeBSDyArg: ++ return Target.getTriple().isOSFreeBSD(); + default: + return false; + } +@@ -807,6 +819,10 @@ bool FormatSpecifier::hasStandardConversionSpecifi + case ConversionSpecifier::SArg: + return LangOpt.ObjC1 || LangOpt.ObjC2; + case ConversionSpecifier::InvalidSpecifier: ++ case ConversionSpecifier::FreeBSDbArg: ++ case ConversionSpecifier::FreeBSDDArg: ++ case ConversionSpecifier::FreeBSDrArg: ++ case ConversionSpecifier::FreeBSDyArg: + case ConversionSpecifier::PrintErrno: + case ConversionSpecifier::DArg: + case ConversionSpecifier::OArg: +Index: tools/clang/lib/Analysis/PrintfFormatString.cpp +=================================================================== +--- tools/clang/lib/Analysis/PrintfFormatString.cpp ++++ tools/clang/lib/Analysis/PrintfFormatString.cpp +@@ -55,7 +55,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier( + unsigned &argIndex, + const LangOptions &LO, + const TargetInfo &Target, +- bool Warn) { ++ bool Warn, ++ bool isFreeBSDKPrintf) { + + using namespace clang::analyze_format_string; + using namespace clang::analyze_printf; +@@ -206,9 +207,24 @@ static PrintfSpecifierResult ParsePrintfSpecifier( + case '@': k = ConversionSpecifier::ObjCObjArg; break; + // Glibc specific. + case 'm': k = ConversionSpecifier::PrintErrno; break; ++ // FreeBSD kernel specific. ++ case 'b': ++ if (isFreeBSDKPrintf) ++ k = ConversionSpecifier::FreeBSDbArg; // int followed by char * ++ break; ++ case 'r': ++ if (isFreeBSDKPrintf) ++ k = ConversionSpecifier::FreeBSDrArg; // int ++ break; ++ case 'y': ++ if (isFreeBSDKPrintf) ++ k = ConversionSpecifier::FreeBSDyArg; // int ++ break; + // Apple-specific. + case 'D': +- if (Target.getTriple().isOSDarwin()) ++ if (isFreeBSDKPrintf) ++ k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * ++ else if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::DArg; + break; + case 'O': +@@ -228,6 +244,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier( + FS.setConversionSpecifier(CS); + if (CS.consumesDataArgument() && !FS.usesPositionalArg()) + FS.setArgIndex(argIndex++); ++ // FreeBSD kernel specific. ++ if (k == ConversionSpecifier::FreeBSDbArg || ++ k == ConversionSpecifier::FreeBSDDArg) ++ argIndex++; + + if (k == ConversionSpecifier::InvalidSpecifier) { + // Assume the conversion takes one argument. +@@ -240,7 +260,8 @@ bool clang::analyze_format_string::ParsePrintfStri + const char *I, + const char *E, + const LangOptions &LO, +- const TargetInfo &Target) { ++ const TargetInfo &Target, ++ bool isFreeBSDKPrintf) { + + unsigned argIndex = 0; + +@@ -247,7 +268,8 @@ bool clang::analyze_format_string::ParsePrintfStri + // 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); ++ LO, Target, 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()) +@@ -276,7 +298,8 @@ bool clang::analyze_format_string::ParseFormatStri + FormatStringHandler H; + while (I != E) { + const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, +- LO, Target, false); ++ LO, Target, 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()) +@@ -674,6 +697,8 @@ bool PrintfSpecifier::hasValidPlusPrefix() const { + case ConversionSpecifier::GArg: + case ConversionSpecifier::aArg: + case ConversionSpecifier::AArg: ++ case ConversionSpecifier::FreeBSDrArg: ++ case ConversionSpecifier::FreeBSDyArg: + return true; + + default: +@@ -699,6 +724,8 @@ bool PrintfSpecifier::hasValidAlternativeForm() co + case ConversionSpecifier::FArg: + case ConversionSpecifier::gArg: + case ConversionSpecifier::GArg: ++ case ConversionSpecifier::FreeBSDrArg: ++ case ConversionSpecifier::FreeBSDyArg: + return true; + + default: +@@ -729,6 +756,8 @@ bool PrintfSpecifier::hasValidLeadingZeros() const + case ConversionSpecifier::FArg: + case ConversionSpecifier::gArg: + case ConversionSpecifier::GArg: ++ case ConversionSpecifier::FreeBSDrArg: ++ case ConversionSpecifier::FreeBSDyArg: + return true; + + default: +@@ -753,6 +782,8 @@ bool PrintfSpecifier::hasValidSpacePrefix() const + case ConversionSpecifier::GArg: + case ConversionSpecifier::aArg: + case ConversionSpecifier::AArg: ++ case ConversionSpecifier::FreeBSDrArg: ++ case ConversionSpecifier::FreeBSDyArg: + return true; + + default: +@@ -818,6 +849,8 @@ bool PrintfSpecifier::hasValidPrecision() const { + case ConversionSpecifier::gArg: + case ConversionSpecifier::GArg: + case ConversionSpecifier::sArg: ++ case ConversionSpecifier::FreeBSDrArg: ++ case ConversionSpecifier::FreeBSDyArg: + return true; + + default: +Index: tools/clang/lib/Sema/SemaChecking.cpp +=================================================================== +--- tools/clang/lib/Sema/SemaChecking.cpp ++++ tools/clang/lib/Sema/SemaChecking.cpp +@@ -2579,6 +2579,7 @@ Sema::FormatStringType Sema::GetFormatStringType(c + .Case("strftime", FST_Strftime) + .Case("strfmon", FST_Strfmon) + .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) ++ .Case("freebsd_kprintf", FST_FreeBSDKPrintf) + .Default(FST_Unknown); + } + +@@ -3360,6 +3361,43 @@ CheckPrintfHandler::HandlePrintfSpecifier(const an + CoveredArgs.set(argIndex); + } + ++ // FreeBSD kernel extensions. ++ if (CS.getKind() == ConversionSpecifier::FreeBSDbArg || ++ CS.getKind() == ConversionSpecifier::FreeBSDDArg) { ++ // We need at least two arguments. ++ if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex + 1)) ++ return false; ++ ++ // Claim the second argument. ++ CoveredArgs.set(argIndex + 1); ++ ++ // Type check the first argument (int for %b, pointer for %D) ++ const Expr *Ex = getDataArg(argIndex); ++ const analyze_printf::ArgType &AT = ++ (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ? ++ ArgType(S.Context.IntTy) : ArgType::CPointerTy; ++ if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) ++ EmitFormatDiagnostic( ++ S.PDiag(diag::warn_format_conversion_argument_type_mismatch) ++ << AT.getRepresentativeTypeName(S.Context) << Ex->getType() ++ << false << Ex->getSourceRange(), ++ Ex->getLocStart(), /*IsStringLocation*/false, ++ getSpecifierRange(startSpecifier, specifierLen)); ++ ++ // Type check the second argument (char * for both %b and %D) ++ Ex = getDataArg(argIndex + 1); ++ const analyze_printf::ArgType &AT2 = ArgType::CStrTy; ++ if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType())) ++ EmitFormatDiagnostic( ++ S.PDiag(diag::warn_format_conversion_argument_type_mismatch) ++ << AT2.getRepresentativeTypeName(S.Context) << Ex->getType() ++ << false << Ex->getSourceRange(), ++ Ex->getLocStart(), /*IsStringLocation*/false, ++ getSpecifierRange(startSpecifier, specifierLen)); ++ ++ return true; ++ } ++ + // Check for using an Objective-C specific conversion specifier + // in a non-ObjC literal. + if (!ObjCContext && CS.isObjCArg()) { +@@ -3983,7 +4021,8 @@ void Sema::CheckFormatString(const StringLiteral * + return; + } + +- if (Type == FST_Printf || Type == FST_NSString) { ++ if (Type == FST_Printf || Type == FST_NSString || ++ Type == FST_FreeBSDKPrintf) { + CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, + numDataArgs, (Type == FST_NSString), + Str, HasVAListArg, Args, format_idx, +@@ -3991,7 +4030,8 @@ void Sema::CheckFormatString(const StringLiteral * + + if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, + getLangOpts(), +- Context.getTargetInfo())) ++ Context.getTargetInfo(), ++ Type == FST_FreeBSDKPrintf)) + H.DoneProcessing(); + } else if (Type == FST_Scanf) { + CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, +Index: tools/clang/lib/Sema/SemaDeclAttr.cpp +=================================================================== +--- tools/clang/lib/Sema/SemaDeclAttr.cpp ++++ tools/clang/lib/Sema/SemaDeclAttr.cpp +@@ -2481,6 +2481,7 @@ static FormatAttrKind getFormatAttrKind(StringRef + .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat) + .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat) + .Case("kprintf", SupportedFormat) // OpenBSD. ++ .Case("freebsd_kprintf", SupportedFormat) // FreeBSD. + + .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat) + .Default(InvalidFormat); +Index: tools/clang/test/Sema/attr-format.c +=================================================================== +--- tools/clang/test/Sema/attr-format.c ++++ tools/clang/test/Sema/attr-format.c +@@ -57,8 +57,15 @@ void callnull(void){ + null(0, (int*)0); // expected-warning {{incompatible pointer types}} + } + ++// FreeBSD kernel extensions ++void a3(const char *a, ...) __attribute__((format(freebsd_kprintf, 1,2))); // no-error ++void b3(const char *a, ...) __attribute__((format(freebsd_kprintf, 1,1))); // expected-error {{'format' attribute parameter 3 is out of bounds}} ++void c3(const char *a, ...) __attribute__((format(freebsd_kprintf, 0,2))); // expected-error {{'format' attribute parameter 2 is out of bounds}} ++void d3(const char *a, int c) __attribute__((format(freebsd_kprintf, 1,2))); // expected-error {{format attribute requires variadic function}} ++void e3(char *str, int c, ...) __attribute__((format(freebsd_kprintf, 2,3))); // expected-error {{format argument not a string type}} + + ++ + // PR4470 + int xx_vprintf(const char *, va_list); + +Index: tools/clang/test/Sema/format-strings-freebsd.c +=================================================================== +--- tools/clang/test/Sema/format-strings-freebsd.c ++++ tools/clang/test/Sema/format-strings-freebsd.c +@@ -0,0 +1,40 @@ ++// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-unknown-freebsd %s ++// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-freebsd %s ++ ++// Test FreeBSD kernel printf extensions. ++int freebsd_kernel_printf(const char *, ...) __attribute__((__format__(__freebsd_kprintf__, 1, 2))); ++ ++void check_freebsd_kernel_extensions(int i, long l, char *s) ++{ ++ // %b expects an int and a char * ++ freebsd_kernel_printf("reg=%b\n", i, "\10\2BITTWO\1BITONE\n"); // no-warning ++ freebsd_kernel_printf("reg=%b\n", l, "\10\2BITTWO\1BITONE\n"); // expected-warning{{format specifies type 'int' but the argument has type 'long'}} ++ freebsd_kernel_printf("reg=%b\n", i, l); // expected-warning{{format specifies type 'char *' but the argument has type 'long'}} ++ freebsd_kernel_printf("reg=%b\n", i); // expected-warning{{more '%' conversions than data arguments}} ++ freebsd_kernel_printf("reg=%b\n", i, "\10\2BITTWO\1BITONE\n", l); // expected-warning{{data argument not used by format string}} ++ ++ // %D expects an unsigned char * and a char * ++ freebsd_kernel_printf("%6D", s, ":"); // no-warning ++ freebsd_kernel_printf("%6D", i, ":"); // expected-warning{{format specifies type 'void *' but the argument has type 'int'}} ++ freebsd_kernel_printf("%6D", s, i); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}} ++ freebsd_kernel_printf("%6D", s); // expected-warning{{more '%' conversions than data arguments}} ++ freebsd_kernel_printf("%6D", s, ":", i); // expected-warning{{data argument not used by format string}} ++ ++ freebsd_kernel_printf("%*D", 42, s, ":"); // no-warning ++ freebsd_kernel_printf("%*D", 42, i, ":"); // expected-warning{{format specifies type 'void *' but the argument has type 'int'}} ++ freebsd_kernel_printf("%*D", 42, s, i); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}} ++ freebsd_kernel_printf("%*D", 42, s); // expected-warning{{more '%' conversions than data arguments}} ++ freebsd_kernel_printf("%*D", 42, s, ":", i); // expected-warning{{data argument not used by format string}} ++ ++ // %r expects an int ++ freebsd_kernel_printf("%r", i); // no-warning ++ freebsd_kernel_printf("%r", l); // expected-warning{{format specifies type 'int' but the argument has type 'long'}} ++ freebsd_kernel_printf("%lr", i); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} ++ freebsd_kernel_printf("%lr", l); // no-warning ++ ++ // %y expects an int ++ freebsd_kernel_printf("%y", i); // no-warning ++ freebsd_kernel_printf("%y", l); // expected-warning{{format specifies type 'int' but the argument has type 'long'}} ++ freebsd_kernel_printf("%ly", i); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} ++ freebsd_kernel_printf("%ly", l); // no-warning ++} |