xref: /llvm-project/clang/test/Sema/attr-diagnose-as-builtin.c (revision e765e0bc8ed06ebb186a9905227273517f0b7240)
1 // RUN: %clang_cc1 -Wfortify-source -triple x86_64-apple-macosx10.14.0 %s -verify
2 // RUN: %clang_cc1 -Wfortify-source -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify
3 
4 typedef unsigned long size_t;
5 
6 __attribute__((diagnose_as_builtin(__builtin_memcpy, 3, 1, 2))) int x; // expected-warning {{'diagnose_as_builtin' attribute only applies to functions}}
7 
test_memcpy(const void * src,size_t c,void * dst)8 void *test_memcpy(const void *src, size_t c, void *dst) __attribute__((diagnose_as_builtin(__builtin_memcpy, 3, 1, 2))) {
9   return __builtin_memcpy(dst, src, c);
10 }
11 
call_test_memcpy(void)12 void call_test_memcpy(void) {
13   char bufferA[10];
14   char bufferB[11];
15   test_memcpy(bufferB, 10, bufferA);
16   test_memcpy(bufferB, 11, bufferA); // expected-warning {{'memcpy' will always overflow; destination buffer has size 10, but size argument is 11}}
17 }
18 
failure_function_doesnt_exist(void)19 void failure_function_doesnt_exist(void) __attribute__((diagnose_as_builtin(__function_that_doesnt_exist))) {} // expected-error {{use of undeclared identifier '__function_that_doesnt_exist'}}
20 
not_a_builtin(void)21 void not_a_builtin(void) {}
22 
failure_not_a_builtin(void)23 void failure_not_a_builtin(void) __attribute__((diagnose_as_builtin(not_a_builtin))) {} // expected-error {{'diagnose_as_builtin' attribute requires parameter 1 to be a builtin function}}
24 
failure_too_many_parameters(void * dst,const void * src,size_t count,size_t nothing)25 void failure_too_many_parameters(void *dst, const void *src, size_t count, size_t nothing) __attribute__((diagnose_as_builtin(__builtin_memcpy, 1, 2, 3, 4))) {} // expected-error {{'diagnose_as_builtin' attribute references function '__builtin_memcpy', which takes exactly 3 arguments}}
26 
failure_too_few_parameters(void * dst,const void * src)27 void failure_too_few_parameters(void *dst, const void *src) __attribute__((diagnose_as_builtin(__builtin_memcpy, 1, 2))) {} // expected-error{{'diagnose_as_builtin' attribute references function '__builtin_memcpy', which takes exactly 3 arguments}}
28 
failure_not_an_integer(void * dst,const void * src,size_t count)29 void failure_not_an_integer(void *dst, const void *src, size_t count) __attribute__((diagnose_as_builtin(__builtin_memcpy, "abc", 2, 3))) {} // expected-error{{'diagnose_as_builtin' attribute requires parameter 2 to be an integer constant}}
30 
failure_not_a_builtin2(void)31 void failure_not_a_builtin2(void) __attribute__((diagnose_as_builtin("abc"))) {} // expected-error{{'diagnose_as_builtin' attribute requires parameter 1 to be a builtin function}}
32 
failure_parameter_index_bounds(void * dst,const void * src)33 void failure_parameter_index_bounds(void *dst, const void *src) __attribute__((diagnose_as_builtin(__builtin_memcpy, 1, 2, 3))) {} // expected-error{{'diagnose_as_builtin' attribute references parameter 3, but the function 'failure_parameter_index_bounds' has only 2 parameters}}
34 
failure_parameter_types(double dst,const void * src,size_t count)35 void failure_parameter_types(double dst, const void *src, size_t count) __attribute__((diagnose_as_builtin(__builtin_memcpy, 1, 2, 3))) {} // expected-error{{'diagnose_as_builtin' attribute parameter types do not match: parameter 1 of function 'failure_parameter_types' has type 'double', but parameter 1 of function '__builtin_memcpy' has type 'void *'}}
36 
37 void to_redeclare(void *dst, const void *src, size_t count);
38 
use_to_redeclare(void)39 void use_to_redeclare(void) {
40   char src[10];
41   char dst[9];
42   // We shouldn't get an error yet.
43   to_redeclare(dst, src, 10);
44 }
45 
46 void to_redeclare(void *dst, const void *src, size_t count) __attribute((diagnose_as_builtin(__builtin_memcpy, 1, 2, 3)));
47 
error_to_redeclare(void)48 void error_to_redeclare(void) {
49   char src[10];
50   char dst[9];
51   // Now we get an error.
52   to_redeclare(dst, src, 10); // expected-warning {{'memcpy' will always overflow; destination buffer has size 9, but size argument is 10}}
53 }
54 
55 // Make sure this works even with extra qualifiers and the pass_object_size attribute.
56 void *memcpy2(void *const dst __attribute__((pass_object_size(0))), const void *src, size_t copy_amount) __attribute((diagnose_as_builtin(__builtin_memcpy, 1, 2, 3)));
57 
call_memcpy2(void)58 void call_memcpy2(void) {
59   char buf1[10];
60   char buf2[11];
61   memcpy2(buf1, buf2, 11); // expected-warning {{'memcpy' will always overflow; destination buffer has size 10, but size argument is 11}}
62 }
63 
64 // We require the types to be identical, modulo canonicalization and qualifiers.
65 // Maybe this could be relaxed if it proves too restrictive.
failure_type(void * dest,char val,size_t n)66 void failure_type(void *dest, char val, size_t n) __attribute__((diagnose_as_builtin(__builtin_memset, 1, 2, 3))) {} // expected-error {{'diagnose_as_builtin' attribute parameter types do not match: parameter 2 of function 'failure_type' has type 'char', but parameter 2 of function '__builtin_memset' has type 'int'}}
67 
68 #ifdef __cplusplus
69 extern "C" {
70 #endif
71 
72 extern int sscanf(const char *input, const char *format, ...);
73 
74 #ifdef __cplusplus
75 }
76 #endif
77 
78 // Variadics should work.
79 int mysscanf(const char *str, const char *format, ...) __attribute__((diagnose_as_builtin(sscanf, 1, 2)));
80 
warn_mysccanf(void)81 void warn_mysccanf(void) {
82   char buf[10];
83   mysscanf("", "%10s", buf); // expected-warning{{'sscanf' may overflow; destination buffer in argument 3 has size 10, but the corresponding specifier may require size 11}}
84 }
85 
86 #ifdef __cplusplus
87 
88 template <class T>
some_templated_function(int x)89 void some_templated_function(int x) {
90   return;
91 }
92 
failure_template(int x)93 void failure_template(int x) __attribute__((diagnose_as_builtin(some_templated_function, 1))) {} // expected-error{{'diagnose_as_builtin' attribute requires parameter 1 to be a builtin function}}
94 
failure_template_instantiation(int x)95 void failure_template_instantiation(int x) __attribute__((diagnose_as_builtin(some_templated_function<int>, 1))) {} // expected-error{{'diagnose_as_builtin' attribute requires parameter 1 to be a builtin function}}
96 
97 void overloaded_function(unsigned);
98 
99 void overloaded_function(int);
100 
failure_overloaded_function(int)101 void failure_overloaded_function(int) __attribute__((diagnose_as_builtin(overloaded_function, 1))) {} // expected-error{{'diagnose_as_builtin' attribute requires parameter 1 to be a builtin function}}
102 
103 struct S {
104   __attribute__((diagnose_as_builtin(__builtin_memset))) void f(); // expected-error{{'diagnose_as_builtin' attribute cannot be applied to non-static member functions}}
105 
test_memcpyS106   __attribute__((diagnose_as_builtin(__builtin_memcpy, 3, 1, 2))) static void *test_memcpy(const void *src, size_t c, void *dst) {
107     return __builtin_memcpy(dst, src, c);
108   }
109 };
110 
call_static_test_memcpy(void)111 void call_static_test_memcpy(void) {
112   char bufferA[10];
113   char bufferB[11];
114   S::test_memcpy(bufferB, 10, bufferA);
115   S::test_memcpy(bufferB, 11, bufferA); // expected-warning {{'memcpy' will always overflow; destination buffer has size 10, but size argument is 11}}
116 }
117 
118 #endif
119