1 // RUN: %clangxx -DDETERMINE_UNIQUE %s -o %t-unique 2 // RUN: %clangxx -std=c++17 -fsanitize=function %s -O3 -g -DSHARED_LIB -fPIC -shared -o %t-so.so 3 // RUN: %clangxx -std=c++17 -fsanitize=function %s -O3 -g -o %t %t-so.so 4 // RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK $(%run %t-unique UNIQUE) 5 // Verify that we can disable symbolization if needed: 6 // RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM $(%run %t-unique NOSYM-UNIQUE) 7 // XFAIL: windows-msvc 8 // Unsupported function flag 9 // UNSUPPORTED: openbsd 10 11 #ifdef DETERMINE_UNIQUE 12 13 #include <iostream> 14 15 #include "../../../../../lib/sanitizer_common/sanitizer_platform.h" 16 main(int,char ** argv)17int main(int, char **argv) { 18 if (!SANITIZER_NON_UNIQUE_TYPEINFO) 19 std::cout << "--check-prefix=" << argv[1]; 20 } 21 22 #else 23 24 struct Shared {}; 25 using FnShared = void (*)(Shared *); 26 FnShared getShared(); 27 28 struct __attribute__((visibility("hidden"))) Hidden {}; 29 using FnHidden = void (*)(Hidden *); 30 FnHidden getHidden(); 31 32 namespace { 33 struct Private {}; 34 } // namespace 35 using FnPrivate = void (*)(void *); 36 FnPrivate getPrivate(); 37 38 #ifdef SHARED_LIB 39 fnShared(Shared *)40void fnShared(Shared *) {} getShared()41FnShared getShared() { return fnShared; } 42 fnHidden(Hidden *)43void fnHidden(Hidden *) {} getHidden()44FnHidden getHidden() { return fnHidden; } 45 fnPrivate(Private *)46void fnPrivate(Private *) {} getPrivate()47FnPrivate getPrivate() { return reinterpret_cast<FnPrivate>(fnPrivate); } 48 49 #else 50 51 #include <stdint.h> 52 f()53void f() {} 54 g(int x)55void g(int x) {} 56 make_valid_call()57void make_valid_call() { 58 // CHECK-NOT: runtime error: call to function g 59 reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42); 60 } 61 make_invalid_call()62void make_invalid_call() { 63 // CHECK: function.cpp:[[@LINE+4]]:3: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)' 64 // CHECK-NEXT: function.cpp:[[@LINE-11]]: note: f() defined here 65 // NOSYM: function.cpp:[[@LINE+2]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)' 66 // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) defined here 67 reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42); 68 } 69 f1(int)70void f1(int) {} f2(unsigned int)71void f2(unsigned int) {} f3(int)72void f3(int) noexcept {} f4(unsigned int)73void f4(unsigned int) noexcept {} 74 check_noexcept_calls()75void check_noexcept_calls() { 76 void (*p1)(int); 77 p1 = &f1; 78 p1(0); 79 p1 = reinterpret_cast<void (*)(int)>(&f2); 80 // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f2(unsigned int) through pointer to incorrect function type 'void (*)(int)' 81 // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)' 82 p1(0); 83 p1 = &f3; 84 p1(0); 85 p1 = reinterpret_cast<void (*)(int)>(&f4); 86 // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f4(unsigned int) through pointer to incorrect function type 'void (*)(int)' 87 // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)' 88 p1(0); 89 90 void (*p2)(int) noexcept; 91 p2 = reinterpret_cast<void (*)(int) noexcept>(&f1); 92 // TODO: Unclear whether calling a non-noexcept function through a pointer to 93 // nexcept function should cause an error. 94 // CHECK-NOT: function.cpp:[[@LINE+2]]:3: runtime error: call to function f1(int) through pointer to incorrect function type 'void (*)(int) noexcept' 95 // NOSYM-NOT: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept' 96 p2(0); 97 p2 = reinterpret_cast<void (*)(int) noexcept>(&f2); 98 // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f2(unsigned int) through pointer to incorrect function type 'void (*)(int) noexcept' 99 // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept' 100 p2(0); 101 p2 = &f3; 102 p2(0); 103 p2 = reinterpret_cast<void (*)(int) noexcept>(&f4); 104 // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f4(unsigned int) through pointer to incorrect function type 'void (*)(int) noexcept' 105 // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept' 106 p2(0); 107 } 108 check_cross_dso()109void check_cross_dso() { 110 getShared()(nullptr); 111 112 // UNIQUE: function.cpp:[[@LINE+2]]:3: runtime error: call to function fnHidden(Hidden*) through pointer to incorrect function type 'void (*)(Hidden *)' 113 // NOSYM-UNIQUE: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(Hidden *)' 114 getHidden()(nullptr); 115 116 // TODO: Unlike GCC, Clang fails to prefix the typeinfo name for the function 117 // type with "*", so this erroneously only fails for "*UNIQUE": 118 // UNIQUE: function.cpp:[[@LINE+2]]:3: runtime error: call to function fnPrivate((anonymous namespace)::Private*) through pointer to incorrect function type 'void (*)((anonymous namespace)::Private *)' 119 // NOSYM-UNIQUE: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)((anonymous namespace)::Private *)' 120 reinterpret_cast<void (*)(Private *)>(getPrivate())(nullptr); 121 } 122 main(void)123int main(void) { 124 make_valid_call(); 125 make_invalid_call(); 126 check_noexcept_calls(); 127 check_cross_dso(); 128 // Check that no more errors will be printed. 129 // CHECK-NOT: runtime error: call to function 130 // NOSYM-NOT: runtime error: call to function 131 make_invalid_call(); 132 } 133 134 #endif 135 136 #endif 137