| // RUN: %clang_cc1 -fsyntax-only -verify -std=c23 -Wmissing-format-attribute %s |
| // RUN: %clang_cc1 -fsyntax-only -std=c23 -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s |
| |
| typedef unsigned long size_t; |
| typedef long ssize_t; |
| typedef __builtin_va_list va_list; |
| |
| [[gnu::format(printf, 1, 2)]] |
| int printf(const char *, ...); |
| |
| [[gnu::format(scanf, 1, 2)]] |
| int scanf(const char *, ...); |
| |
| [[gnu::format(printf, 1, 0)]] |
| int vprintf(const char *, va_list); |
| |
| [[gnu::format(scanf, 1, 0)]] |
| int vscanf(const char *, va_list); |
| |
| [[gnu::format(printf, 2, 0)]] |
| int vsprintf(char *, const char *, va_list); |
| |
| struct tm { unsigned i; }; |
| [[gnu::format(strftime, 3, 0)]] |
| size_t strftime(char *, size_t, const char *, const struct tm *); |
| |
| [[gnu::format(strfmon, 3, 4)]] |
| ssize_t strfmon(char *, size_t, const char *, ...); |
| |
| [[gnu::format_matches(printf, 1, "%d %f \"'")]] |
| int custom_print(const char *, va_list); |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 0)]] " |
| void f1(const char *fmt, va_list args) // #f1 |
| { |
| vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f1'}} |
| // expected-note@#f1 {{'f1' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 0)]] " |
| void f2(const char *fmt, va_list args) // #f2 |
| { |
| vscanf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 0)' attribute to the declaration of 'f2'}} |
| // expected-note@#f2 {{'f2' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] " |
| void f3(const char *fmt, ... /* args */) // #f3 |
| { |
| va_list args; |
| vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f3'}} |
| // expected-note@#f3 {{'f3' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] " |
| void f4(const char *fmt, ... /* args */) // #f4 |
| { |
| va_list args; |
| vscanf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f4'}} |
| // expected-note@#f4 {{'f4' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(printf, 2, 3)]] " |
| [[gnu::format(printf, 1, 3)]] |
| void f5(char *out, const char *format, ... /* args */) // #f5 |
| { |
| va_list args; |
| vsprintf(out, format, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f5'}} |
| // expected-note@#f5 {{'f5' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(printf, 2, 3)]] " |
| [[gnu::format(scanf, 1, 3)]] |
| void f6(char *out, const char *format, ... /* args */) // #f6 |
| { |
| va_list args; |
| vsprintf(out, format, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f6'}} |
| // expected-note@#f6 {{'f6' declared here}} |
| } |
| |
| // Ok, out is not passed to print functions. |
| void f7(char* out, ... /* args */) |
| { |
| va_list args; |
| |
| const char *ch = "format"; |
| vprintf(ch, args); |
| vprintf("test", args); |
| } |
| |
| // Ok, format string is not passed to format functions. |
| void f8(va_list args) |
| { |
| const char * const ch = "format"; |
| vprintf(ch, args); |
| vprintf("test", args); |
| |
| vscanf(ch, args); |
| vscanf("test", args); |
| |
| char out[10]; |
| |
| struct tm tm_arg; |
| tm_arg.i = 0; |
| strftime(out, sizeof(out), ch, &tm_arg); |
| strftime(out, sizeof(out), "test", &tm_arg); |
| |
| strfmon(out, sizeof(out), ch); |
| strfmon(out, sizeof(out), "test"); |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format_matches(printf, 1, \"%d %f \\\"'\")]] " |
| void f9(const char *fmt, ...) // #f9 |
| { |
| va_list args; |
| custom_print(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format_matches(printf, 1, "%d %f \"'")' attribute to the declaration of 'f9'}} |
| // expected-note@#f9 {{'f9' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] " |
| void f10(const char *out, ... /* args */) // #f10 |
| { |
| va_list args; |
| vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f10'}} |
| // expected-note@#f10 {{'f10' declared here}} |
| vprintf(out, args); // expected-warning {{passing 'scanf' format string where 'printf' format string is expected}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] " |
| void f11(const char out[], ... /* args */) // #f11 |
| { |
| va_list args; |
| char ch[10] = "format"; |
| vprintf(ch, args); |
| vsprintf(ch, out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f11'}} |
| // expected-note@#f11 {{'f11' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 0)]] " |
| void f12(char* out) // #f12 |
| { |
| va_list args; |
| const char *ch = "format"; |
| vsprintf(out, ch, args); |
| vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f12'}} |
| // expected-note@#f12 {{'f12' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 0)]] " |
| void f13(char *out, va_list args) // #f13 |
| { |
| vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f13'}} |
| // expected-note@#f13 {{'f13' declared here}} |
| vscanf(out, args); // expected-warning {{passing 'printf' format string where 'scanf' format string is expected}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] " |
| void f14(char *out, ... /* args */) // #f14 |
| { |
| va_list args; |
| vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f14'}} |
| // expected-note@#f14 {{'f14' declared here}} |
| vscanf(out, args); |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(printf, 1, 3)]] " |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 2, 3)]] " |
| void f15(char *ch, const char *out, ... /* args */) // #f15 |
| { |
| va_list args; |
| vprintf(ch, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of 'f15'}} |
| // expected-note@#f15 {{'f15' declared here}} |
| vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f15'}} |
| // expected-note@#f15 {{'f15' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] " |
| void f16(const char *a, ...) // #f16 |
| { |
| va_list args; |
| const char *const b = a; |
| vprintf(b, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f16'}} |
| // expected-note@#f16 {{'f16' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] " |
| void f17(char *fmt, unsigned x, unsigned y, unsigned z) // #f17 |
| { |
| printf(fmt, x, y, z); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f17'}} |
| // expected-note@#f17 {{'f17' declared here}} |
| } |
| |
| void f18(char *fmt, unsigned x, unsigned y, unsigned z) // #f18 |
| { |
| // Arguments are not passed in the same order. |
| printf(fmt, x, z, y); |
| } |
| |
| void f19(char *out, ... /* args */) |
| { |
| printf(out, 1); // No warning, arguments are not passed to printf. |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(strftime, 3, 0)]] " |
| void f20(char *out, const size_t len, const char *format) // #f20 |
| { |
| struct tm tm_arg; |
| tm_arg.i = 0; |
| strftime(out, len, format, &tm_arg); // expected-warning {{diagnostic behavior may be improved by adding the 'format(strftime, 3, 0)' attribute to the declaration of 'f20'}} |
| // expected-note@#f20 {{'f20' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(strfmon, 3, 4)]] " |
| void f21(char *out, const size_t len, const char *format, int x, int y) // #f21 |
| { |
| strfmon(out, len, format, x, y); // expected-warning {{diagnostic behavior may be improved by adding the 'format(strfmon, 3, 4)' attribute to the declaration of 'f21'}} |
| // expected-note@#f21 {{'f21' declared here}} |
| } |
| |
| // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] " |
| void f22(const char *fmt, ... /* args */); // #f22 |
| |
| void f22(const char *fmt, ... /* args */) |
| { |
| va_list args; |
| vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f22'}} |
| // expected-note@#f22 {{'f22' declared here}} |
| } |