// 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
// 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;
// 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)
? 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.
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);
}
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();
}
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
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*);
// 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.