reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
// UNSUPPORTED: windows-msvc

// RUN: %clangxx_cfi -o %t %s
// RUN: %expect_crash %run %t a
// RUN: %expect_crash %run %t b
// RUN: %expect_crash %run %t c
// RUN: %expect_crash %run %t d
// RUN: %expect_crash %run %t e
// RUN: %run %t f
// RUN: %run %t g

// RUN: %clangxx_cfi_diag -o %t2 %s
// RUN: %run %t2 a 2>&1 | FileCheck --check-prefix=A %s
// RUN: %run %t2 b 2>&1 | FileCheck --check-prefix=B %s
// RUN: %run %t2 c 2>&1 | FileCheck --check-prefix=C %s
// RUN: %run %t2 d 2>&1 | FileCheck --check-prefix=D %s
// RUN: %run %t2 e 2>&1 | FileCheck --check-prefix=E %s

#include <assert.h>
#include <string.h>

struct SBase1 {
  void b1() {}
};

struct SBase2 {
  void b2() {}
};

struct S : SBase1, SBase2 {
  void f1() {}
  int f2() { return 1; }
  virtual void g1() {}
  virtual int g2() { return 1; }
  virtual int g3() { return 1; }
};

struct T {
  void f1() {}
  int f2() { return 2; }
  virtual void g1() {}
  virtual int g2() { return 2; }
  virtual void g3() {}
};

typedef void (S::*S_void)();

typedef int (S::*S_int)();
typedef int (T::*T_int)();

template <typename To, typename From>
To bitcast(From f) {
  assert(sizeof(To) == sizeof(From));
  To t;
  memcpy(&t, &f, sizeof(f));
  return t;
}

int main(int argc, char **argv) {
  S s;
  T t;

  switch (argv[1][0]) {
    case 'a':
      // A: runtime error: control flow integrity check for type 'int (S::*)()' failed during non-virtual pointer to member function call
      // A: note: S::f1() defined here
      (s.*bitcast<S_int>(&S::f1))();
      break;
    case 'b':
      // B: runtime error: control flow integrity check for type 'int (T::*)()' failed during non-virtual pointer to member function call
      // B: note: S::f2() defined here
      (t.*bitcast<T_int>(&S::f2))();
      break;
    case 'c':
      // C: runtime error: control flow integrity check for type 'int (S::*)()' failed during virtual pointer to member function call
      // C: note: vtable is of type 'S'
      (s.*bitcast<S_int>(&S::g1))();
      break;
    case 'd':
      // D: runtime error: control flow integrity check for type 'int (S::*)()' failed during virtual pointer to member function call
      // D: note: vtable is of type 'T'
      (reinterpret_cast<S &>(t).*&S::g2)();
      break;
    case 'e':
      // E: runtime error: control flow integrity check for type 'void (S::*)()' failed during virtual pointer to member function call
      // E: note: vtable is of type 'S'
      (s.*bitcast<S_void>(&T::g3))();
      break;
    case 'f':
      (s.*&SBase1::b1)();
      break;
    case 'g':
      (s.*&SBase2::b2)();
      break;
  }
}