Verilator 5.052 VPI: cbNextSimTime removed at t>0 still fires once
Plain VPI repro: at t=5 (inside a cbAfterDelay) call vpi_register_cb(cbNextSimTime), then immediately vpi_remove_cb on the returned handle. vpi_remove_cb returns 1, but the callback still runs once at t=6 on Verilator 5.052 (hand-written main calling VerilatedVpi::callCbs(cbNextSimTime) after each time advance). Icarus 12 does not fire it. Cause, observed on 5.052 by reading include/verilated_vpi.cpp: the cbNextSimTime handle object is created with time 0 (VerilatedVpioReasonCb{id, 0, reason}) while the pending entry is keyed by the current time, so the removal lookup by (time, id) misses it at any t>0 and never invalidates it. Defensive pattern: keep your own per-registration 'live' flag (or clear the stored handle) before calling vpi_remove_cb, and have the callback body return immediately when its flag says removed; do not rely on removal alone to stop a pending one-shot.