1// { dg-do run }
2
3#include <assert.h>
4#include <signal.h>
5#include <setjmp.h>
6#include <stdio.h>
7
8#include <iostream>
9#include <fstream>
10
11using std::ofstream;
12using std::ifstream;
13using std::ios;
14
15struct A {
16  A():value(123) {}
17    int value;
18    virtual int access() { return this->value; }
19};
20struct B {
21  B():value(456) {}
22    int value;
23    virtual int access() { return this->value; }
24};
25struct C : public A, public B {
26  C():better_value(789) {}
27    int better_value;
28    virtual int access() { return this->better_value; }
29};
30struct D: public C {
31  D():other_value(987) {}
32  int other_value;
33  virtual int access() { return this->other_value; }
34};
35
36volatile static int signal_count = 0;
37
38sigjmp_buf before_segv;
39
40static void
41handler(int sig, siginfo_t *si, void *unused)
42{
43  /*
44  printf("Got SIGSEGV at address: 0x%lx\n",
45         (long) si->si_addr);
46  */
47
48  signal_count++;
49  /* You are not supposed to longjmp out of a signal handler but it seems
50     to work for this test case and it simplifies it */
51  siglongjmp(before_segv, 1);
52  /* exit(1); */
53}
54
55/* Access one of the vtable_map variables generated by this .o */
56extern void * _ZN4_VTVI1BE12__vtable_mapE;
57
58/* Access one of the vtable_map variables generated by libstdc++ */
59extern void * _ZN4_VTVISt8ios_baseE12__vtable_mapE;
60
61int use(B *b)
62{
63  int ret;
64
65  ret = sigsetjmp(before_segv, 1);
66  if (ret == 0)
67    {
68      /* This should generate a segmentation violation. ie: at this point it should
69	 be protected */
70      _ZN4_VTVI1BE12__vtable_mapE = 0;
71    }
72  assert(ret == 1 && signal_count == 1);
73
74  ret = sigsetjmp(before_segv, 1);
75  if (ret == 0)
76    {
77      /* Try to modify one of the vtable_map variables in the stdc++ library.
78	 This should generate a segmentation violation. ie: at this point it
79	 should be protected */
80      _ZN4_VTVISt8ios_baseE12__vtable_mapE = 0;
81    }
82  assert(ret == 1 && signal_count == 2);
83
84  return b->access();
85}
86
87void myread(std::istream * in)
88{
89  char input_str[50] = "\0";
90  if (in->good())
91    (*in) >> input_str;
92  std::cout << input_str << std::endl;
93  delete in;
94}
95
96int main()
97{
98  ifstream * infile = new ifstream("./thunk_vtable_map_attack.cpp");
99  myread(infile);
100
101  /* Set up handler for SIGSEGV. */
102  struct sigaction sa;
103  sa.sa_flags = SA_SIGINFO;
104  sigemptyset(&sa.sa_mask);
105  sa.sa_sigaction = handler;
106  if (sigaction(SIGSEGV, &sa, NULL) == -1)
107    assert(0);
108
109  C c;
110  assert(use(&c) == 789);
111
112  return 0;
113}
114