241 lines · cpp
1// RUN: %clang_cc1 -Wall -Wno-unused -Wno-uninitialized -std=c++2b -verify %s2 3#define CFI_UNCHECKED_CALLEE __attribute__((cfi_unchecked_callee))4 5void unchecked(void) CFI_UNCHECKED_CALLEE {}6void checked(void) {}7 8void (*checked_ptr)(void) = unchecked; // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}9void (CFI_UNCHECKED_CALLEE *unchecked_ptr)(void) = unchecked;10void (CFI_UNCHECKED_CALLEE *from_normal)(void) = checked;11void (CFI_UNCHECKED_CALLEE *c_no_function_decay)(void) = &unchecked;12void (CFI_UNCHECKED_CALLEE __attribute__((noreturn)) *other_conflict)(void) = &checked; // expected-error{{cannot initialize a variable of type 'void (*)() __attribute__((noreturn)) __attribute__((cfi_unchecked_callee))' with an rvalue of type 'void (*)()'}}13void (CFI_UNCHECKED_CALLEE *arr[10])(void);14void (*cfi_elem)(void) = arr[1]; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}15void (CFI_UNCHECKED_CALLEE *cfi_unchecked_elem)(void) = arr[1];16void (CFI_UNCHECKED_CALLEE &ref)(void) = unchecked;17void (CFI_UNCHECKED_CALLEE &ref2)(void) = *unchecked;18void (&ref_cfi_checked)(void) = unchecked; // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void ()' discards 'cfi_unchecked_callee' attribute}}19void (&ref_cfi_checked2)(void) = *unchecked; // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void ()' discards 'cfi_unchecked_callee' attribute}}20 21void (CFI_UNCHECKED_CALLEE *unchecked_from_deref)(void) = &*unchecked;22void (*checked_from_deref)(void) = &*unchecked; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}23 24typedef void (CFI_UNCHECKED_CALLEE unchecked_func_t)(void);25typedef void (checked_func_t)(void);26typedef void (CFI_UNCHECKED_CALLEE *unchecked_func_ptr_t)(void);27typedef void (*checked_func_ptr_t)(void);28checked_func_t *checked_func = unchecked; // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}29unchecked_func_t *unchecked_func = unchecked;30 31void CFI_UNCHECKED_CALLEE before_func(void);32CFI_UNCHECKED_CALLEE void before_return_type(void);33void (* CFI_UNCHECKED_CALLEE after_name)(void);34 35void UsageOnImproperTypes() {36 int CFI_UNCHECKED_CALLEE i; // expected-warning{{'cfi_unchecked_callee' only applies to function types; type here is 'int'}}37}38 39/// Explicit casts suppress the warning.40void CheckCasts() {41 void (*should_warn)(void) = unchecked; // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}42 43 void (*no_warn_c_style_cast)(void) = (void (*)(void))unchecked;44 void (*no_warn_static_cast)(void) = static_cast<void (*)(void)>(unchecked);45 void (*no_warn_reinterpret_cast)(void) = reinterpret_cast<void (*)(void)>(unchecked);46 unsigned long long ull = (unsigned long long)unchecked;47 48 struct A {};49 void (CFI_UNCHECKED_CALLEE A::*cfi_unchecked_member_ptr)(void);50 void (A::*member_ptr)(void) = cfi_unchecked_member_ptr; // expected-warning{{implicit conversion from 'void (A::*)() __attribute__((cfi_unchecked_callee))' to 'void (A::*)()' discards 'cfi_unchecked_callee' attribute}}51 52 struct B {} CFI_UNCHECKED_CALLEE b; // expected-warning{{'cfi_unchecked_callee' attribute only applies to functions and methods}}53 struct CFI_UNCHECKED_CALLEE C {} c; // expected-warning{{'cfi_unchecked_callee' attribute only applies to functions and methods}}54 CFI_UNCHECKED_CALLEE struct D {} d; // expected-warning{{'cfi_unchecked_callee' only applies to function types; type here is 'struct D'}}55 56 void *ptr2 = (void *)unchecked;57}58 59void CheckDifferentConstructions() {60 checked_func_t *checked_func(unchecked_func); // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}61 new (checked_func_t *)(unchecked_func); // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}62 struct S {63 checked_func_t *checked_func;64 65 S(unchecked_func_t *unchecked_func) : checked_func(unchecked_func) {} // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}66 };67 68 checked_func_t *checked_func2{unchecked_func}; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}69 checked_ptr = checked_func_ptr_t(unchecked);70 71 auto checked_auto = checked;72 auto unchecked_auto = unchecked;73 unchecked_ptr = checked_auto;74 unchecked_ptr = unchecked_auto;75 checked_ptr = checked_auto;76 checked_ptr = unchecked_auto; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}77}78 79checked_func_t *returning_checked_func() {80 return unchecked; // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}81}82 83int checked_arg_func(checked_func_t *checked_func);84int invoke = checked_arg_func(unchecked); // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}85 86template <typename T>87struct S {88 S(T *ptr) {}89};90S<unchecked_func_t> s(checked);91S<unchecked_func_t> s2(unchecked);92S<checked_func_t> s3(checked);93S<checked_func_t> s4(unchecked); // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}94S s5(checked);95S s6(unchecked);96 97template <typename T, typename U>98struct is_same {99 static constexpr bool value = false;100};101template <typename T>102struct is_same<T,T> {103 static constexpr bool value = true;104};105 106template <typename T>107struct ExpectingCFIUncheckedCallee {108 static_assert(is_same<T, unchecked_func_t>::value);109 ExpectingCFIUncheckedCallee(T *) {}110 ExpectingCFIUncheckedCallee() = default;111};112ExpectingCFIUncheckedCallee<unchecked_func_t> expecting;113ExpectingCFIUncheckedCallee expecting2(unchecked);114 115void no_args() __attribute__((cfi_unchecked_callee(10))); // expected-error{{'cfi_unchecked_callee' attribute takes no arguments}}116 117void bracket_cfi_unchecked(void) [[clang::cfi_unchecked_callee]] {}118 119void BracketNotation() {120 checked_ptr = bracket_cfi_unchecked; // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}121}122 123void Comparisons() {124 /// Let's be able to compare checked and unchecked pointers without warnings.125 unchecked == checked_ptr;126 checked_ptr == unchecked;127 unchecked == unchecked_ptr;128 unchecked != checked_ptr;129 checked_ptr != unchecked;130 unchecked != unchecked_ptr;131 132 (void (*)(void))unchecked == checked_ptr;133 checked_ptr == (void (*)(void))unchecked;134 135 struct S {136 typedef void CB() CFI_UNCHECKED_CALLEE;137 constexpr bool operator==(const S &other) const {138 return cb == other.cb;139 }140 CB *cb;141 };142}143 144/// Type aliasing145typedef void (BaseType)(void);146using WithoutAttr = BaseType;147using WithAttr = __attribute__((cfi_unchecked_callee)) BaseType;148 149WithoutAttr *checked_func_alias = unchecked; // expected-warning{{implicit conversion from 'void () __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}150WithAttr *unchecked_func_allias = unchecked;151WithoutAttr *checked_func_alias2 = checked;152WithAttr *unchecked_func_alias2 = checked;153 154using MyType = WithAttr; // expected-note{{previous definition is here}}155using MyType = WithoutAttr; // expected-error{{type alias redefinition with different types ('WithoutAttr' (aka 'void ()') vs 'WithAttr' (aka 'void () __attribute__((cfi_unchecked_callee))'))}}156 157void MemberFunctionPointer() {158 struct A {159 void unchecked() CFI_UNCHECKED_CALLEE {}160 virtual void unchecked_virtual() CFI_UNCHECKED_CALLEE {}161 static void unchecked_static() CFI_UNCHECKED_CALLEE {}162 void unchecked_explicit_this(this A&) CFI_UNCHECKED_CALLEE {}163 int operator+=(int i) CFI_UNCHECKED_CALLEE { return i; }164 165 void checked() {}166 virtual void checked_virtual() {}167 static void checked_static() {}168 void checked_explicit_this(this A&) {}169 int operator-=(int i) { return i; }170 };171 172 void (CFI_UNCHECKED_CALLEE A::*unchecked)() = &A::unchecked;173 unchecked = &A::unchecked_virtual;174 void (CFI_UNCHECKED_CALLEE *unchecked_explicit_this)(A&) = &A::unchecked_explicit_this;175 void (CFI_UNCHECKED_CALLEE *unchecked_static)() = &A::unchecked_static;176 int (CFI_UNCHECKED_CALLEE A::*unchecked_overloaded)(int) = &A::operator+=;177 178 void (A::*checked)() = &A::unchecked; // expected-warning{{implicit conversion from 'void (A::*)() __attribute__((cfi_unchecked_callee))' to 'void (A::*)()' discards 'cfi_unchecked_callee' attribute}}179 checked = &A::unchecked_virtual; // expected-warning{{implicit conversion from 'void (A::*)() __attribute__((cfi_unchecked_callee))' to 'void (A::*)()' discards 'cfi_unchecked_callee' attribute}}180 void (*checked_explicit_this)(A&) = &A::unchecked_explicit_this; // expected-warning{{implicit conversion from 'void (*)(A &) __attribute__((cfi_unchecked_callee))' to 'void (*)(A &)' discards 'cfi_unchecked_callee' attribute}}181 void (*checked_static)() = &A::unchecked_static; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}182 int (A::*checked_overloaded)(int) = &A::operator+=; // expected-warning{{implicit conversion from 'int (A::*)(int) __attribute__((cfi_unchecked_callee))' to 'int (A::*)(int)' discards 'cfi_unchecked_callee' attribute}}183 184 unchecked = &A::checked;185 unchecked = &A::checked_virtual;186 unchecked_explicit_this = &A::checked_explicit_this;187 unchecked_static = &A::checked_static;188 unchecked_overloaded = &A::operator-=;189 190 checked = &A::checked;191 checked = &A::checked_virtual;192 checked_explicit_this = &A::checked_explicit_this;193 checked_static = &A::checked_static;194 checked_overloaded = &A::operator-=;195 196 typedef void (CFI_UNCHECKED_CALLEE A::*WithAttr)();197 typedef void (CFI_UNCHECKED_CALLEE A::*WithoutAttr)();198 using WithoutAttr = decltype(unchecked);199}200 201void lambdas() {202 auto unchecked_lambda = [](void) CFI_UNCHECKED_CALLEE -> void {};203 auto checked_lambda = [](void) -> void {};204 void (CFI_UNCHECKED_CALLEE *unchecked_func)(void) = unchecked_lambda;205 unchecked_func = checked_lambda;206 void (*checked_func)(void) = unchecked_lambda; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}207 checked_func = checked_lambda;208 209 auto capture_by_value = [unchecked_lambda, checked_lambda]() {210 void (CFI_UNCHECKED_CALLEE *unchecked_func)(void) = unchecked_lambda;211 unchecked_func = checked_lambda;212 void (*checked_func)(void) = unchecked_lambda; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}213 checked_func = checked_lambda;214 };215 216 auto capture_by_ref = [&unchecked_lambda, &checked_lambda]() {217 void (CFI_UNCHECKED_CALLEE *unchecked_func)(void) = unchecked_lambda;218 unchecked_func = checked_lambda;219 void (*checked_func)(void) = unchecked_lambda; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}220 checked_func = checked_lambda;221 };222 223 auto capture_all_by_value = [=]() {224 void (CFI_UNCHECKED_CALLEE *unchecked_func)(void) = unchecked_lambda;225 unchecked_func = checked_lambda;226 void (*checked_func)(void) = unchecked_lambda; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}227 checked_func = checked_lambda;228 };229 230 auto capture_all_by_ref = [&]() {231 void (CFI_UNCHECKED_CALLEE *unchecked_func)(void) = unchecked_lambda;232 unchecked_func = checked_lambda;233 void (*checked_func)(void) = unchecked_lambda; // expected-warning{{implicit conversion from 'void (*)() __attribute__((cfi_unchecked_callee))' to 'void (*)()' discards 'cfi_unchecked_callee' attribute}}234 checked_func = checked_lambda;235 };236}237 238CFI_UNCHECKED_CALLEE239void func(void);240void func(void) {} // No warning expected.241