Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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 #562

Open
xortive opened this issue Apr 29, 2024 · 0 comments

Comments

@xortive
Copy link

xortive commented Apr 29, 2024

@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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant