Skip to content

Commit

Permalink
qdev: Protect device-list-properties against broken devices
Browse files Browse the repository at this point in the history
Several devices don't survive object_unref(object_new(T)): they crash
or hang during cleanup, or they leave dangling pointers behind.

This breaks at least device-list-properties, because
qmp_device_list_properties() needs to create a device to find its
properties.  Broken in commit f4eb32b "qmp: show QOM properties in
device-list-properties", v2.1.  Example reproducer:

    $ qemu-system-aarch64 -nodefaults -display none -machine none -S -qmp stdio
    {"QMP": {"version": {"qemu": {"micro": 50, "minor": 4, "major": 2}, "package": ""}, "capabilities": []}}
    { "execute": "qmp_capabilities" }
    {"return": {}}
    { "execute": "device-list-properties", "arguments": { "typename": "pxa2xx-pcmcia" } }
    qemu-system-aarch64: /home/armbru/work/qemu/memory.c:1307: memory_region_finalize: Assertion `((&mr->subregions)->tqh_first == ((void *)0))' failed.
    Aborted (core dumped)
    [Exit 134 (SIGABRT)]

Unfortunately, I can't fix the problems in these devices right now.
Instead, add DeviceClass member cannot_destroy_with_object_finalize_yet
to mark them:

* Hang during cleanup (didn't debug, so I can't say why):
  "realview_pci", "versatile_pci".

* Dangling pointer in cpus: most CPUs, plus "allwinner-a10", "digic",
  "fsl,imx25", "fsl,imx31", "xlnx,zynqmp", because they create such
  CPUs

* Assert kvm_enabled(): "host-x86_64-cpu", host-i386-cpu",
  "host-powerpc64-cpu", "host-embedded-powerpc-cpu",
  "host-powerpc-cpu" (the powerpc ones can't currently reach the
  assertion, because the CPUs are only registered when KVM is enabled,
  but the assertion is arguably in the wrong place all the same)

Make qmp_device_list_properties() fail cleanly when the device is so
marked.  This improves device-list-properties from "crashes, hangs or
leaves dangling pointers behind" to "fails".  Not a complete fix, just
a better-than-nothing work-around.  In the above reproducer,
device-list-properties now fails with "Can't list properties of device
'pxa2xx-pcmcia'".

This also protects -device FOO,help, which uses the same machinery
since commit ef52358 "qdev-monitor: include QOM properties in -device
FOO, help output", v2.2.  Example reproducer:

    $ qemu-system-aarch64 -machine none -device pxa2xx-pcmcia,help

Before:

    qemu-system-aarch64: .../memory.c:1307: memory_region_finalize: Assertion `((&mr->subregions)->tqh_first == ((void *)0))' failed.

After:

    Can't list properties of device 'pxa2xx-pcmcia'

Cc: "Andreas Färber" <[email protected]>
Cc: "Edgar E. Iglesias" <[email protected]>
Cc: Alexander Graf <[email protected]>
Cc: Anthony Green <[email protected]>
Cc: Aurelien Jarno <[email protected]>
Cc: Bastian Koppelmann <[email protected]>
Cc: Blue Swirl <[email protected]>
Cc: Eduardo Habkost <[email protected]>
Cc: Guan Xuetao <[email protected]>
Cc: Jia Liu <[email protected]>
Cc: Leon Alrae <[email protected]>
Cc: Mark Cave-Ayland <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Michael Walle <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Peter Maydell <[email protected]>
Cc: Richard Henderson <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Markus Armbruster <[email protected]>
Reviewed-by: Eduardo Habkost <[email protected]>
Message-Id: <[email protected]>
  • Loading branch information
Markus Armbruster committed Oct 9, 2015
1 parent edb1523 commit 4c315c2
Show file tree
Hide file tree
Showing 27 changed files with 185 additions and 27 deletions.
6 changes: 6 additions & 0 deletions hw/arm/allwinner-a10.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ static void aw_a10_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);

dc->realize = aw_a10_realize;

/*
* Reason: creates an ARM CPU, thus use after free(), see
* arm_cpu_class_init()
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo aw_a10_type_info = {
Expand Down
6 changes: 6 additions & 0 deletions hw/arm/digic.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ static void digic_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);

dc->realize = digic_realize;

/*
* Reason: creates an ARM CPU, thus use after free(), see
* arm_cpu_class_init()
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo digic_type_info = {
Expand Down
6 changes: 6 additions & 0 deletions hw/arm/fsl-imx25.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ static void fsl_imx25_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);

dc->realize = fsl_imx25_realize;

/*
* Reason: creates an ARM CPU, thus use after free(), see
* arm_cpu_class_init()
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo fsl_imx25_type_info = {
Expand Down
6 changes: 6 additions & 0 deletions hw/arm/fsl-imx31.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@ static void fsl_imx31_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);

dc->realize = fsl_imx31_realize;

/*
* Reason: creates an ARM CPU, thus use after free(), see
* arm_cpu_class_init()
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo fsl_imx31_type_info = {
Expand Down
6 changes: 6 additions & 0 deletions hw/arm/xlnx-zynqmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,12 @@ static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)

dc->props = xlnx_zynqmp_props;
dc->realize = xlnx_zynqmp_realize;

/*
* Reason: creates an ARM CPU, thus use after free(), see
* arm_cpu_class_init()
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo xlnx_zynqmp_type_info = {
Expand Down
11 changes: 11 additions & 0 deletions hw/pci-host/versatile.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ static void pci_vpb_class_init(ObjectClass *klass, void *data)
dc->reset = pci_vpb_reset;
dc->vmsd = &pci_vpb_vmstate;
dc->props = pci_vpb_properties;
/* Reason: object_unref() hangs */
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo pci_vpb_info = {
Expand All @@ -521,10 +523,19 @@ static void pci_realview_init(Object *obj)
s->mem_win_size[2] = 0x08000000;
}

static void pci_realview_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);

/* Reason: object_unref() hangs */
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo pci_realview_info = {
.name = "realview_pci",
.parent = TYPE_VERSATILE_PCI,
.instance_init = pci_realview_init,
.class_init = pci_realview_class_init,
};

static void versatile_pci_register_types(void)
Expand Down
13 changes: 13 additions & 0 deletions include/hw/qdev-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ typedef struct DeviceClass {
* TODO remove once we're there
*/
bool cannot_instantiate_with_device_add_yet;
/*
* Does this device model survive object_unref(object_new(TNAME))?
* All device models should, and this flag shouldn't exist. Some
* devices crash in object_new(), some crash or hang in
* object_unref(). Makes introspecting properties with
* qmp_device_list_properties() dangerous. Bad, because it's used
* by -device FOO,help. This flag serves to protect that code.
* It should never be set without a comment explaining why it is
* set.
* TODO remove once we're there
*/
bool cannot_destroy_with_object_finalize_yet;

bool hotpluggable;

/* callbacks */
Expand Down
5 changes: 5 additions & 0 deletions qmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,11 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
return NULL;
}

if (DEVICE_CLASS(klass)->cannot_destroy_with_object_finalize_yet) {
error_setg(errp, "Can't list properties of device '%s'", typename);
return NULL;
}

obj = object_new(typename);

QTAILQ_FOREACH(prop, &obj->properties, node) {
Expand Down
7 changes: 7 additions & 0 deletions target-alpha/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
dc->vmsd = &vmstate_alpha_cpu;
#endif
cc->gdb_num_core_regs = 67;

/*
* Reason: alpha_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo alpha_cpu_type_info = {
Expand Down
11 changes: 11 additions & 0 deletions target-arm/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,17 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->debug_excp_handler = arm_debug_excp_handler;

cc->disas_set_info = arm_disas_set_info;

/*
* Reason: arm_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*
* Once this is fixed, the devices that create ARM CPUs should be
* updated not to set cannot_destroy_with_object_finalize_yet,
* unless they still screw up something else.
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static void cpu_register(const ARMCPUInfo *info)
Expand Down
7 changes: 7 additions & 0 deletions target-cris/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,13 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_stop_before_watchpoint = true;

cc->disas_set_info = cris_disas_set_info;

/*
* Reason: cris_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo cris_cpu_type_info = {
Expand Down
8 changes: 8 additions & 0 deletions target-i386/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,8 @@ static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
*/

dc->props = host_x86_cpu_properties;
/* Reason: host_x86_cpu_initfn() dies when !kvm_enabled() */
dc->cannot_destroy_with_object_finalize_yet = true;
}

static void host_x86_cpu_initfn(Object *obj)
Expand Down Expand Up @@ -3190,6 +3192,12 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
#endif
cc->cpu_exec_enter = x86_cpu_exec_enter;
cc->cpu_exec_exit = x86_cpu_exec_exit;

/*
* Reason: x86_cpu_initfn() calls cpu_exec_init(), which saves the
* object in cpus -> dangling pointer after final object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo x86_cpu_type_info = {
Expand Down
7 changes: 7 additions & 0 deletions target-lm32/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_num_core_regs = 32 + 7;
cc->gdb_stop_before_watchpoint = true;
cc->debug_excp_handler = lm32_debug_excp_handler;

/*
* Reason: lm32_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static void lm32_register_cpu_type(const LM32CPUInfo *info)
Expand Down
7 changes: 7 additions & 0 deletions target-m68k/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,13 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
dc->vmsd = &vmstate_m68k_cpu;
cc->gdb_num_core_regs = 18;
cc->gdb_core_xml_file = "cf-core.xml";

/*
* Reason: m68k_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static void register_cpu_type(const M68kCPUInfo *info)
Expand Down
6 changes: 6 additions & 0 deletions target-microblaze/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_num_core_regs = 32 + 5;

cc->disas_set_info = mb_disas_set_info;

/*
* Reason: mb_cpu_initfn() calls cpu_exec_init(), which saves the
* object in cpus -> dangling pointer after final object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo mb_cpu_type_info = {
Expand Down
7 changes: 7 additions & 0 deletions target-mips/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)

cc->gdb_num_core_regs = 73;
cc->gdb_stop_before_watchpoint = true;

/*
* Reason: mips_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo mips_cpu_type_info = {
Expand Down
7 changes: 7 additions & 0 deletions target-moxie/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ static void moxie_cpu_class_init(ObjectClass *oc, void *data)
cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_moxie_cpu;
#endif

/*
* Reason: moxie_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static void moxielite_initfn(Object *obj)
Expand Down
7 changes: 7 additions & 0 deletions target-openrisc/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
dc->vmsd = &vmstate_openrisc_cpu;
#endif
cc->gdb_num_core_regs = 32 + 3;

/*
* Reason: openrisc_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static void cpu_register(const OpenRISCCPUInfo *info)
Expand Down
4 changes: 4 additions & 0 deletions target-ppc/kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2192,6 +2192,7 @@ static void kvmppc_host_cpu_initfn(Object *obj)

static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
uint32_t vmx = kvmppc_get_vmx();
uint32_t dfp = kvmppc_get_dfp();
Expand All @@ -2218,6 +2219,9 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
if (icache_size != -1) {
pcc->l1_icache_size = icache_size;
}

/* Reason: kvmppc_host_cpu_initfn() dies when !kvm_enabled() */
dc->cannot_destroy_with_object_finalize_yet = true;
}

bool kvmppc_has_cap_epr(void)
Expand Down
7 changes: 7 additions & 0 deletions target-s390x/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,13 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
#endif
cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
cc->gdb_core_xml_file = "s390x-core64.xml";

/*
* Reason: s390_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo s390_cpu_type_info = {
Expand Down
7 changes: 7 additions & 0 deletions target-sh4/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
#endif
dc->vmsd = &vmstate_sh_cpu;
cc->gdb_num_core_regs = 59;

/*
* Reason: superh_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo superh_cpu_type_info = {
Expand Down
7 changes: 7 additions & 0 deletions target-sparc/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,13 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
#else
cc->gdb_num_core_regs = 72;
#endif

/*
* Reason: sparc_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo sparc_cpu_type_info = {
Expand Down
7 changes: 7 additions & 0 deletions target-tilegx/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ static void tilegx_cpu_class_init(ObjectClass *oc, void *data)
cc->set_pc = tilegx_cpu_set_pc;
cc->handle_mmu_fault = tilegx_cpu_handle_mmu_fault;
cc->gdb_num_core_regs = 0;

/*
* Reason: tilegx_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo tilegx_cpu_type_info = {
Expand Down
6 changes: 6 additions & 0 deletions target-tricore/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data)
cc->set_pc = tricore_cpu_set_pc;
cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb;

/*
* Reason: tricore_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static void cpu_register(const TriCoreCPUInfo *info)
Expand Down
7 changes: 7 additions & 0 deletions target-unicore32/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data)
cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug;
#endif
dc->vmsd = &vmstate_uc32_cpu;

/*
* Reason: uc32_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static void uc32_register_cpu_type(const UniCore32CPUInfo *info)
Expand Down
7 changes: 7 additions & 0 deletions target-xtensa/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
#endif
cc->debug_excp_handler = xtensa_breakpoint_handler;
dc->vmsd = &vmstate_xtensa_cpu;

/*
* Reason: xtensa_cpu_initfn() calls cpu_exec_init(), which saves
* the object in cpus -> dangling pointer after final
* object_unref().
*/
dc->cannot_destroy_with_object_finalize_yet = true;
}

static const TypeInfo xtensa_cpu_type_info = {
Expand Down
Loading

0 comments on commit 4c315c2

Please sign in to comment.