fix reading of upgraded pointer lists
This commit is contained in:
parent
257f646ec1
commit
3e2034f45d
4 changed files with 85 additions and 21 deletions
|
@ -113,6 +113,38 @@ public class EncodingTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@org.junit.Test
|
||||||
|
public void testUpgradeStructReadAsOld() {
|
||||||
|
MessageBuilder builder = new MessageBuilder();
|
||||||
|
Test.TestAnyPointer.Builder root = builder.initRoot(Test.TestAnyPointer.factory);
|
||||||
|
|
||||||
|
{
|
||||||
|
Test.TestNewVersion.Builder newVersion = root.getAnyPointerField().initAs(Test.TestNewVersion.factory);
|
||||||
|
newVersion.setOld1(123);
|
||||||
|
newVersion.setOld2("foo");
|
||||||
|
Test.TestNewVersion.Builder sub = newVersion.initOld3();
|
||||||
|
sub.setOld1(456);
|
||||||
|
sub.setOld2("bar");
|
||||||
|
|
||||||
|
StructList.Builder<Test.TestNewVersion.UpgradedFromText.Builder> names =
|
||||||
|
newVersion.initOld4(2);
|
||||||
|
|
||||||
|
names.get(0).setTextField("alice");
|
||||||
|
names.get(1).setTextField("bob");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Test.TestOldVersion.Reader oldVersion = root.getAnyPointerField().asReader().getAs(Test.TestOldVersion.factory);
|
||||||
|
Assert.assertEquals(oldVersion.getOld1(), 123);
|
||||||
|
Assert.assertEquals(oldVersion.getOld2().toString(), "foo");
|
||||||
|
|
||||||
|
TextList.Reader names = oldVersion.getOld4();
|
||||||
|
Assert.assertEquals(names.size(), 2);
|
||||||
|
Assert.assertEquals("alice", names.get(0).toString());
|
||||||
|
Assert.assertEquals("bob", names.get(1).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@org.junit.Test
|
@org.junit.Test
|
||||||
public void testUpgradeStructInBuilder() {
|
public void testUpgradeStructInBuilder() {
|
||||||
MessageBuilder builder = new MessageBuilder();
|
MessageBuilder builder = new MessageBuilder();
|
||||||
|
|
|
@ -319,6 +319,7 @@ struct TestOldVersion {
|
||||||
old1 @0 :Int64;
|
old1 @0 :Int64;
|
||||||
old2 @1 :Text;
|
old2 @1 :Text;
|
||||||
old3 @2 :TestOldVersion;
|
old3 @2 :TestOldVersion;
|
||||||
|
old4 @3 :List(Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestNewVersion {
|
struct TestNewVersion {
|
||||||
|
@ -326,9 +327,16 @@ struct TestNewVersion {
|
||||||
old1 @0 :Int64;
|
old1 @0 :Int64;
|
||||||
old2 @1 :Text;
|
old2 @1 :Text;
|
||||||
old3 @2 :TestNewVersion;
|
old3 @2 :TestNewVersion;
|
||||||
new1 @3 :Int64 = 987;
|
|
||||||
new2 @4 :Text = "baz";
|
struct UpgradedFromText {
|
||||||
new3 @5 :Data;
|
textField @0 :Text;
|
||||||
|
int32Field @1 :Int32;
|
||||||
|
dataField @2 :Data;
|
||||||
|
}
|
||||||
|
old4 @3 :List(UpgradedFromText);
|
||||||
|
new1 @4 :Int64 = 987;
|
||||||
|
new2 @5 :Text = "baz";
|
||||||
|
new3 @6 :TestDefaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestGenerics(Foo, Bar) {
|
struct TestGenerics(Foo, Bar) {
|
||||||
|
|
|
@ -131,9 +131,13 @@ public class ListReader extends CapTableReader.ReaderContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T> T _getPointerElement(FromPointerReader<T> factory, int index) {
|
protected <T> T _getPointerElement(FromPointerReader<T> factory, int index) {
|
||||||
return factory.fromPointerReader(this.segment,
|
return factory.fromPointerReader(
|
||||||
|
this.segment,
|
||||||
this.capTable,
|
this.capTable,
|
||||||
(this.ptr + (int)((long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD,
|
(this.ptr +
|
||||||
|
(this.structDataSize / Constants.BITS_PER_BYTE) +
|
||||||
|
(int)((long)index * this.step / Constants.BITS_PER_BYTE))
|
||||||
|
/ Constants.BYTES_PER_WORD,
|
||||||
this.nestingLimit);
|
this.nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1255,8 +1255,8 @@ final class WireHelpers {
|
||||||
throw new DecodeException("Message contains non-list pointer where list was expected.");
|
throw new DecodeException("Message contains non-list pointer where list was expected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte elementSize = ListPointer.elementSize(resolved.ref);
|
byte oldSize = ListPointer.elementSize(resolved.ref);
|
||||||
switch (elementSize) {
|
switch (oldSize) {
|
||||||
case ElementSize.INLINE_COMPOSITE : {
|
case ElementSize.INLINE_COMPOSITE : {
|
||||||
int wordCount = ListPointer.inlineCompositeWordCount(resolved.ref);
|
int wordCount = ListPointer.inlineCompositeWordCount(resolved.ref);
|
||||||
|
|
||||||
|
@ -1269,7 +1269,8 @@ final class WireHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = WirePointer.inlineCompositeListElementCount(tag);
|
int size = WirePointer.inlineCompositeListElementCount(tag);
|
||||||
|
int dataSize = StructPointer.dataSize(tag);
|
||||||
|
short ptrCount = (short)StructPointer.ptrCount(tag);
|
||||||
int wordsPerElement = StructPointer.wordSize(tag);
|
int wordsPerElement = StructPointer.wordSize(tag);
|
||||||
|
|
||||||
if ((long)size * wordsPerElement > wordCount) {
|
if ((long)size * wordsPerElement > wordCount) {
|
||||||
|
@ -1282,14 +1283,33 @@ final class WireHelpers {
|
||||||
resolved.segment.arena.checkReadLimit(size);
|
resolved.segment.arena.checkReadLimit(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO check whether the size is compatible
|
switch (expectedElementSize) {
|
||||||
|
case ElementSize.VOID: break;
|
||||||
|
case ElementSize.BIT: {
|
||||||
|
throw new DecodeException("Found struct list where bit list was expected");
|
||||||
|
}
|
||||||
|
case ElementSize.BYTE:
|
||||||
|
case ElementSize.TWO_BYTES:
|
||||||
|
case ElementSize.FOUR_BYTES:
|
||||||
|
case ElementSize.EIGHT_BYTES:
|
||||||
|
if (dataSize == 0) {
|
||||||
|
throw new DecodeException(
|
||||||
|
"Expected a primitive list, but got a list of pointer-only structs");
|
||||||
|
}
|
||||||
|
case ElementSize.POINTER:
|
||||||
|
if (ptrCount == 0) {
|
||||||
|
throw new DecodeException(
|
||||||
|
"Expected a pointer list, but got a list of data-only structs");
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
return factory.constructReader(resolved.segment, capTable,
|
return factory.constructReader(resolved.segment,
|
||||||
ptr * Constants.BYTES_PER_WORD,
|
ptr * Constants.BYTES_PER_WORD,
|
||||||
size,
|
size,
|
||||||
wordsPerElement * Constants.BITS_PER_WORD,
|
wordsPerElement * Constants.BITS_PER_WORD,
|
||||||
StructPointer.dataSize(tag) * Constants.BITS_PER_WORD,
|
dataSize * Constants.BITS_PER_WORD,
|
||||||
(short)StructPointer.ptrCount(tag),
|
ptrCount,
|
||||||
nestingLimit - 1);
|
nestingLimit - 1);
|
||||||
}
|
}
|
||||||
default : {
|
default : {
|
||||||
|
@ -1297,8 +1317,8 @@ final class WireHelpers {
|
||||||
//# lists can also be interpreted as struct lists. We
|
//# lists can also be interpreted as struct lists. We
|
||||||
//# need to compute the data size and pointer count for
|
//# need to compute the data size and pointer count for
|
||||||
//# such structs.
|
//# such structs.
|
||||||
int dataSize = ElementSize.dataBitsPerElement(elementSize);
|
int dataSize = ElementSize.dataBitsPerElement(oldSize);
|
||||||
int pointerCount = ElementSize.pointersPerElement(elementSize);
|
int pointerCount = ElementSize.pointersPerElement(oldSize);
|
||||||
int elementCount = ListPointer.elementCount(resolved.ref);
|
int elementCount = ListPointer.elementCount(resolved.ref);
|
||||||
int step = dataSize + pointerCount * Constants.BITS_PER_POINTER;
|
int step = dataSize + pointerCount * Constants.BITS_PER_POINTER;
|
||||||
|
|
||||||
|
@ -1309,7 +1329,7 @@ final class WireHelpers {
|
||||||
throw new DecodeException("Message contains out-of-bounds list pointer");
|
throw new DecodeException("Message contains out-of-bounds list pointer");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementSize == ElementSize.VOID) {
|
if (oldSize == ElementSize.VOID) {
|
||||||
// Watch out for lists of void, which can claim to be arbitrarily large without
|
// Watch out for lists of void, which can claim to be arbitrarily large without
|
||||||
// having sent actual data.
|
// having sent actual data.
|
||||||
resolved.segment.arena.checkReadLimit(elementCount);
|
resolved.segment.arena.checkReadLimit(elementCount);
|
||||||
|
|
Loading…
Reference in a new issue