brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.2 KiB · 9a6e591 Raw
274 lines · c
1// RUN: %clang_cc1 -verify -fblocks -fsyntax-only -Wformat-nonliteral -Wformat-signedness -isystem %S/Inputs %s2// RUN: %clang_cc1 -verify -fblocks -fsyntax-only -Wformat-nonliteral -Wformat-signedness -isystem %S/Inputs -fno-signed-char %s3 4#include <stdarg.h>5 6__attribute__((format_matches(printf, -1, "%s"))) // expected-error{{'format_matches' attribute parameter 2 is out of bounds}}7int test_out_of_bounds(void);8 9__attribute__((format_matches(printf, 0, "%s"))) // expected-error{{'format_matches' attribute parameter 2 is out of bounds}}10int test_out_of_bounds(void);11 12__attribute__((format_matches(printf, 1, "%s"))) // expected-error{{'format_matches' attribute parameter 2 is out of bounds}}13int test_out_of_bounds(void);14 15__attribute__((format_matches(printf, 1, "%s"))) // expected-error{{format argument not a string type}}16int test_out_of_bounds_int(int x);17 18// MARK: -19// Calling printf with a format from format_matches(printf) diagnoses with20// that format string21__attribute__((format(printf, 1, 2)))22int printf(const char *fmt, ...);23 24__attribute__((format(printf, 1, 0)))25int vprintf(const char *fmt, va_list);26 27__attribute__((format_matches(printf, 1, "%s %1.5s")))28void format_str_str0(const char *fmt) {29    printf(fmt, "hello", "world");30}31 32__attribute__((format_matches(printf, 1, "%s" "%1.5s")))33void format_str_str1(const char *fmt) {34    printf(fmt, "hello", "world");35}36 37__attribute__((format_matches(printf, 1, ("%s" "%1.5s") + 5))) // expected-error{{format string is not a string literal}}38void format_str_str2(const char *fmt);39 40__attribute__((format_matches(printf, 1, "%s %g"))) // expected-note{{format string is defined here}}41void format_str_double_warn(const char *fmt) {42    printf(fmt, "hello", "world"); // expected-warning{{format specifies type 'double' but the argument has type 'char *'}}43}44 45__attribute__((format_matches(printf, 1, "%s %g")))46void vformat(const char *fmt, ...) {47    va_list ap;48    va_start(ap, fmt);49    vprintf(fmt, ap); // XXX: ideally this would be a diagnostic50    va_end(ap);51}52 53// MARK: -54// Calling a function with format_matches diagnoses for incompatible formats.55 56void cvt_percent(const char *c) __attribute__((format_matches(printf, 1, "%%"))); // expected-note 2{{comparing with this format string}}57void cvt_at(const char *c) __attribute__((format_matches(NSString, 1, "%@")));  // \58    expected-note{{comparing with this specifier}} \59    expected-note 3{{comparing with this format string}}60void cvt_c(const char *c) __attribute__((format_matches(printf, 1, "%c"))); // expected-note{{comparing with this specifier}}61void cvt_u(const char *c) __attribute__((format_matches(printf, 1, "%u"))); // expected-note 2{{comparing with this specifier}}62void cvt_hhi(const char *c) __attribute__((format_matches(printf, 1, "%hhi")));  // expected-note 3{{comparing with this specifier}}63void cvt_i(const char *c) __attribute__((format_matches(printf, 1, "%i"))); // expected-note 5{{comparing with this specifier}}64void cvt_p(const char *c) __attribute__((format_matches(printf, 1, "%p")));65void cvt_s(const char *c) __attribute__((format_matches(printf, 1, "%s"))); // expected-note{{comparing with this specifier}}66void cvt_n(const char *c) __attribute__((format_matches(printf, 1, "%n"))); // expected-note{{comparing with this specifier}}67 68void test_compatibility(void) {69    cvt_c("%i");70    const char *const fmt_i = "%i";71    cvt_c(fmt_i);72 73    cvt_i("%c");74    cvt_c("%u"); // expected-warning{{signedness of format specifier 'u' is incompatible with 'c'}}75    cvt_u("%c"); // expected-warning{{signedness of format specifier 'c' is incompatible with 'u'}}76 77    const char *const fmt_c = "%c"; // expected-note{{format string is defined here}}78    cvt_u(fmt_c); // expected-warning{{signedness of format specifier 'c' is incompatible with 'u'}}79 80    cvt_i("%hi"); // expected-warning{{format specifier 'hi' is incompatible with 'i'}}81    cvt_i("%hhi"); // expected-warning{{format specifier 'hhi' is incompatible with 'i'}}82    cvt_i("%lli"); // expected-warning{{format specifier 'lli' is incompatible with 'i'}}83    cvt_i("%p"); // expected-warning{{format specifier 'p' is incompatible with 'i'}}84    cvt_hhi("%hhi");85    cvt_hhi("%hi"); // expected-warning{{format specifier 'hi' is incompatible with 'hhi'}} 86    cvt_hhi("%i"); // expected-warning{{format specifier 'i' is incompatible with 'hhi'}} 87    cvt_hhi("%li"); // expected-warning{{format specifier 'li' is incompatible with 'hhi'}} 88    cvt_n("%s"); // expected-warning{{format specifier 's' is incompatible with 'n'}}89    cvt_s("%hhn"); // expected-warning{{format specifier 'hhn' is incompatible with 's'}}90    91    cvt_p("%@"); // expected-warning{{invalid conversion specifier '@'}}92    cvt_at("%p"); // expected-warning{{format specifier 'p' is incompatible with '@'}}93 94    cvt_percent("hello");95    cvt_percent("%c"); // expected-warning{{more specifiers in format string than expected}}96 97    const char *const too_many = "%c"; // expected-note{{format string is defined here}}98    cvt_percent(too_many); // expected-warning{{more specifiers in format string than expected}}99}100 101void test_too_few_args(void) {102    cvt_at("a"); // expected-warning{{fewer specifiers in format string than expected}}103    cvt_at("%@ %@"); // expected-warning{{more specifiers in format string than expected}}104 105    const char *const too_few = "a"; // expected-note{{format string is defined here}}106    cvt_at(too_few); // expected-warning{{fewer specifiers in format string than expected}}107}108 109void cvt_several(const char *c) __attribute__((format_matches(printf, 1, "%f %i %s"))); // expected-note{{comparing with this specifier}}110 111void test_moving_args_around(void) {112    cvt_several("%1g %-d %1.5s"); 113 114    cvt_several("%3$s %1$g %2$i");115 116    cvt_several("%f %*s"); // expected-warning{{format argument is an indirect field width, but it should be a value}}117}118 119void cvt_freebsd_D(const char *c) __attribute__((format_matches(freebsd_kprintf, 1, "%D"))); // expected-note{{comparing with this specifier}}120 121void test_freebsd_specifiers(void) {122    cvt_freebsd_D("%D");123    cvt_freebsd_D("%b");124    cvt_freebsd_D("%s %i"); // expected-warning{{format argument is a value, but it should be an auxiliary value}}125}126 127// passing the wrong kind of string literal128void takes_printf_string(const char *fmt) __attribute__((format_matches(printf, 1, "%s")));129__attribute__((format_matches(freebsd_kprintf, 1, "%s"))) // expected-note{{format string is defined here}}130void takes_freebsd_kprintf_string(const char *fmt) {131    takes_printf_string(fmt); // expected-warning{{passing 'freebsd_kprintf' format string where 'printf' format string is expected}}132 133    const char *const fmt2 = fmt;134    takes_printf_string(fmt2); // expected-warning{{passing 'freebsd_kprintf' format string where 'printf' format string is expected}}135}136 137__attribute__((format_matches(printf, 1, "%s"))) // expected-note{{comparing with this specifier}}138__attribute__((format_matches(os_log, 2, "%i"))) // expected-note{{comparing with this specifier}}139void test_recv_multiple_format_strings(const char *fmt1, const char *fmt2);140 141__attribute__((format_matches(printf, 1, "%s")))142__attribute__((format_matches(os_log, 2, "%i")))143void test_multiple_format_strings(const char *fmt1, const char *fmt2) {144    test_recv_multiple_format_strings("%s", "%i");145    test_recv_multiple_format_strings("%s", "%s"); // expected-warning{{format specifier 's' is incompatible with 'i'}}146    test_recv_multiple_format_strings("%i", "%i"); // expected-warning{{format specifier 'i' is incompatible with 's'}}147 148    test_recv_multiple_format_strings(fmt1, fmt2);149    test_recv_multiple_format_strings("%.5s", fmt2);150    test_recv_multiple_format_strings(fmt1, "%04d");151    152    test_recv_multiple_format_strings("%s", fmt1); // expected-warning{{passing 'printf' format string where 'os_log' format string is expected}}153    test_recv_multiple_format_strings(fmt2, "%d"); // expected-warning{{passing 'os_log' format string where 'printf' format string is expected}}154 155    test_recv_multiple_format_strings(fmt2, fmt1); // \156        expected-warning{{passing 'printf' format string where 'os_log' format string is expected}} \157        expected-warning{{passing 'os_log' format string where 'printf' format string is expected}}158}159 160__attribute__((format_matches(os_log, 1, "%{public}s"))) // expected-note 4{{comparing with this specifier}}161void call_oslog_public(const char *fmt);162 163__attribute__((format_matches(os_log, 1, "%{sensitive}s"))) // expected-note 2{{comparing with this specifier}}164void call_oslog_sensitive(const char *fmt);165 166__attribute__((format_matches(os_log, 1, "%{private}s"))) // expected-note 2{{comparing with this specifier}}167void call_oslog_private(const char *fmt);168 169void test_oslog(void) {170    call_oslog_public("%{public}s");171    call_oslog_public("%{private}s"); // expected-warning{{argument sensitivity is private, but it should be public}}172    call_oslog_public("%{sensitive}s"); // expected-warning{{argument sensitivity is sensitive, but it should be public}}173 174    call_oslog_sensitive("%{public}s"); // expected-warning{{argument sensitivity is public, but it should be sensitive}}175    call_oslog_sensitive("%{private}s"); // expected-warning{{argument sensitivity is private, but it should be sensitive}}176    call_oslog_sensitive("%{sensitive}s");177 178    call_oslog_private("%{public}s"); // expected-warning{{argument sensitivity is public, but it should be private}}179    call_oslog_private("%{private}s");180    call_oslog_private("%{sensitive}s"); // expected-warning{{argument sensitivity is sensitive, but it should be private}}181 182    // expected-warning@+2{{argument sensitivity is private, but it should be public}}183    // expected-warning@+1{{format specifier 'i' is incompatible with 's'}}184    call_oslog_public("%{private}i");185}186 187// MARK: - 188void accept_value(const char *f) __attribute__((format_matches(freebsd_kprintf, 1, "%s%i%i"))); // \189    expected-note 3{{comparing with this specifier}} \190    expected-note 3{{format string is defined here}}191void accept_indirect_field_width(const char *f) __attribute__((format_matches(freebsd_kprintf, 1, "%s%*i"))); // \192    expected-note 3{{comparing with this specifier}} \193    expected-note 3{{format string is defined here}}194void accept_indirect_field_precision(const char *f) __attribute__((format_matches(freebsd_kprintf, 1, "%s%.*i"))); // \195    expected-note 3{{comparing with this specifier}} \196    expected-note 3{{format string is defined here}}197void accept_aux_value(const char *f) __attribute__((format_matches(freebsd_kprintf, 1, "%D%i"))); // \198    expected-note 3{{comparing with this specifier}} \199    expected-note 3{{format string is defined here}}200 201void accept_value(const char *f) {202    accept_indirect_field_width(f); // expected-warning{{format argument is a value, but it should be an indirect field width}}203    accept_indirect_field_precision(f); // expected-warning{{format argument is a value, but it should be an indirect precision}}204    accept_aux_value(f); // expected-warning{{format argument is a value, but it should be an auxiliary value}}205}206 207void accept_indirect_field_width(const char *f) {208    accept_value(f); // expected-warning{{format argument is an indirect field width, but it should be a value}}209    accept_indirect_field_precision(f); // expected-warning{{format argument is an indirect field width, but it should be an indirect precision}}210    accept_aux_value(f); // expected-warning{{format argument is an indirect field width, but it should be an auxiliary value}}211}212 213void accept_indirect_field_precision(const char *f) {214    accept_value(f); // expected-warning{{format argument is an indirect precision, but it should be a value}}215    accept_indirect_field_width(f); // expected-warning{{format argument is an indirect precision, but it should be an indirect field width}}216    accept_aux_value(f); // expected-warning{{format argument is an indirect precision, but it should be an auxiliary value}}217}218 219void accept_aux_value(const char *f) {220    accept_value(f); // expected-warning{{format argument is an auxiliary value, but it should be a value}}221    accept_indirect_field_width(f); // expected-warning{{format argument is an auxiliary value, but it should be an indirect field width}}222    accept_indirect_field_precision(f); // expected-warning{{format argument is an auxiliary value, but it should be an indirect precision}}223}224 225// MARK: - Merging format attributes226__attribute__((format_matches(printf, 1, "%i")))227__attribute__((format_matches(printf, 1, "%d")))228void test_merge_self(const char *f);229 230__attribute__((format_matches(printf, 1, "%i"))) // expected-note{{comparing with this specifier}}231__attribute__((format_matches(printf, 1, "%s"))) // expected-warning{{format specifier 's' is incompatible with 'i'}}232void test_merge_self_warn(const char *f);233 234__attribute__((format_matches(printf, 1, "%i")))235void test_merge_redecl(const char *f);236 237__attribute__((format_matches(printf, 1, "%d")))238void test_merge_redecl(const char *f);239 240// XXX: ideally the warning and note would be swapped, but this is entirely241// reliant on which decl clang considers to be the "true one", and it might242// upset something else more important if we tried to change it.243__attribute__((format_matches(printf, 1, "%i"))) // expected-warning{{format specifier 'i' is incompatible with 's'}}244void test_merge_redecl_warn(const char *f);245 246__attribute__((format_matches(printf, 1, "%s"))) // expected-note{{comparing with this specifier}}247void test_merge_redecl_warn(const char *f);248 249// MARK: -250// Positional madness251 252__attribute__((format_matches(printf, 1, "%1$s %1$d")))  // \253    expected-warning{{format specifier 'd' is incompatible with 's'}} \254    expected-note{{comparing with this specifier}}255void test_positional_incompatible(const char *f);256 257void call_positional_incompatible(void) {258    // expect the attribute was dropped and that there is no diagnostic here259    test_positional_incompatible("%d %d %d %d %d");260}261 262void test_many_i(void) {263    cvt_i("%1$d %1$i");264    cvt_i("%1$d %1$s"); // expected-warning{{format specifier 's' is incompatible with 'i'}}265}266 267__attribute__((format_matches(printf, 1, "%*d %*d"))) // expected-note{{comparing with this specifier}}268void accept_modifiers(const char *f);269 270void test_modifiers(void) {271    accept_modifiers("%2$*1$d %4$*3$d");272    accept_modifiers("%2$*3$d %4$*3$d"); // expected-warning{{format argument modifies specifier at position 2, but it should modify specifier at position 4}}273}274