Skip to content

Reinstate no randomize layout #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
1 change: 1 addition & 0 deletions clang/include/clang/AST/RandstructSeed.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
#include <string>
namespace clang {
extern std::string RandstructSeed;
extern bool RandstructAutoSelect;
}
#endif
3 changes: 3 additions & 0 deletions clang/include/clang/AST/RecordFieldReorganizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class RecordFieldReorganizer {
};

class Randstruct : public RecordFieldReorganizer {
public:
/// Determines if the Record can be safely and easily randomized based on certain criteria (see implementation).
static bool isTriviallyRandomizable(const RecordDecl *D);
protected:
virtual void reorganize(const ASTContext &C, const RecordDecl *D,
SmallVector<Decl *, 64> &NewOrder) const override;
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -3208,3 +3208,10 @@ def RandomizeLayout : InheritableAttr {
let Subjects = SubjectList<[Record]>;
let Documentation = [ClangRandstructDocs];
}

def NoRandomizeLayout : InheritableAttr {
let Spellings = [GCC<"no_randomize_layout">, Declspec<"no_randomize_layout">,
Keyword<"no_randomize_layout">];
let Subjects = SubjectList<[Record]>;
let Documentation = [ClangRandstructDocs];
}
32 changes: 30 additions & 2 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -4099,10 +4099,24 @@ When compiled without ``-fobjc-arc``, this attribute is ignored.

def ClangRandstructDocs : Documentation {
let Category = DocCatVariable;
let Heading = "randomize_layout, no_randomize_layout";
let Content = [{
The attribute ``randomize_layout`` can be applied to the declaration of
a record. ``randomize_layout`` instructs the compiler to randomize the memory layout
The attributes ``randomize_layout`` and ``no_randomize_layout`` can be applied
to a record.

``randomize_layout`` instructs the compiler to randomize the memory layout
of the member variables of the record.

Conversely, ``no_randomize_layout`` is used to indicate that if using the
automatic strucuture selection feature of the Randstruct implementation, the
compiler should not shuffle the members of the record.

In the event that a record is labeled with both attributes, the compiler will
emit a warning indicating that these two cannot be used on the same record.
The default behavior in this case is to not randomize the struct, as the
attribute ``no_randomize_layout`` takes precedence over ``randomize_layout``.
This is implementation defined behavior.

.. code-block:: c

// Indicates that this struct should be randomized by Randstruct implementation.
Expand All @@ -4111,5 +4125,19 @@ of the member variables of the record.
char *b;
char *c;
}__attribute__((randomize_layout));

// Indicates that this struct should NOT be randomized by Randstruct implementation.
struct s {
char *a;
char *b;
char *c;
}__attribute__((no_randomize_layout));

// Emits compiler warning. Struct is NOT randomized by Randstruct implementation.
struct s {
char *a;
char *b;
char *c;
}__attribute__((randomize_layout)) __attribute__((no_randomize_layout));
}];
}
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -345,4 +345,7 @@ def warn_unnecessary_packed : Warning<
"packed attribute is unnecessary for %0">, InGroup<Packed>, DefaultIgnore;
def warn_randomize_attr_union : Warning<
"union declared with 'randomize_layout' attribute">, InGroup<DiagGroup<"randomize-layout">>;
def warn_randomize_attr_conflict : Warning<
"struct declared with 'randomize_layout' and 'no_randomize_layout' attributes; "
"attribute 'no_randomize_layout' takes precedence">, InGroup<DiagGroup<"no-randomize-layout">>;
}
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,9 @@ def freroll_loops : Flag<["-"], "freroll-loops">, Group<f_Group>,
HelpText<"Turn on loop reroller">, Flags<[CC1Option]>;
def fno_reroll_loops : Flag<["-"], "fno-reroll-loops">, Group<f_Group>,
HelpText<"Turn off loop reroller">;
def randstruct_auto : Flag<["-"], "randstruct-auto">,
HelpText<"Enable automatic structure selection for field randomization; "
"disabled with no_randomize_layout">, Flags<[CC1Option]>;
def ftrigraphs : Flag<["-"], "ftrigraphs">, Group<f_Group>,
HelpText<"Process trigraph sequences">, Flags<[CC1Option]>;
def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group<f_Group>,
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/AST/RecordFieldReorganizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

namespace clang {
std::string RandstructSeed = "";
bool RandstructAutoSelect = false;

void RecordFieldReorganizer::reorganizeFields(const ASTContext &C,
const RecordDecl *D) const {
Expand All @@ -37,7 +38,6 @@ void RecordFieldReorganizer::reorganizeFields(const ASTContext &C,
mutateGuard.insert(f);
fields.push_back(f);
}

// Now allow subclass implementations to reorder the fields
reorganize(C, D, fields);

Expand All @@ -52,7 +52,6 @@ void RecordFieldReorganizer::reorganizeFields(const ASTContext &C,

commit(D, fields);
}

void RecordFieldReorganizer::commit(
const RecordDecl *D, SmallVectorImpl<Decl *> &NewFieldOrder) const {
Decl *First, *Last;
Expand Down Expand Up @@ -254,5 +253,12 @@ void Randstruct::reorganize(const ASTContext &C, const RecordDecl *D,
SmallVector<Decl *, 64> randomized = perfrandomize(C, NewOrder);
NewOrder = randomized;
}

bool Randstruct::isTriviallyRandomizable(const RecordDecl *D) {
for (auto f : D->fields()){
//If an element of the structure does not have a
//function type is not a function pointer
if(f->getFunctionType() == nullptr){ return false; }
}
return true;
}
} // namespace clang
25 changes: 15 additions & 10 deletions clang/lib/AST/RecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2987,18 +2987,23 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
if (Entry) return *Entry;

const ASTRecordLayout *NewEntry = nullptr;

bool ShouldBeRandomized = D->getAttr<RandomizeLayoutAttr>() != nullptr;
if (ShouldBeRandomized) {
// There is no technical benefit to randomizing the fields of a union
// since they all share the same offset of zero.
if (D->isUnion()) {
bool NotToBeRandomized = D->getAttr<NoRandomizeLayoutAttr>() != nullptr;
bool AutoSelectable = RandstructAutoSelect && Randstruct::isTriviallyRandomizable(D);

if (ShouldBeRandomized && NotToBeRandomized) {
getDiagnostics().Report(D->getLocation(), diag::warn_randomize_attr_conflict);
}

if (ShouldBeRandomized && D->isUnion()) {
getDiagnostics().Report(D->getLocation(), diag::warn_randomize_attr_union);
}
else {
Randstruct randstruct;
randstruct.reorganizeFields(*this,D);
}
NotToBeRandomized = true;
}

if (!NotToBeRandomized && (ShouldBeRandomized || AutoSelectable)) {
Randstruct randstruct;
randstruct.reorganizeFields(*this,D);
}

if (isMsLayout(*this)) {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4411,6 +4411,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(0));
}

if (Arg *A = Args.getLastArg(options::OPT_randstruct_auto)) {
CmdArgs.push_back( "-randstruct-auto" );
}

// -fvisibility= and -fvisibility-ms-compat are of a piece.
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
if (const Arg* A = Args.getLastArg(OPT_randstruct_seed)) {
RandstructSeed = A->getValue(0);
}
if (const Arg* A = Args.getLastArg(OPT_randstruct_auto)) {
RandstructAutoSelect = true;
}
Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin);
for (const auto *AA : Args.filtered(OPT_plugin_arg))
Opts.PluginArgs[AA->getValue(0)].emplace_back(AA->getValue(1));
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6856,6 +6856,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_RandomizeLayout:
handleSimpleAttribute<RandomizeLayoutAttr>(S, D, AL);
break;
case ParsedAttr::AT_NoRandomizeLayout:
handleSimpleAttribute<NoRandomizeLayoutAttr>(S, D, AL);
break;
case ParsedAttr::AT_CodeSeg:
handleCodeSegAttr(S, D, AL);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
// CHECK-NEXT: NoInstrumentFunction (SubjectMatchRule_function)
// CHECK-NEXT: NoMicroMips (SubjectMatchRule_function)
// CHECK-NEXT: NoMips16 (SubjectMatchRule_function)
// CHECK-NEXT: NoRandomizeLayout (SubjectMatchRule_record)
// CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
// CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
// CHECK-NEXT: NoSpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)
Expand Down