diff --git a/libs/iovm/source/IoList.c b/libs/iovm/source/IoList.c index b62b25809..ed689ad72 100644 --- a/libs/iovm/source/IoList.c +++ b/libs/iovm/source/IoList.c @@ -1116,7 +1116,6 @@ IO_METHOD(IoList, fromEncodedList) { } uint32_t id = *((uint32_t *)(d + index)); IoMessage_setCachedArg_to_(rm, 0, IONUMBER(id)); - IoMessage_setCachedArg_to_(rm, 0, IONIL(self)); index += sizeof(uint32_t); @@ -1124,6 +1123,7 @@ IO_METHOD(IoList, fromEncodedList) { IoObject *result = IoObject_perform(locals, locals, rm); List_append_(list, result); } + IoMessage_setCachedArg_to_(rm, 0, IONIL(self)); } else { IOASSERT(0, "unrecognized encoded type"); } diff --git a/libs/iovm/tests/correctness/ListTest.io b/libs/iovm/tests/correctness/ListTest.io index 0cb330efe..d3843dbb4 100644 --- a/libs/iovm/tests/correctness/ListTest.io +++ b/libs/iovm/tests/correctness/ListTest.io @@ -492,6 +492,41 @@ ListTest := UnitTest clone do( assertEquals(t, t asEncodedList asDecodedList) ) + # Regression for IoList.c REFERENCE decode: objectForReferenceId must receive + # IONUMBER(id) (clear cached arg only after perform). Same id=42 as bug.io. + # Uses manual bytes (IOLIST_ENCODING_TYPE_REFERENCE + uint32 LE) so this test + # does not depend on asEncodedList or Lobby referenceIdForObject under doString. + testEncodedListFromEncodedListReferenceId := method( + ref := Object clone + hadObj := Lobby hasLocalSlot("objectForReferenceId") + hadStash := Lobby hasLocalSlot("referenceRoundTripRef") + prevObj := if(hadObj, Lobby getSlot("objectForReferenceId"), nil) + prevStash := if(hadStash, Lobby getSlot("referenceRoundTripRef"), nil) + + Lobby referenceRoundTripRef := ref + Lobby do( + objectForReferenceId := method(id, + if(id isIdenticalTo(42), Lobby getSlot("referenceRoundTripRef"), nil) + ) + ) + + enc := ("" asMutable) + enc appendSeq(3 asCharacter, 0 asCharacter, 0 asCharacter) + enc appendSeq(42 asCharacter, 0 asCharacter, 0 asCharacter, 0 asCharacter) + dec := List fromEncodedList(enc) + assertEquals(1, dec size) + assertTrue(dec first isIdenticalTo(ref)) + + if(hadObj, + Lobby do(objectForReferenceId := prevObj), + Lobby removeSlot("objectForReferenceId") + ) + if(hadStash, + Lobby do(referenceRoundTripRef := prevStash), + Lobby removeSlot("referenceRoundTripRef") + ) + ) + testSlice := method( a := list(1, 2, 3, 4, 5, 6) assertEquals(a, a slice(0))