mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 14:06:06 +00:00
[randstruct] Don't allow implicit forward decl to stop struct randomization
If a struct/enum type used in a record doesn't have a forward decl / def, an implicit one is injected into the struct. This stops clang from randomizing the structure in some situations---i.e. when the struct contains only function pointers. So we accept forward decls so they don't prevent randomization. Fixes 60349 Reviewed By: MaskRay, nickdesaulniers Differential Revision: https://reviews.llvm.org/D143300
This commit is contained in:
parent
d453d73d0d
commit
f85a9a6452
@ -18873,10 +18873,24 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
|
||||
ProcessDeclAttributeList(S, Record, Attrs);
|
||||
|
||||
// Check to see if a FieldDecl is a pointer to a function.
|
||||
auto IsFunctionPointer = [&](const Decl *D) {
|
||||
auto IsFunctionPointerOrForwardDecl = [&](const Decl *D) {
|
||||
const FieldDecl *FD = dyn_cast<FieldDecl>(D);
|
||||
if (!FD)
|
||||
if (!FD) {
|
||||
// Check whether this is a forward declaration that was inserted by
|
||||
// Clang. This happens when a non-forward declared / defined type is
|
||||
// used, e.g.:
|
||||
//
|
||||
// struct foo {
|
||||
// struct bar *(*f)();
|
||||
// struct bar *(*g)();
|
||||
// };
|
||||
//
|
||||
// "struct bar" shows up in the decl AST as a "RecordDecl" with an
|
||||
// incomplete definition.
|
||||
if (const auto *TD = dyn_cast<TagDecl>(D))
|
||||
return !TD->isCompleteDefinition();
|
||||
return false;
|
||||
}
|
||||
QualType FieldType = FD->getType().getDesugaredType(Context);
|
||||
if (isa<PointerType>(FieldType)) {
|
||||
QualType PointeeType = cast<PointerType>(FieldType)->getPointeeType();
|
||||
@ -18890,7 +18904,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
|
||||
if (!getLangOpts().CPlusPlus &&
|
||||
(Record->hasAttr<RandomizeLayoutAttr>() ||
|
||||
(!Record->hasAttr<NoRandomizeLayoutAttr>() &&
|
||||
llvm::all_of(Record->decls(), IsFunctionPointer))) &&
|
||||
llvm::all_of(Record->decls(), IsFunctionPointerOrForwardDecl))) &&
|
||||
!Record->isUnion() && !getLangOpts().RandstructSeed.empty() &&
|
||||
!Record->isRandomized()) {
|
||||
SmallVector<Decl *, 32> NewDeclOrdering;
|
||||
|
36
clang/test/CodeGen/init-randomized-struct-fwd-decl.c
Normal file
36
clang/test/CodeGen/init-randomized-struct-fwd-decl.c
Normal file
@ -0,0 +1,36 @@
|
||||
// RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm -frandomize-layout-seed=1234567890abcdef < %s | FileCheck %s
|
||||
// PR60349
|
||||
|
||||
// Clang will add a forward declaration of "struct bar" and "enum qux" to the
|
||||
// structures. This shouldn't prevent these structures from being randomized.
|
||||
// So the 'f' element shouldn't be at the start of the structure anymore.
|
||||
|
||||
struct foo {
|
||||
struct bar *(*f)(void);
|
||||
struct bar *(*g)(void);
|
||||
struct bar *(*h)(void);
|
||||
struct bar *(*i)(void);
|
||||
struct bar *(*j)(void);
|
||||
struct bar *(*k)(void);
|
||||
};
|
||||
|
||||
// CHECK-LABEL: define {{.*}}@t1(
|
||||
// CHECK-NOT: getelementptr inbounds %struct.foo, ptr %3, i32 0, i32 0
|
||||
struct bar *t1(struct foo *z) {
|
||||
return z->f();
|
||||
}
|
||||
|
||||
struct baz {
|
||||
enum qux *(*f)(void);
|
||||
enum qux *(*g)(void);
|
||||
enum qux *(*h)(void);
|
||||
enum qux *(*i)(void);
|
||||
enum qux *(*j)(void);
|
||||
enum qux *(*k)(void);
|
||||
};
|
||||
|
||||
// CHECK-LABEL: define {{.*}}@t2(
|
||||
// CHECK-NOT: getelementptr inbounds %struct.baz, ptr %3, i32 0, i32 0
|
||||
enum qux *t2(struct baz *z) {
|
||||
return z->f();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user