[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)