[port] remove incorrect assertion in CancelQueued
ZX-4206 is cause by an incorrect assertion introduced in a previous
change, that assumed that packets removed by CancelQueued cannot be
ephemeral. The reasoning was that CancelQueued is used with a handle
and ephemeral packets cannot contain a handle.
But CancelQueued is also used for packets added by hypervisor traps,
and these packets are ephemeral and not associated to a handle, thus
CancelQueued is called with a null handle, and we panic.
This change removes the assertion.
TEST=added guest_set_trap_with_bell_drop, crashes on patchset #1
Change-Id: Ia6659f4ee4d97780619bead3b8058d61e79e72b8
diff --git a/zircon/kernel/object/port_dispatcher.cpp b/zircon/kernel/object/port_dispatcher.cpp
index a6eb23a..dc74218 100644
--- a/zircon/kernel/object/port_dispatcher.cpp
+++ b/zircon/kernel/object/port_dispatcher.cpp
@@ -483,7 +483,9 @@
for (auto it = packets_.begin(); it != packets_.end();) {
if ((it->handle == handle) && (it->key() == key)) {
auto to_remove = it++;
- DEBUG_ASSERT(!to_remove->is_ephemeral());
+ if (to_remove->is_ephemeral()) {
+ --num_ephemeral_packets_;
+ }
// Destroyed as we go around the loop.
ktl::unique_ptr<const PortObserver> observer =
ktl::move(packets_.erase(to_remove)->observer);
diff --git a/zircon/system/utest/hypervisor/guest.cpp b/zircon/system/utest/hypervisor/guest.cpp
index 67dfade..160799ef 100644
--- a/zircon/system/utest/hypervisor/guest.cpp
+++ b/zircon/system/utest/hypervisor/guest.cpp
@@ -460,6 +460,37 @@
END_TEST;
}
+// Test for ZX-4206.
+static bool guest_set_trap_with_bell_drop() {
+ BEGIN_TEST;
+
+ // Build the port before test so test is destructed first.
+ zx::port port;
+ ASSERT_EQ(zx::port::create(0, &port), ZX_OK);
+
+ test_t test;
+ ASSERT_TRUE(setup(&test, guest_set_trap_start, guest_set_trap_end));
+ if (!test.supported) {
+ // The hypervisor isn't supported, so don't run the test.
+ return true;
+ }
+
+ // Trap on access of TRAP_ADDR.
+ ASSERT_EQ(test.guest.set_trap(ZX_GUEST_TRAP_BELL, TRAP_ADDR, PAGE_SIZE, port, kTrapKey), ZX_OK);
+
+ zx_port_packet_t packet = {};
+ ASSERT_EQ(test.vcpu.resume(&packet), ZX_OK);
+ EXPECT_EQ(packet.type, ZX_PKT_TYPE_GUEST_MEM);
+ EXPECT_EQ(packet.guest_mem.addr, EXIT_TEST_ADDR);
+
+ ASSERT_TRUE(teardown(&test));
+
+ // The guest in test is destructed with one packet still queued on the
+ // port. This should work correctly.
+
+ END_TEST;
+}
+
#ifdef __aarch64__
static bool vcpu_wfi() {
@@ -905,6 +936,7 @@
RUN_TEST(vcpu_interrupt)
RUN_TEST(guest_set_trap_with_mem)
RUN_TEST(guest_set_trap_with_bell)
+RUN_TEST(guest_set_trap_with_bell_drop)
#if __aarch64__
RUN_TEST(vcpu_wfi)
RUN_TEST(vcpu_wfi_pending_interrupt)