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

source code of compiler-rt/test/ubsan/TestCases/TypeCheck/Function/function.cpp