freebsd-dev/contrib/llvm/patches/patch-01-freebsd-kprintf.diff
Dimitry Andric b09980d164 Merge llvm 3.6.0rc4 from ^/vendor/llvm/dist, merge clang 3.6.0rc4 from
^/vendor/clang/dist, resolve conflicts, and update patches.
2015-02-19 22:20:19 +00:00

382 lines
17 KiB
Diff

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'
@@ -204,7 +210,8 @@ class ConversionSpecifier {
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 +653,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
@@ -8566,6 +8566,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
@@ -2584,6 +2584,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);
}
@@ -3365,6 +3366,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()) {
@@ -3988,7 +4026,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,
@@ -3996,7 +4035,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
+}