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
This commit is contained in:
parent
3ddf08b3b8
commit
378b9abe56
|
@ -1,4 +1,4 @@
|
|||
960637781ca9546ea2db913e48afd7eccbdadfa9
|
||||
0d64279c01a37b2579c0c62ca4f2c3e3f81de07c
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -13082,6 +13082,12 @@ Struct_construction_expression::do_get_backend(Translate_context* context)
|
|||
++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());
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
// backend.h.
|
||||
|
||||
static void
|
||||
get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
|
||||
bool use_placeholder,
|
||||
get_backend_struct_fields(Gogo* gogo, Struct_type* type, bool use_placeholder,
|
||||
std::vector<Backend::Btyped_identifier>* bfields);
|
||||
|
||||
static void
|
||||
|
@ -1162,8 +1161,7 @@ Type::get_backend_placeholder(Gogo* gogo)
|
|||
// struct field.
|
||||
{
|
||||
std::vector<Backend::Btyped_identifier> bfields;
|
||||
get_backend_struct_fields(gogo, this->struct_type()->fields(),
|
||||
true, &bfields);
|
||||
get_backend_struct_fields(gogo, this->struct_type(), true, &bfields);
|
||||
bt = gogo->backend()->struct_type(bfields);
|
||||
}
|
||||
break;
|
||||
|
@ -6140,12 +6138,14 @@ Struct_type::interface_method_table(Interface_type* interface,
|
|||
// backend.h.
|
||||
|
||||
static void
|
||||
get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
|
||||
bool use_placeholder,
|
||||
get_backend_struct_fields(Gogo* gogo, Struct_type* type, bool use_placeholder,
|
||||
std::vector<Backend::Btyped_identifier>* bfields)
|
||||
{
|
||||
const Struct_field_list* fields = type->fields();
|
||||
bfields->resize(fields->size());
|
||||
size_t i = 0;
|
||||
int64_t lastsize = 0;
|
||||
bool saw_nonzero = false;
|
||||
for (Struct_field_list::const_iterator p = fields->begin();
|
||||
p != fields->end();
|
||||
++p, ++i)
|
||||
|
@ -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(gogo));
|
||||
(*bfields)[i].location = p->location();
|
||||
lastsize = gogo->backend()->type_size((*bfields)[i].btype);
|
||||
if (lastsize != 0)
|
||||
saw_nonzero = true;
|
||||
}
|
||||
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.
|
||||
|
@ -6165,7 +6181,7 @@ Btype*
|
|||
Struct_type::do_get_backend(Gogo* gogo)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -10504,8 +10520,7 @@ Named_type::convert(Gogo* gogo)
|
|||
case TYPE_STRUCT:
|
||||
{
|
||||
std::vector<Backend::Btyped_identifier> bfields;
|
||||
get_backend_struct_fields(gogo, base->struct_type()->fields(),
|
||||
true, &bfields);
|
||||
get_backend_struct_fields(gogo, base->struct_type(), true, &bfields);
|
||||
if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
|
||||
bt = gogo->backend()->error_type();
|
||||
}
|
||||
|
|
|
@ -2432,7 +2432,7 @@ class Struct_type : public Type
|
|||
Struct_type(Struct_field_list* fields, Location location)
|
||||
: Type(TYPE_STRUCT),
|
||||
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
|
||||
|
@ -2552,6 +2552,17 @@ class Struct_type : public Type
|
|||
set_is_struct_incomparable()
|
||||
{ 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.
|
||||
void
|
||||
write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*);
|
||||
|
@ -2656,6 +2667,9 @@ class Struct_type : public Type
|
|||
// True if this is a generated struct that is not considered to be
|
||||
// comparable.
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue