Commit b32a53bd authored by Kenton Varda's avatar Kenton Varda

Fix bug where capability pointers were corrupted when 'transferred', e.g. using…

Fix bug where capability pointers were corrupted when 'transferred', e.g. using adoptWithCaveats() or truncate().
parent eae03397
...@@ -960,6 +960,30 @@ TEST(Capability, ThisCap) { ...@@ -960,6 +960,30 @@ TEST(Capability, ThisCap) {
EXPECT_EQ(-1, callCount); EXPECT_EQ(-1, callCount);
} }
TEST(Capability, TransferCap) {
kj::EventLoop loop;
kj::WaitScope waitScope(loop);
MallocMessageBuilder message;
auto root = message.initRoot<test::TestTransferCap>();
auto orphan = message.getOrphanage().newOrphan<test::TestTransferCap::Element>();
auto e = orphan.get();
e.setText("foo");
e.setCap(KJ_EXCEPTION(FAILED, "whatever"));
root.initList(1).adoptWithCaveats(0, kj::mv(orphan));
// This line used to throw due to capability pointers being incorrectly transferred.
auto cap = root.getList()[0].getCap();
cap.whenResolved().then([]() {
KJ_FAIL_EXPECT("didn't throw?");
}, [](kj::Exception&&) {
// success
}).wait(waitScope);
}
} // namespace } // namespace
} // namespace _ } // namespace _
} // namespace capnp } // namespace capnp
...@@ -868,11 +868,11 @@ struct WireHelpers { ...@@ -868,11 +868,11 @@ struct WireHelpers {
if (src->isNull()) { if (src->isNull()) {
memset(dst, 0, sizeof(WirePointer)); memset(dst, 0, sizeof(WirePointer));
} else if (src->kind() == WirePointer::FAR) { } else if (src->isPositional()) {
// Far pointers are position-independent, so we can just copy.
memcpy(dst, src, sizeof(WirePointer));
} else {
transferPointer(dstSegment, dst, srcSegment, src, src->target()); transferPointer(dstSegment, dst, srcSegment, src, src->target());
} else {
// Far and other pointers are position-independent, so we can just copy.
memcpy(dst, src, sizeof(WirePointer));
} }
} }
...@@ -2884,7 +2884,7 @@ bool OrphanBuilder::truncate(ElementCount size, bool isText) { ...@@ -2884,7 +2884,7 @@ bool OrphanBuilder::truncate(ElementCount size, bool isText) {
tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, size); tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, size);
segment->tryTruncate(oldEndWord, newEndWord); segment->tryTruncate(oldEndWord, newEndWord);
} else if (newEndWord <= oldEndWord) { } else if (newEndWord <= oldEndWord) {
// Apparently the old list was over-allecated? The word count is more than needed to store // Apparently the old list was over-allocated? The word count is more than needed to store
// the elements. This is "valid" but shouldn't happen in practice unless someone is toying // the elements. This is "valid" but shouldn't happen in practice unless someone is toying
// with us. // with us.
word* expectedEnd = target + oldSize * (elementWordCount / ELEMENTS); word* expectedEnd = target + oldSize * (elementWordCount / ELEMENTS);
...@@ -2898,7 +2898,6 @@ bool OrphanBuilder::truncate(ElementCount size, bool isText) { ...@@ -2898,7 +2898,6 @@ bool OrphanBuilder::truncate(ElementCount size, bool isText) {
tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, size); tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, size);
} else { } else {
// Need to re-allocate and transfer. // Need to re-allocate and transfer.
StructSize structSize(tag->structRef.dataSize.get(), tag->structRef.ptrCount.get());
OrphanBuilder replacement = initStructList(segment->getArena(), size, structSize); OrphanBuilder replacement = initStructList(segment->getArena(), size, structSize);
ListBuilder newList = replacement.asStructList(structSize); ListBuilder newList = replacement.asStructList(structSize);
......
...@@ -786,6 +786,14 @@ interface TestMoreStuff extends(TestCallOrder) { ...@@ -786,6 +786,14 @@ interface TestMoreStuff extends(TestCallOrder) {
# this can be used to test garbage collection. # this can be used to test garbage collection.
} }
struct TestTransferCap {
list @0 :List(Element);
struct Element {
text @0 :Text;
cap @1 :TestInterface;
}
}
interface TestKeywordMethods { interface TestKeywordMethods {
delete @0 (); delete @0 ();
class @1 (); class @1 ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment