fix Method.getModifiers crash due to bootimage miscompile

When calculating field offsets in the bootimage generator, we failed
to consider alignment at inheritence boundaries (i.e. the last field
inherited by from a superclass should be followed by enough padding to
align the first non-inherited field at a machine word boundary).  This
led to a mismatch between native code and Java code in terms of class
layouts, including that of java.lang.reflect.Method.
This commit is contained in:
Joel Dice 2014-01-06 15:19:00 -07:00
parent 1f6051bcbc
commit bb86500155
3 changed files with 45 additions and 35 deletions

View File

@ -1292,9 +1292,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
unsigned size = fieldSize(t, code); unsigned size = fieldSize(t, code);
if (flags & ACC_STATIC) { if (flags & ACC_STATIC) {
while (staticOffset % size) { staticOffset = pad(staticOffset, size);
++ staticOffset;
}
fieldOffset(t, field) = staticOffset; fieldOffset(t, field) = staticOffset;
@ -1308,9 +1306,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
classVmFlags(t, class_) |= HasFinalMemberFlag; classVmFlags(t, class_) |= HasFinalMemberFlag;
} }
while (memberOffset % size) { memberOffset = pad(memberOffset, size);
++ memberOffset;
}
fieldOffset(t, field) = memberOffset; fieldOffset(t, field) = memberOffset;
@ -1335,9 +1331,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
for (unsigned i = 0, offset = BytesPerWord; i < staticCount; ++i) { for (unsigned i = 0, offset = BytesPerWord; i < staticCount; ++i) {
unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]); unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]);
while (offset % size) { offset = pad(offset, size);
++ offset;
}
unsigned value = intArrayBody(t, staticValueTable, i); unsigned value = intArrayBody(t, staticValueTable, i);
if (value) { if (value) {

View File

@ -48,6 +48,7 @@ const bool DebugNativeTarget = false;
enum Type { enum Type {
Type_none, Type_none,
Type_pad,
Type_object, Type_object,
Type_object_nogc, Type_object_nogc,
Type_int8_t, Type_int8_t,
@ -517,9 +518,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
} }
if (fieldFlags(t, field) & ACC_STATIC) { if (fieldFlags(t, field) & ACC_STATIC) {
while (targetStaticOffset % targetSize) { targetStaticOffset = pad(targetStaticOffset, targetSize);
++ targetStaticOffset;
}
buildStaticOffset = fieldOffset(t, field); buildStaticOffset = fieldOffset(t, field);
@ -531,9 +530,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
++ staticIndex; ++ staticIndex;
} else { } else {
while (targetMemberOffset % targetSize) { targetMemberOffset = pad(targetMemberOffset, targetSize);
++ targetMemberOffset;
}
buildMemberOffset = fieldOffset(t, field); buildMemberOffset = fieldOffset(t, field);
@ -1339,13 +1336,16 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp
for (unsigned i = 0; i < arrayLength(t, t->m->types); ++i) { for (unsigned i = 0; i < arrayLength(t, t->m->types); ++i) {
Type* source = types[i]; Type* source = types[i];
unsigned count = 0; unsigned typeCount = 0;
while (source[count] != Type_none) { unsigned fieldCount = 1;
++ count; while (source[typeCount] != Type_none) {
++ typeCount;
if (source[typeCount] != Type_pad) {
++ fieldCount;
}
} }
++ count;
THREAD_RUNTIME_ARRAY(t, Field, fields, count); THREAD_RUNTIME_ARRAY(t, Field, fields, fieldCount);
init(new (RUNTIME_ARRAY_BODY(fields)) Field, Type_object, 0, init(new (RUNTIME_ARRAY_BODY(fields)) Field, Type_object, 0,
BytesPerWord, 0, TargetBytesPerWord); BytesPerWord, 0, TargetBytesPerWord);
@ -1356,8 +1356,15 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp
Type type = Type_none; Type type = Type_none;
unsigned buildSize = 0; unsigned buildSize = 0;
unsigned targetSize = 0; unsigned targetSize = 0;
for (unsigned j = 1; j < count; ++j) { unsigned fieldOffset = 1;
switch (source[j - 1]) { for (unsigned j = 0; j < typeCount; ++j) {
switch (source[j]) {
case Type_pad:
type = Type_pad;
buildSize = 0;
targetSize = 0;
break;
case Type_object: case Type_object:
type = Type_object; type = Type_object;
buildSize = BytesPerWord; buildSize = BytesPerWord;
@ -1412,21 +1419,21 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp
default: abort(t); default: abort(t);
} }
if (source[j - 1] == Type_array) { if (source[j] == Type_array) {
sawArray = true; sawArray = true;
} }
if (not sawArray) { if (type == Type_pad) {
while (buildOffset % buildSize) { buildOffset = pad(buildOffset, BytesPerWord);
++ buildOffset;
}
while (targetOffset % targetSize) { targetOffset = pad(targetOffset, TargetBytesPerWord);
++ targetOffset; } else if (not sawArray) {
} buildOffset = pad(buildOffset, buildSize);
init(new (RUNTIME_ARRAY_BODY(fields) + j) Field, type, buildOffset, targetOffset = pad(targetOffset, targetSize);
buildSize, targetOffset, targetSize);
init(new (RUNTIME_ARRAY_BODY(fields) + (fieldOffset++)) Field, type,
buildOffset, buildSize, targetOffset, targetSize);
buildOffset += buildSize; buildOffset += buildSize;
targetOffset += targetSize; targetOffset += targetSize;
@ -1438,12 +1445,12 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp
unsigned buildArrayElementSize; unsigned buildArrayElementSize;
unsigned targetArrayElementSize; unsigned targetArrayElementSize;
if (sawArray) { if (sawArray) {
fixedFieldCount = count - 2; fixedFieldCount = fieldCount - 2;
arrayElementType = type; arrayElementType = type;
buildArrayElementSize = buildSize; buildArrayElementSize = buildSize;
targetArrayElementSize = targetSize; targetArrayElementSize = targetSize;
} else { } else {
fixedFieldCount = count; fixedFieldCount = fieldCount;
arrayElementType = Type_none; arrayElementType = Type_none;
buildArrayElementSize = 0; buildArrayElementSize = 0;
targetArrayElementSize = 0; targetArrayElementSize = 0;

View File

@ -636,6 +636,7 @@ class MemberIterator {
unsigned size_; unsigned size_;
unsigned padding_; unsigned padding_;
unsigned alignment_; unsigned alignment_;
unsigned sawSuperclassBoundary;
MemberIterator(Object* type, bool skipSupers = false): MemberIterator(Object* type, bool skipSupers = false):
types(derivationChain(type)), types(derivationChain(type)),
@ -646,7 +647,8 @@ class MemberIterator {
offset_(BytesPerWord), offset_(BytesPerWord),
size_(0), size_(0),
padding_(0), padding_(0),
alignment_(BytesPerWord) alignment_(BytesPerWord),
sawSuperclassBoundary(true)
{ {
while (skipSupers and hasMore() and this->type != type) next(); while (skipSupers and hasMore() and this->type != type) next();
padding_ = 0; padding_ = 0;
@ -663,7 +665,10 @@ class MemberIterator {
offset_ = ((offset_ + size_) + (BytesPerWord - 1)) offset_ = ((offset_ + size_) + (BytesPerWord - 1))
& ~(BytesPerWord - 1); & ~(BytesPerWord - 1);
alignment_ = BytesPerWord; alignment_ = BytesPerWord;
sawSuperclassBoundary = true;
member = 0; member = 0;
} else {
sawSuperclassBoundary = false;
} }
type = car(types); type = car(types);
@ -1833,6 +1838,10 @@ writeMap(Output* out, Object* type)
for (MemberIterator it(type); it.hasMore();) { for (MemberIterator it(type); it.hasMore();) {
Object* m = it.next(); Object* m = it.next();
if (it.sawSuperclassBoundary) {
out->write("Type_pad, ");
}
switch (m->type) { switch (m->type) {
case Object::Scalar: { case Object::Scalar: {
out->write("Type_"); out->write("Type_");