xref: /llvm-project/compiler-rt/test/cfi/two-vcalls.cpp (revision 714301d784308c74724ab30ea566fa14fc01d300)
1 // RUN: %clangxx_cfi_diag -o %t %s
2 // RUN: %run %t 2>&1 | FileCheck %s
3 
4 // This test checks that we don't generate two type checks,
5 // if two virtual calls are in the same function.
6 
7 // UNSUPPORTED: target={{.*windows-msvc.*}}
8 // REQUIRES: cxxabi
9 
10 // TODO(krasin): implement the optimization to not emit two type checks.
11 // XFAIL: *
12 #include <stdio.h>
13 
14 class Base {
15  public:
Foo()16   virtual void Foo() {
17     fprintf(stderr, "Base::Foo\n");
18   }
19 
Bar()20   virtual void Bar() {
21     fprintf(stderr, "Base::Bar\n");
22   }
23 };
24 
25 class Derived : public Base {
26  public:
Foo()27   void Foo() override {
28     fprintf(stderr, "Derived::Foo\n");
29   }
30 
Bar()31   void Bar() override {
32     printf("Derived::Bar\n");
33   }
34 };
35 
print(Base * ptr)36 __attribute__((noinline)) void print(Base* ptr) {
37   ptr->Foo();
38   // Corrupt the vtable pointer. We expect that the optimization will
39   // check vtable before the first vcall then store it in a local
40   // variable, and reuse it for the second vcall. With no optimization,
41   // CFI will complain about the virtual table being corrupted.
42   *reinterpret_cast<void**>(ptr) = 0;
43   ptr->Bar();
44 }
45 
46 
main()47 int main() {
48   Base b;
49   Derived d;
50   // CHECK: Base::Foo
51   // CHECK: Base::Bar
52   print(&b);
53 
54   // CHECK: Derived::Foo
55   // CHECK-NOT: runtime error
56   // CHECK: Derived::Bar
57   print(&d);
58 
59   return 0;
60 }
61