Commit 378b9abe by Ian Lance Taylor

compiler: pad structs ending with zero-sized field

    
    For a struct with zero-sized last field, the address of the
    field falls out of the object boundary, which confuses the
    garbage collector. Pad an extra byte in this case.
    
    Reviewed-on: https://go-review.googlesource.com/c/157557

From-SVN: r267861
parent 3ddf08b3
960637781ca9546ea2db913e48afd7eccbdadfa9 0d64279c01a37b2579c0c62ca4f2c3e3f81de07c
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -13082,6 +13082,12 @@ Struct_construction_expression::do_get_backend(Translate_context* context) ...@@ -13082,6 +13082,12 @@ Struct_construction_expression::do_get_backend(Translate_context* context)
++pv; ++pv;
} }
} }
if (this->type_->struct_type()->has_padding())
{
// Feed an extra value if there is a padding field.
Btype *fbtype = Type::lookup_integer_type("uint8")->get_backend(gogo);
init.push_back(gogo->backend()->zero_expression(fbtype));
}
return gogo->backend()->constructor_expression(btype, init, this->location()); return gogo->backend()->constructor_expression(btype, init, this->location());
} }
......
...@@ -24,8 +24,7 @@ ...@@ -24,8 +24,7 @@
// backend.h. // backend.h.
static void static void
get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, get_backend_struct_fields(Gogo* gogo, Struct_type* type, bool use_placeholder,
bool use_placeholder,
std::vector<Backend::Btyped_identifier>* bfields); std::vector<Backend::Btyped_identifier>* bfields);
static void static void
...@@ -1162,8 +1161,7 @@ Type::get_backend_placeholder(Gogo* gogo) ...@@ -1162,8 +1161,7 @@ Type::get_backend_placeholder(Gogo* gogo)
// struct field. // struct field.
{ {
std::vector<Backend::Btyped_identifier> bfields; std::vector<Backend::Btyped_identifier> bfields;
get_backend_struct_fields(gogo, this->struct_type()->fields(), get_backend_struct_fields(gogo, this->struct_type(), true, &bfields);
true, &bfields);
bt = gogo->backend()->struct_type(bfields); bt = gogo->backend()->struct_type(bfields);
} }
break; break;
...@@ -6140,12 +6138,14 @@ Struct_type::interface_method_table(Interface_type* interface, ...@@ -6140,12 +6138,14 @@ Struct_type::interface_method_table(Interface_type* interface,
// backend.h. // backend.h.
static void static void
get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, get_backend_struct_fields(Gogo* gogo, Struct_type* type, bool use_placeholder,
bool use_placeholder,
std::vector<Backend::Btyped_identifier>* bfields) std::vector<Backend::Btyped_identifier>* bfields)
{ {
const Struct_field_list* fields = type->fields();
bfields->resize(fields->size()); bfields->resize(fields->size());
size_t i = 0; size_t i = 0;
int64_t lastsize = 0;
bool saw_nonzero = false;
for (Struct_field_list::const_iterator p = fields->begin(); for (Struct_field_list::const_iterator p = fields->begin();
p != fields->end(); p != fields->end();
++p, ++i) ++p, ++i)
...@@ -6155,8 +6155,24 @@ get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, ...@@ -6155,8 +6155,24 @@ get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
? p->type()->get_backend_placeholder(gogo) ? p->type()->get_backend_placeholder(gogo)
: p->type()->get_backend(gogo)); : p->type()->get_backend(gogo));
(*bfields)[i].location = p->location(); (*bfields)[i].location = p->location();
lastsize = gogo->backend()->type_size((*bfields)[i].btype);
if (lastsize != 0)
saw_nonzero = true;
} }
go_assert(i == fields->size()); go_assert(i == fields->size());
if (saw_nonzero && lastsize == 0)
{
// For nonzero-sized structs which end in a zero-sized thing, we add
// an extra byte of padding to the type. This padding ensures that
// taking the address of the zero-sized thing can't manufacture a
// pointer to the next object in the heap. See issue 9401.
size_t n = fields->size();
bfields->resize(n + 1);
(*bfields)[n].name = "_";
(*bfields)[n].btype = Type::lookup_integer_type("uint8")->get_backend(gogo);
(*bfields)[n].location = (*bfields)[n-1].location;
type->set_has_padding();
}
} }
// Get the backend representation for a struct type. // Get the backend representation for a struct type.
...@@ -6165,7 +6181,7 @@ Btype* ...@@ -6165,7 +6181,7 @@ Btype*
Struct_type::do_get_backend(Gogo* gogo) Struct_type::do_get_backend(Gogo* gogo)
{ {
std::vector<Backend::Btyped_identifier> bfields; std::vector<Backend::Btyped_identifier> bfields;
get_backend_struct_fields(gogo, this->fields_, false, &bfields); get_backend_struct_fields(gogo, this, false, &bfields);
return gogo->backend()->struct_type(bfields); return gogo->backend()->struct_type(bfields);
} }
...@@ -10504,8 +10520,7 @@ Named_type::convert(Gogo* gogo) ...@@ -10504,8 +10520,7 @@ Named_type::convert(Gogo* gogo)
case TYPE_STRUCT: case TYPE_STRUCT:
{ {
std::vector<Backend::Btyped_identifier> bfields; std::vector<Backend::Btyped_identifier> bfields;
get_backend_struct_fields(gogo, base->struct_type()->fields(), get_backend_struct_fields(gogo, base->struct_type(), true, &bfields);
true, &bfields);
if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
bt = gogo->backend()->error_type(); bt = gogo->backend()->error_type();
} }
......
...@@ -2432,7 +2432,7 @@ class Struct_type : public Type ...@@ -2432,7 +2432,7 @@ class Struct_type : public Type
Struct_type(Struct_field_list* fields, Location location) Struct_type(Struct_field_list* fields, Location location)
: Type(TYPE_STRUCT), : Type(TYPE_STRUCT),
fields_(fields), location_(location), all_methods_(NULL), fields_(fields), location_(location), all_methods_(NULL),
is_struct_incomparable_(false) is_struct_incomparable_(false), has_padding_(false)
{ } { }
// Return the field NAME. This only looks at local fields, not at // Return the field NAME. This only looks at local fields, not at
...@@ -2552,6 +2552,17 @@ class Struct_type : public Type ...@@ -2552,6 +2552,17 @@ class Struct_type : public Type
set_is_struct_incomparable() set_is_struct_incomparable()
{ this->is_struct_incomparable_ = true; } { this->is_struct_incomparable_ = true; }
// Return whether this struct's backend type has padding, due to
// trailing zero-sized field.
bool
has_padding() const
{ return this->has_padding_; }
// Record that this struct's backend type has padding.
void
set_has_padding()
{ this->has_padding_ = true; }
// Write the hash function for this type. // Write the hash function for this type.
void void
write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*); write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*);
...@@ -2656,6 +2667,9 @@ class Struct_type : public Type ...@@ -2656,6 +2667,9 @@ class Struct_type : public Type
// True if this is a generated struct that is not considered to be // True if this is a generated struct that is not considered to be
// comparable. // comparable.
bool is_struct_incomparable_; bool is_struct_incomparable_;
// True if this struct's backend type has padding, due to trailing
// zero-sized field.
bool has_padding_;
}; };
// The type of an array. // The type of an array.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment