e100_nic_realize() registers a system reset handler via qemu_register_reset(nic_reset, s), but pci_nic_uninit() never unregisters it. After the device is hot-unplugged, the LegacyReset object stored in the root reset container still holds the raw pointer to the freed EEPRO100State, so the next system reset invokes nic_reset() on freed memory.
Instead, define a reset phase on the device itself: assign phases.hold in eepro100_class_init() to a wrapper around nic_reset(). The device is already part of the resettable tree via its parent bus (TYPE_DEVICE implements the Resettable interface), so no explicit registration is needed, and the reset state is automatically dropped when the device is unplugged. This follows the approach used by the e1000, e1000e and igb emulations. Reported-by: Hui Peng <[email protected]> Suggested-by: Peter Maydell <[email protected]> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4058 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4510 Signed-off-by: Stefan Weil <[email protected]> --- Note that I used AI assistance to create and test the patch. I am not shure whether this is acceptable to small and rather mechnical changes like in this case. The Reported-by for issue 4058 was not added because I did not find the required full name and email of the reporter. Stefan W. hw/net/eepro100.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index aaa3eb60f8a..e1cd8346941 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -617,6 +617,13 @@ static void nic_reset(void *opaque) nic_selective_reset(s); } +static void eepro100_reset_hold(Object *obj, ResetType type) +{ + EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, PCI_DEVICE(obj)); + + nic_reset(s); +} + #if defined(DEBUG_EEPRO100) static const char * const e100_reg[PCI_IO_SIZE / 4] = { "Command/Status", @@ -1881,8 +1888,6 @@ static void e100_nic_realize(PCIDevice *pci_dev, Error **errp) qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); TRACE(OTHER, logout("%s\n", qemu_get_queue(s->nic)->info_str)); - qemu_register_reset(nic_reset, s); - s->vmstate = g_memdup(&vmstate_eepro100, sizeof(vmstate_eepro100)); s->vmstate->name = qemu_get_queue(s->nic)->model; vmstate_register_any(VMSTATE_IF(&pci_dev->qdev), s->vmstate, s); @@ -2064,6 +2069,7 @@ static void eepro100_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); E100PCIDeviceInfo *info; info = eepro100_get_class_by_name(object_class_get_name(klass)); @@ -2080,6 +2086,7 @@ static void eepro100_class_init(ObjectClass *klass, const void *data) k->revision = info->revision; k->subsystem_vendor_id = info->subsystem_vendor_id; k->subsystem_id = info->subsystem_id; + rc->phases.hold = eepro100_reset_hold; } static void eepro100_register_types(void) -- 2.54.0 (Apple Git-157)
