capnproto / go-capnp

Cap'n Proto library and code generator for Go

Home Page:https://capnproto.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Setting a field in the data section of an unmarshaled struct created with a previous version that did not have any data section fields panics

xortive opened this issue · comments

commented
@0xbf613bdc8c0f6ae4;
struct OldStruct @0xee1b66e79b51bbbf {  # 0 bytes, 2 ptrs
  foo @0 :Data;  # ptr[0]
  bar @1 :Data;  # ptr[1]
}
struct NewStruct @0xb78a3d22d4285878 {  # 8 bytes, 2 ptrs
  foo @0 :Data;  # ptr[0]
  bar @1 :Data;  # ptr[1]
  newField @2 :Bool;  # bits[0, 1)
}

If one were to serialize OldStruct with go-capnp, deserialize it, and set newField, it will panic here:

panic("capnp: set field outside struct boundaries")

I think go-capnp should allocate a data section in this scenario to match the C++ implementation.

reproduction test:

func TestDataSectionBug(t *testing.T) {
	arena := capnp.SingleSegment(nil)
	oldMsg, seg, err := capnp.NewMessage(arena)
	assert.NoError(t, err)

	oldStruct, err := schema.NewOldStruct(seg)
	assert.NoError(t, err)

	err = oldStruct.SetFoo([]byte{255, 255})
	assert.NoError(t, err)
	err = oldStruct.SetFoo([]byte{127, 127})
	assert.NoError(t, err)

	oldSerialized, err := oldMsg.Marshal()
	assert.NoError(t, err)

	newMsg, err := capnp.Unmarshal(oldSerialized)
	assert.NoError(t, err)

	newStruct, err := schema.ReadRootNewStruct(newMsg)
	assert.NoError(t, err)

	newStruct.SetNewField(true) // panics
}