]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/patches/patch-01-freebsd-kprintf.diff
Merge ^/head r277719 through 277776.
[FreeBSD/FreeBSD.git] / contrib / llvm / patches / patch-01-freebsd-kprintf.diff
1 This patch adds support for the FreeBSD kernel specific printf format
2 specifiers: %b, %D, %r and %y, via a new __freebsd_kprintf__ format
3 string type.
4
5 Sent upstream as http://reviews.llvm.org/D7154
6
7 Index: tools/clang/include/clang/Analysis/Analyses/FormatString.h
8 ===================================================================
9 --- tools/clang/include/clang/Analysis/Analyses/FormatString.h
10 +++ tools/clang/include/clang/Analysis/Analyses/FormatString.h
11 @@ -161,6 +161,12 @@ class ConversionSpecifier {
12      ObjCObjArg,  // '@'
13      ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
14  
15 +    // FreeBSD kernel specific specifiers.
16 +    FreeBSDbArg,
17 +    FreeBSDDArg,
18 +    FreeBSDrArg,
19 +    FreeBSDyArg,
20 +
21      // GlibC specific specifiers.
22      PrintErrno,   // 'm'
23  
24 @@ -203,8 +209,8 @@ class ConversionSpecifier {
25    unsigned getLength() const {
26      return EndScanList ? EndScanList - Position : 1;
27    }
28 -
29 -  bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
30 +  bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
31 +    kind == FreeBSDrArg || kind == FreeBSDyArg; }
32    bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
33    bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
34    const char *toString() const;
35 @@ -646,7 +652,7 @@ class FormatStringHandler {
36  
37  bool ParsePrintfString(FormatStringHandler &H,
38                         const char *beg, const char *end, const LangOptions &LO,
39 -                       const TargetInfo &Target);
40 +                       const TargetInfo &Target, bool isFreeBSDKPrintf);
41    
42  bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO,
43                                const TargetInfo &Target);
44 Index: tools/clang/include/clang/Sema/Sema.h
45 ===================================================================
46 --- tools/clang/include/clang/Sema/Sema.h
47 +++ tools/clang/include/clang/Sema/Sema.h
48 @@ -8572,6 +8572,7 @@ class Sema {
49      FST_Strftime,
50      FST_Strfmon,
51      FST_Kprintf,
52 +    FST_FreeBSDKPrintf,
53      FST_Unknown
54    };
55    static FormatStringType GetFormatStringType(const FormatAttr *Format);
56 Index: tools/clang/lib/Analysis/FormatString.cpp
57 ===================================================================
58 --- tools/clang/lib/Analysis/FormatString.cpp
59 +++ tools/clang/lib/Analysis/FormatString.cpp
60 @@ -552,6 +552,12 @@ const char *ConversionSpecifier::toString() const
61    // Objective-C specific specifiers.
62    case ObjCObjArg: return "@";
63  
64 +  // FreeBSD kernel specific specifiers.
65 +  case FreeBSDbArg: return "b";
66 +  case FreeBSDDArg: return "D";
67 +  case FreeBSDrArg: return "r";
68 +  case FreeBSDyArg: return "y";
69 +
70    // GlibC specific specifiers.
71    case PrintErrno: return "m";
72  
73 @@ -647,6 +653,9 @@ bool FormatSpecifier::hasValidLengthModifier(const
74          case ConversionSpecifier::XArg:
75          case ConversionSpecifier::nArg:
76            return true;
77 +        case ConversionSpecifier::FreeBSDrArg:
78 +        case ConversionSpecifier::FreeBSDyArg:
79 +          return Target.getTriple().isOSFreeBSD();
80          default:
81            return false;
82        }
83 @@ -677,6 +686,9 @@ bool FormatSpecifier::hasValidLengthModifier(const
84          case ConversionSpecifier::ScanListArg:
85          case ConversionSpecifier::ZArg:
86            return true;
87 +        case ConversionSpecifier::FreeBSDrArg:
88 +        case ConversionSpecifier::FreeBSDyArg:
89 +          return Target.getTriple().isOSFreeBSD();
90          default:
91            return false;
92        }
93 @@ -807,6 +819,10 @@ bool FormatSpecifier::hasStandardConversionSpecifi
94      case ConversionSpecifier::SArg:
95        return LangOpt.ObjC1 || LangOpt.ObjC2;
96      case ConversionSpecifier::InvalidSpecifier:
97 +    case ConversionSpecifier::FreeBSDbArg:
98 +    case ConversionSpecifier::FreeBSDDArg:
99 +    case ConversionSpecifier::FreeBSDrArg:
100 +    case ConversionSpecifier::FreeBSDyArg:
101      case ConversionSpecifier::PrintErrno:
102      case ConversionSpecifier::DArg:
103      case ConversionSpecifier::OArg:
104 Index: tools/clang/lib/Analysis/PrintfFormatString.cpp
105 ===================================================================
106 --- tools/clang/lib/Analysis/PrintfFormatString.cpp
107 +++ tools/clang/lib/Analysis/PrintfFormatString.cpp
108 @@ -55,7 +55,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(
109                                                    unsigned &argIndex,
110                                                    const LangOptions &LO,
111                                                    const TargetInfo &Target,
112 -                                                  bool Warn) {
113 +                                                  bool Warn,
114 +                                                  bool isFreeBSDKPrintf) {
115  
116    using namespace clang::analyze_format_string;
117    using namespace clang::analyze_printf;
118 @@ -206,9 +207,24 @@ static PrintfSpecifierResult ParsePrintfSpecifier(
119      case '@': k = ConversionSpecifier::ObjCObjArg; break;
120      // Glibc specific.
121      case 'm': k = ConversionSpecifier::PrintErrno; break;
122 +    // FreeBSD kernel specific.
123 +    case 'b':
124 +      if (isFreeBSDKPrintf)
125 +        k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
126 +      break;
127 +    case 'r':
128 +      if (isFreeBSDKPrintf)
129 +        k = ConversionSpecifier::FreeBSDrArg; // int
130 +      break;
131 +    case 'y':
132 +      if (isFreeBSDKPrintf)
133 +        k = ConversionSpecifier::FreeBSDyArg; // int
134 +      break;
135      // Apple-specific.
136      case 'D':
137 -      if (Target.getTriple().isOSDarwin())
138 +      if (isFreeBSDKPrintf)
139 +        k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
140 +      else if (Target.getTriple().isOSDarwin())
141          k = ConversionSpecifier::DArg;
142        break;
143      case 'O':
144 @@ -228,6 +244,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier(
145    FS.setConversionSpecifier(CS);
146    if (CS.consumesDataArgument() && !FS.usesPositionalArg())
147      FS.setArgIndex(argIndex++);
148 +  // FreeBSD kernel specific.
149 +  if (k == ConversionSpecifier::FreeBSDbArg ||
150 +      k == ConversionSpecifier::FreeBSDDArg)
151 +    argIndex++;
152  
153    if (k == ConversionSpecifier::InvalidSpecifier) {
154      // Assume the conversion takes one argument.
155 @@ -240,7 +260,8 @@ bool clang::analyze_format_string::ParsePrintfStri
156                                                       const char *I,
157                                                       const char *E,
158                                                       const LangOptions &LO,
159 -                                                     const TargetInfo &Target) {
160 +                                                     const TargetInfo &Target,
161 +                                                     bool isFreeBSDKPrintf) {
162  
163    unsigned argIndex = 0;
164  
165 @@ -247,7 +268,8 @@ bool clang::analyze_format_string::ParsePrintfStri
166    // Keep looking for a format specifier until we have exhausted the string.
167    while (I != E) {
168      const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
169 -                                                            LO, Target, true);
170 +                                                            LO, Target, true,
171 +                                                            isFreeBSDKPrintf);
172      // Did a fail-stop error of any kind occur when parsing the specifier?
173      // If so, don't do any more processing.
174      if (FSR.shouldStop())
175 @@ -276,7 +298,8 @@ bool clang::analyze_format_string::ParseFormatStri
176    FormatStringHandler H;
177    while (I != E) {
178      const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
179 -                                                            LO, Target, false);
180 +                                                            LO, Target, false,
181 +                                                            false);
182      // Did a fail-stop error of any kind occur when parsing the specifier?
183      // If so, don't do any more processing.
184      if (FSR.shouldStop())
185 @@ -674,6 +697,8 @@ bool PrintfSpecifier::hasValidPlusPrefix() const {
186    case ConversionSpecifier::GArg:
187    case ConversionSpecifier::aArg:
188    case ConversionSpecifier::AArg:
189 +  case ConversionSpecifier::FreeBSDrArg:
190 +  case ConversionSpecifier::FreeBSDyArg:
191      return true;
192  
193    default:
194 @@ -699,6 +724,8 @@ bool PrintfSpecifier::hasValidAlternativeForm() co
195    case ConversionSpecifier::FArg:
196    case ConversionSpecifier::gArg:
197    case ConversionSpecifier::GArg:
198 +  case ConversionSpecifier::FreeBSDrArg:
199 +  case ConversionSpecifier::FreeBSDyArg:
200      return true;
201  
202    default:
203 @@ -729,6 +756,8 @@ bool PrintfSpecifier::hasValidLeadingZeros() const
204    case ConversionSpecifier::FArg:
205    case ConversionSpecifier::gArg:
206    case ConversionSpecifier::GArg:
207 +  case ConversionSpecifier::FreeBSDrArg:
208 +  case ConversionSpecifier::FreeBSDyArg:
209      return true;
210  
211    default:
212 @@ -753,6 +782,8 @@ bool PrintfSpecifier::hasValidSpacePrefix() const
213    case ConversionSpecifier::GArg:
214    case ConversionSpecifier::aArg:
215    case ConversionSpecifier::AArg:
216 +  case ConversionSpecifier::FreeBSDrArg:
217 +  case ConversionSpecifier::FreeBSDyArg:
218      return true;
219  
220    default:
221 @@ -818,6 +849,8 @@ bool PrintfSpecifier::hasValidPrecision() const {
222    case ConversionSpecifier::gArg:
223    case ConversionSpecifier::GArg:
224    case ConversionSpecifier::sArg:
225 +  case ConversionSpecifier::FreeBSDrArg:
226 +  case ConversionSpecifier::FreeBSDyArg:
227      return true;
228  
229    default:
230 Index: tools/clang/lib/Sema/SemaChecking.cpp
231 ===================================================================
232 --- tools/clang/lib/Sema/SemaChecking.cpp
233 +++ tools/clang/lib/Sema/SemaChecking.cpp
234 @@ -2579,6 +2579,7 @@ Sema::FormatStringType Sema::GetFormatStringType(c
235    .Case("strftime", FST_Strftime)
236    .Case("strfmon", FST_Strfmon)
237    .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf)
238 +  .Case("freebsd_kprintf", FST_FreeBSDKPrintf)
239    .Default(FST_Unknown);
240  }
241  
242 @@ -3360,6 +3361,43 @@ CheckPrintfHandler::HandlePrintfSpecifier(const an
243      CoveredArgs.set(argIndex);
244    }
245  
246 +  // FreeBSD kernel extensions.
247 +  if (CS.getKind() == ConversionSpecifier::FreeBSDbArg ||
248 +      CS.getKind() == ConversionSpecifier::FreeBSDDArg) {
249 +    // We need at least two arguments.
250 +    if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex + 1))
251 +      return false;
252 +
253 +    // Claim the second argument.
254 +    CoveredArgs.set(argIndex + 1);
255 +
256 +    // Type check the first argument (int for %b, pointer for %D)
257 +    const Expr *Ex = getDataArg(argIndex);
258 +    const analyze_printf::ArgType &AT =
259 +      (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ?
260 +        ArgType(S.Context.IntTy) : ArgType::CPointerTy;
261 +    if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType()))
262 +      EmitFormatDiagnostic(
263 +        S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
264 +        << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
265 +        << false << Ex->getSourceRange(),
266 +        Ex->getLocStart(), /*IsStringLocation*/false,
267 +        getSpecifierRange(startSpecifier, specifierLen));
268 +
269 +    // Type check the second argument (char * for both %b and %D)
270 +    Ex = getDataArg(argIndex + 1);
271 +    const analyze_printf::ArgType &AT2 = ArgType::CStrTy;
272 +    if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType()))
273 +      EmitFormatDiagnostic(
274 +        S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
275 +        << AT2.getRepresentativeTypeName(S.Context) << Ex->getType()
276 +        << false << Ex->getSourceRange(),
277 +        Ex->getLocStart(), /*IsStringLocation*/false,
278 +        getSpecifierRange(startSpecifier, specifierLen));
279 +
280 +     return true;
281 +  }
282 +
283    // Check for using an Objective-C specific conversion specifier
284    // in a non-ObjC literal.
285    if (!ObjCContext && CS.isObjCArg()) {
286 @@ -3983,7 +4021,8 @@ void Sema::CheckFormatString(const StringLiteral *
287      return;
288    }
289    
290 -  if (Type == FST_Printf || Type == FST_NSString) {
291 +  if (Type == FST_Printf || Type == FST_NSString ||
292 +      Type == FST_FreeBSDKPrintf) {
293      CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
294                           numDataArgs, (Type == FST_NSString),
295                           Str, HasVAListArg, Args, format_idx,
296 @@ -3991,7 +4030,8 @@ void Sema::CheckFormatString(const StringLiteral *
297    
298      if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
299                                                    getLangOpts(),
300 -                                                  Context.getTargetInfo()))
301 +                                                  Context.getTargetInfo(),
302 +                                                  Type == FST_FreeBSDKPrintf))
303        H.DoneProcessing();
304    } else if (Type == FST_Scanf) {
305      CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
306 Index: tools/clang/lib/Sema/SemaDeclAttr.cpp
307 ===================================================================
308 --- tools/clang/lib/Sema/SemaDeclAttr.cpp
309 +++ tools/clang/lib/Sema/SemaDeclAttr.cpp
310 @@ -2481,6 +2481,7 @@ static FormatAttrKind getFormatAttrKind(StringRef
311      .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat)
312      .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
313      .Case("kprintf", SupportedFormat) // OpenBSD.
314 +    .Case("freebsd_kprintf", SupportedFormat) // FreeBSD.
315  
316      .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat)
317      .Default(InvalidFormat);
318 Index: tools/clang/test/Sema/attr-format.c
319 ===================================================================
320 --- tools/clang/test/Sema/attr-format.c
321 +++ tools/clang/test/Sema/attr-format.c
322 @@ -57,8 +57,15 @@ void callnull(void){
323    null(0,  (int*)0); // expected-warning {{incompatible pointer types}}
324  }
325  
326 +// FreeBSD kernel extensions
327 +void a3(const char *a, ...)    __attribute__((format(freebsd_kprintf, 1,2))); // no-error
328 +void b3(const char *a, ...)    __attribute__((format(freebsd_kprintf, 1,1))); // expected-error {{'format' attribute parameter 3 is out of bounds}}
329 +void c3(const char *a, ...)    __attribute__((format(freebsd_kprintf, 0,2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
330 +void d3(const char *a, int c)  __attribute__((format(freebsd_kprintf, 1,2))); // expected-error {{format attribute requires variadic function}}
331 +void e3(char *str, int c, ...) __attribute__((format(freebsd_kprintf, 2,3))); // expected-error {{format argument not a string type}}
332  
333  
334 +
335  // PR4470
336  int xx_vprintf(const char *, va_list);
337  
338 Index: tools/clang/test/Sema/format-strings-freebsd.c
339 ===================================================================
340 --- tools/clang/test/Sema/format-strings-freebsd.c
341 +++ tools/clang/test/Sema/format-strings-freebsd.c
342 @@ -0,0 +1,40 @@
343 +// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-unknown-freebsd %s
344 +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-freebsd %s
345 +
346 +// Test FreeBSD kernel printf extensions.
347 +int freebsd_kernel_printf(const char *, ...) __attribute__((__format__(__freebsd_kprintf__, 1, 2)));
348 +
349 +void check_freebsd_kernel_extensions(int i, long l, char *s)
350 +{
351 +  // %b expects an int and a char *
352 +  freebsd_kernel_printf("reg=%b\n", i, "\10\2BITTWO\1BITONE\n"); // no-warning
353 +  freebsd_kernel_printf("reg=%b\n", l, "\10\2BITTWO\1BITONE\n"); // expected-warning{{format specifies type 'int' but the argument has type 'long'}}
354 +  freebsd_kernel_printf("reg=%b\n", i, l); // expected-warning{{format specifies type 'char *' but the argument has type 'long'}}
355 +  freebsd_kernel_printf("reg=%b\n", i); // expected-warning{{more '%' conversions than data arguments}}
356 +  freebsd_kernel_printf("reg=%b\n", i, "\10\2BITTWO\1BITONE\n", l); // expected-warning{{data argument not used by format string}}
357 +
358 +  // %D expects an unsigned char * and a char *
359 +  freebsd_kernel_printf("%6D", s, ":"); // no-warning
360 +  freebsd_kernel_printf("%6D", i, ":"); // expected-warning{{format specifies type 'void *' but the argument has type 'int'}}
361 +  freebsd_kernel_printf("%6D", s, i); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
362 +  freebsd_kernel_printf("%6D", s); // expected-warning{{more '%' conversions than data arguments}}
363 +  freebsd_kernel_printf("%6D", s, ":", i); // expected-warning{{data argument not used by format string}}
364 +
365 +  freebsd_kernel_printf("%*D", 42, s, ":"); // no-warning
366 +  freebsd_kernel_printf("%*D", 42, i, ":"); // expected-warning{{format specifies type 'void *' but the argument has type 'int'}}
367 +  freebsd_kernel_printf("%*D", 42, s, i); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
368 +  freebsd_kernel_printf("%*D", 42, s); // expected-warning{{more '%' conversions than data arguments}}
369 +  freebsd_kernel_printf("%*D", 42, s, ":", i); // expected-warning{{data argument not used by format string}}
370 +
371 +  // %r expects an int
372 +  freebsd_kernel_printf("%r", i); // no-warning
373 +  freebsd_kernel_printf("%r", l); // expected-warning{{format specifies type 'int' but the argument has type 'long'}}
374 +  freebsd_kernel_printf("%lr", i); // expected-warning{{format specifies type 'long' but the argument has type 'int'}}
375 +  freebsd_kernel_printf("%lr", l); // no-warning
376 +
377 +  // %y expects an int
378 +  freebsd_kernel_printf("%y", i); // no-warning
379 +  freebsd_kernel_printf("%y", l); // expected-warning{{format specifies type 'int' but the argument has type 'long'}}
380 +  freebsd_kernel_printf("%ly", i); // expected-warning{{format specifies type 'long' but the argument has type 'int'}}
381 +  freebsd_kernel_printf("%ly", l); // no-warning
382 +}