summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/patches/patch-01-freebsd-kprintf.diff
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/patches/patch-01-freebsd-kprintf.diff')
-rw-r--r--contrib/llvm/patches/patch-01-freebsd-kprintf.diff382
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
++}
OpenPOWER on IntegriCloud