Permalink
Browse files

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.
  • Loading branch information...
1 parent 1f6051b commit bb86500155f366f62e945b88b4997cc7917dec39 @dicej dicej committed Jan 6, 2014
Showing with 45 additions and 35 deletions.
  1. +3 −9 src/machine.cpp
  2. +32 −25 src/tools/bootimage-generator/main.cpp
  3. +10 −1 src/tools/type-generator/main.cpp
View
@@ -1292,9 +1292,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
unsigned size = fieldSize(t, code);
if (flags & ACC_STATIC) {
- while (staticOffset % size) {
- ++ staticOffset;
- }
+ staticOffset = pad(staticOffset, size);
fieldOffset(t, field) = staticOffset;
@@ -1308,9 +1306,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
classVmFlags(t, class_) |= HasFinalMemberFlag;
}
- while (memberOffset % size) {
- ++ memberOffset;
- }
+ memberOffset = pad(memberOffset, size);
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) {
unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]);
- while (offset % size) {
- ++ offset;
- }
+ offset = pad(offset, size);
unsigned value = intArrayBody(t, staticValueTable, i);
if (value) {
@@ -48,6 +48,7 @@ const bool DebugNativeTarget = false;
enum Type {
Type_none,
+ Type_pad,
Type_object,
Type_object_nogc,
Type_int8_t,
@@ -517,9 +518,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
}
if (fieldFlags(t, field) & ACC_STATIC) {
- while (targetStaticOffset % targetSize) {
- ++ targetStaticOffset;
- }
+ targetStaticOffset = pad(targetStaticOffset, targetSize);
buildStaticOffset = fieldOffset(t, field);
@@ -531,9 +530,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
++ staticIndex;
} else {
- while (targetMemberOffset % targetSize) {
- ++ targetMemberOffset;
- }
+ targetMemberOffset = pad(targetMemberOffset, targetSize);
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) {
Type* source = types[i];
- unsigned count = 0;
- while (source[count] != Type_none) {
- ++ count;
+ unsigned typeCount = 0;
+ unsigned fieldCount = 1;
+ 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,
BytesPerWord, 0, TargetBytesPerWord);
@@ -1356,8 +1356,15 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp
Type type = Type_none;
unsigned buildSize = 0;
unsigned targetSize = 0;
- for (unsigned j = 1; j < count; ++j) {
- switch (source[j - 1]) {
+ unsigned fieldOffset = 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:
type = Type_object;
buildSize = BytesPerWord;
@@ -1412,21 +1419,21 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp
default: abort(t);
}
- if (source[j - 1] == Type_array) {
+ if (source[j] == Type_array) {
sawArray = true;
}
- if (not sawArray) {
- while (buildOffset % buildSize) {
- ++ buildOffset;
- }
+ if (type == Type_pad) {
+ buildOffset = pad(buildOffset, BytesPerWord);
- while (targetOffset % targetSize) {
- ++ targetOffset;
- }
+ targetOffset = pad(targetOffset, TargetBytesPerWord);
+ } else if (not sawArray) {
+ buildOffset = pad(buildOffset, buildSize);
+
+ targetOffset = pad(targetOffset, targetSize);
- init(new (RUNTIME_ARRAY_BODY(fields) + j) Field, type, buildOffset,
- buildSize, targetOffset, targetSize);
+ init(new (RUNTIME_ARRAY_BODY(fields) + (fieldOffset++)) Field, type,
+ buildOffset, buildSize, targetOffset, targetSize);
buildOffset += buildSize;
targetOffset += targetSize;
@@ -1438,12 +1445,12 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp
unsigned buildArrayElementSize;
unsigned targetArrayElementSize;
if (sawArray) {
- fixedFieldCount = count - 2;
+ fixedFieldCount = fieldCount - 2;
arrayElementType = type;
buildArrayElementSize = buildSize;
targetArrayElementSize = targetSize;
} else {
- fixedFieldCount = count;
+ fixedFieldCount = fieldCount;
arrayElementType = Type_none;
buildArrayElementSize = 0;
targetArrayElementSize = 0;
@@ -636,6 +636,7 @@ class MemberIterator {
unsigned size_;
unsigned padding_;
unsigned alignment_;
+ unsigned sawSuperclassBoundary;
MemberIterator(Object* type, bool skipSupers = false):
types(derivationChain(type)),
@@ -646,7 +647,8 @@ class MemberIterator {
offset_(BytesPerWord),
size_(0),
padding_(0),
- alignment_(BytesPerWord)
+ alignment_(BytesPerWord),
+ sawSuperclassBoundary(true)
{
while (skipSupers and hasMore() and this->type != type) next();
padding_ = 0;
@@ -663,7 +665,10 @@ class MemberIterator {
offset_ = ((offset_ + size_) + (BytesPerWord - 1))
& ~(BytesPerWord - 1);
alignment_ = BytesPerWord;
+ sawSuperclassBoundary = true;
member = 0;
+ } else {
+ sawSuperclassBoundary = false;
}
type = car(types);
@@ -1833,6 +1838,10 @@ writeMap(Output* out, Object* type)
for (MemberIterator it(type); it.hasMore();) {
Object* m = it.next();
+ if (it.sawSuperclassBoundary) {
+ out->write("Type_pad, ");
+ }
+
switch (m->type) {
case Object::Scalar: {
out->write("Type_");

0 comments on commit bb86500

Please sign in to comment.