Add tests for non-virtual call checking.

Differential Revision: http://reviews.llvm.org/D8792

llvm-svn: 233876
This commit is contained in:
Peter Collingbourne 2015-04-02 00:33:36 +00:00
parent 1a7488afaa
commit 7881648a4e
3 changed files with 98 additions and 1 deletions

View File

@ -0,0 +1,8 @@
The tests in this directory use a common convention for exercising the
functionality associated with bit sets of different sizes. When certain
macros are defined the tests instantiate classes that force the bit sets
to be of certain sizes.
- B32 forces 32-bit bit sets.
- B64 forces 64-bit bit sets.
- BM forces memory bit sets.

View File

@ -0,0 +1,65 @@
// RUN: %clangxx_cfi -o %t %s
// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s
// RUN: %clangxx_cfi -DB32 -o %t %s
// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s
// RUN: %clangxx_cfi -DB64 -o %t %s
// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s
// RUN: %clangxx_cfi -DBM -o %t %s
// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s
// RUN: %clangxx -o %t %s
// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s
// Tests that the CFI mechanism crashes the program when making a non-virtual
// call to an object of the wrong class, by casting a pointer to such an object
// and attempting to make a call through it.
#include <stdio.h>
#include "utils.h"
struct A {
virtual void f();
};
void A::f() {}
struct B {
void f();
virtual void g();
};
void B::f() {}
void B::g() {}
int main() {
#ifdef B32
break_optimization(new Deriver<B, 0>);
#endif
#ifdef B64
break_optimization(new Deriver<B, 0>);
break_optimization(new Deriver<B, 1>);
#endif
#ifdef BM
break_optimization(new Deriver<B, 0>);
break_optimization(new Deriver<B, 1>);
break_optimization(new Deriver<B, 2>);
#endif
A *a = new A;
break_optimization(a);
// CFI: 1
// NCFI: 1
fprintf(stderr, "1\n");
((B *)a)->f(); // UB here
// CFI-NOT: 2
// NCFI: 2
fprintf(stderr, "2\n");
}

View File

@ -3,95 +3,119 @@
// Tests that the CFI mechanism does not crash the program when making various
// kinds of valid calls involving classes with various different linkages and
// types of inheritance.
// types of inheritance, and both virtual and non-virtual member functions.
#include "utils.h"
struct A {
virtual void f();
void g();
};
void A::f() {}
void A::g() {}
struct A2 : A {
virtual void f();
void g();
};
void A2::f() {}
void A2::g() {}
struct B {
virtual void f() {}
void g() {}
};
struct B2 : B {
virtual void f() {}
void g() {}
};
namespace {
struct C {
virtual void f();
void g();
};
void C::f() {}
void C::g() {}
struct C2 : C {
virtual void f();
void g();
};
void C2::f() {}
void C2::g() {}
struct D {
virtual void f() {}
void g() {}
};
struct D2 : D {
virtual void f() {}
void g() {}
};
}
struct E {
virtual void f() {}
void g() {}
};
struct E2 : virtual E {
virtual void f() {}
void g() {}
};
int main() {
A *a = new A;
break_optimization(a);
a->f();
a->g();
a = new A2;
break_optimization(a);
a->f();
a->g();
B *b = new B;
break_optimization(b);
b->f();
b->g();
b = new B2;
break_optimization(b);
b->f();
b->g();
C *c = new C;
break_optimization(c);
c->f();
c->g();
c = new C2;
break_optimization(c);
c->f();
c->g();
D *d = new D;
break_optimization(d);
d->f();
d->g();
d = new D2;
break_optimization(d);
d->f();
d->g();
E *e = new E;
break_optimization(e);
e->f();
e->g();
e = new E2;
break_optimization(e);
e->f();
e->g();
}