1 | I saw various sanitizer errors when running check-qtest-ppc64. While | 1 | I saw various sanitizer errors when running check-qtest-ppc64. While |
---|---|---|---|
2 | I could just turn off sanitizers, I decided to tackle them this time. | 2 | I could just turn off sanitizers, I decided to tackle them this time. |
3 | 3 | ||
4 | Unfortunately, GLib does not free test data in some cases so some | 4 | Unfortunately, GLib versions older than 2.81.0 do not free test data in |
5 | sanitizer errors remain. All sanitizer errors will be gone with this | 5 | some cases so some sanitizer errors remain. All sanitizer errors will be |
6 | patch series combined with the following change for GLib: | 6 | gone with this patch series combined with the following change for GLib: |
7 | https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4120 | 7 | https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4120 |
8 | 8 | ||
9 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | 9 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> |
10 | --- | 10 | --- |
11 | Akihiko Odaki (14): | 11 | Changes in v7: |
12 | hw/core: Free CPUState allocations | 12 | - Don't open code memory_region_ref(). (Peter Xu) |
13 | hw/ide: Free macio-ide IRQs | 13 | - Link to v6: https://lore.kernel.org/r/20250105-san-v6-0-11fc859b99b7@daynix.com |
14 | hw/isa/vt82c686: Free irqs | 14 | |
15 | spapr: Free stdout path | 15 | Changes in v6: |
16 | ppc/vof: Fix unaligned FDT property access | 16 | - Avoid referring owner as "the object that tracks the region's |
17 | hw/virtio: Free vqs before vhost_dev_cleanup() | 17 | reference count". |
18 | migration: Free removed SaveStateEntry | 18 | - Noted that memroy_region_ref() and memroy_region_unref() do nothing |
19 | if the owner is not present. | ||
20 | - Explicitly stated that memory_region_unref() may destroy the owner | ||
21 | along with the memory region itself. | ||
22 | - Link to v5: https://lore.kernel.org/r/20250104-san-v5-0-8b430457b09d@daynix.com | ||
23 | |||
24 | Changes in v5: | ||
25 | - Rebased. | ||
26 | - Merged four patches to update inline documentation into one | ||
27 | - Link to v4: https://lore.kernel.org/r/20240823-san-v4-0-a24c6dfa4ceb@daynix.com | ||
28 | |||
29 | Changes in v4: | ||
30 | - Changed to create a reference to the subregion instead of its owner | ||
31 | when its owner equals to the container's owner. | ||
32 | - Dropped R-b from patch "memory: Do not create circular reference with | ||
33 | subregion". | ||
34 | - Rebased. | ||
35 | - Link to v3: https://lore.kernel.org/r/20240708-san-v3-0-b03f671c40c6@daynix.com | ||
36 | |||
37 | Changes in v3: | ||
38 | - Added patch "memory: Clarify that we use owner's reference count". | ||
39 | - Added patch "memory: Refer to docs/devel/memory.rst for 'owner'". | ||
40 | - Fixed the message of patch | ||
41 | "memory: Do not create circular reference with subregion". | ||
42 | - Dropped patch "cpu: Free cpu_ases" in favor of: | ||
43 | https://lore.kernel.org/r/20240607115649.214622-7-salil.mehta@huawei.com/ | ||
44 | ("[PATCH V13 6/8] physmem: Add helper function to destroy CPU | ||
45 | AddressSpace") | ||
46 | - Dropped patches "hw/ide: Convert macio ide_irq into GPIO line" and | ||
47 | "hw/ide: Remove internal DMA qemu_irq" in favor of commit efb359346c7a | ||
48 | ("hw/ide/macio: switch from using qemu_allocate_irq() to qdev input | ||
49 | GPIOs") | ||
50 | - Dropped patch "hw/isa/vt82c686: Define a GPIO line between vt82c686 | ||
51 | and i8259" in favor of: | ||
52 | https://patchew.org/QEMU/20240704205854.18537-1-shentey@gmail.com/ | ||
53 | ("[PATCH 0/3] Resolve vt82c686 and piix4 qemu_irq memory leaks") | ||
54 | - Dropped pulled patches. | ||
55 | - Link to v2: https://lore.kernel.org/r/20240627-san-v2-0-750bb0946dbd@daynix.com | ||
56 | |||
57 | Changes in v2: | ||
58 | - Rebased to "[PATCH] cpu: fix memleak of 'halt_cond' and 'thread'". | ||
59 | (Philippe Mathieu-Daudé) | ||
60 | - Converted IRQs into GPIO lines and removed one qemu_irq usage. | ||
61 | (Peter Maydell) | ||
62 | - s/suppresses/fixes/ (Michael S. Tsirkin) | ||
63 | - Corrected title of patch "hw/virtio: Free vqs after vhost_dev_cleanup()" | ||
64 | (was "hw/virtio: Free vqs before vhost_dev_cleanup()") | ||
65 | - Link to v1: https://lore.kernel.org/r/20240626-san-v1-0-f3cc42302189@daynix.com | ||
66 | |||
67 | --- | ||
68 | Akihiko Odaki (2): | ||
69 | memory: Update inline documentation | ||
19 | memory: Do not create circular reference with subregion | 70 | memory: Do not create circular reference with subregion |
20 | tests/qtest: Use qtest_add_data_func_full() | ||
21 | tests/qtest: Free unused QMP response | ||
22 | tests/qtest: Free old machine variable name | ||
23 | tests/qtest: Delete previous boot file | ||
24 | tests/qtest: Free paths | ||
25 | tests/qtest: Free GThread | ||
26 | 71 | ||
27 | hw/core/cpu-common.c | 3 +++ | 72 | include/exec/memory.h | 59 ++++++++++++++++++++++++--------------------------- |
28 | hw/ide/macio.c | 9 +++++++++ | 73 | system/memory.c | 24 +++++++++++++++++++-- |
29 | hw/isa/vt82c686.c | 3 ++- | 74 | 2 files changed, 50 insertions(+), 33 deletions(-) |
30 | hw/ppc/spapr_vof.c | 2 +- | ||
31 | hw/ppc/vof.c | 2 +- | ||
32 | hw/virtio/vhost-user-base.c | 2 ++ | ||
33 | migration/savevm.c | 2 ++ | ||
34 | system/memory.c | 11 +++++++++-- | ||
35 | tests/qtest/device-introspect-test.c | 7 +++---- | ||
36 | tests/qtest/libqtest.c | 3 +++ | ||
37 | tests/qtest/migration-test.c | 18 +++++++++++------- | ||
38 | tests/qtest/qos-test.c | 16 ++++++++++++---- | ||
39 | tests/qtest/vhost-user-test.c | 6 +++--- | ||
40 | 13 files changed, 61 insertions(+), 23 deletions(-) | ||
41 | --- | 75 | --- |
42 | base-commit: 74abb45dac6979e7ff76172b7f0a24e869405184 | 76 | base-commit: 38d0939b86e2eef6f6a622c6f1f7befda0146595 |
43 | change-id: 20240625-san-097afaf4f1c2 | 77 | change-id: 20240625-san-097afaf4f1c2 |
44 | 78 | ||
45 | Best regards, | 79 | Best regards, |
46 | -- | 80 | -- |
47 | Akihiko Odaki <akihiko.odaki@daynix.com> | 81 | Akihiko Odaki <akihiko.odaki@daynix.com> |
82 | |||
83 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | hw/core/cpu-common.c | 3 +++ | ||
6 | 1 file changed, 3 insertions(+) | ||
7 | |||
8 | diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/hw/core/cpu-common.c | ||
11 | +++ b/hw/core/cpu-common.c | ||
12 | @@ -XXX,XX +XXX,XX @@ static void cpu_common_finalize(Object *obj) | ||
13 | { | ||
14 | CPUState *cpu = CPU(obj); | ||
15 | |||
16 | + g_free(cpu->thread); | ||
17 | + g_free(cpu->halt_cond); | ||
18 | + g_free(cpu->cpu_ases); | ||
19 | g_array_free(cpu->gdb_regs, TRUE); | ||
20 | qemu_lockcnt_destroy(&cpu->in_ioctl_lock); | ||
21 | qemu_mutex_destroy(&cpu->work_mutex); | ||
22 | |||
23 | -- | ||
24 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | hw/ide/macio.c | 9 +++++++++ | ||
6 | 1 file changed, 9 insertions(+) | ||
7 | |||
8 | diff --git a/hw/ide/macio.c b/hw/ide/macio.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/hw/ide/macio.c | ||
11 | +++ b/hw/ide/macio.c | ||
12 | @@ -XXX,XX +XXX,XX @@ static void macio_ide_initfn(Object *obj) | ||
13 | qdev_prop_allow_set_link_before_realize, 0); | ||
14 | } | ||
15 | |||
16 | +static void macio_ide_finalize(Object *obj) | ||
17 | +{ | ||
18 | + MACIOIDEState *s = MACIO_IDE(obj); | ||
19 | + | ||
20 | + qemu_free_irq(s->dma_irq); | ||
21 | + qemu_free_irq(s->ide_irq); | ||
22 | +} | ||
23 | + | ||
24 | static Property macio_ide_properties[] = { | ||
25 | DEFINE_PROP_UINT32("channel", MACIOIDEState, channel, 0), | ||
26 | DEFINE_PROP_UINT32("addr", MACIOIDEState, addr, -1), | ||
27 | @@ -XXX,XX +XXX,XX @@ static const TypeInfo macio_ide_type_info = { | ||
28 | .parent = TYPE_SYS_BUS_DEVICE, | ||
29 | .instance_size = sizeof(MACIOIDEState), | ||
30 | .instance_init = macio_ide_initfn, | ||
31 | + .instance_finalize = macio_ide_finalize, | ||
32 | .class_init = macio_ide_class_init, | ||
33 | }; | ||
34 | |||
35 | |||
36 | -- | ||
37 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | hw/isa/vt82c686.c | 3 ++- | ||
6 | 1 file changed, 2 insertions(+), 1 deletion(-) | ||
7 | |||
8 | diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/hw/isa/vt82c686.c | ||
11 | +++ b/hw/isa/vt82c686.c | ||
12 | @@ -XXX,XX +XXX,XX @@ static void via_isa_realize(PCIDevice *d, Error **errp) | ||
13 | |||
14 | qdev_init_gpio_out(dev, &s->cpu_intr, 1); | ||
15 | qdev_init_gpio_in_named(dev, via_isa_pirq, "pirq", PCI_NUM_PINS); | ||
16 | - isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1); | ||
17 | isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d), | ||
18 | errp); | ||
19 | |||
20 | @@ -XXX,XX +XXX,XX @@ static void via_isa_realize(PCIDevice *d, Error **errp) | ||
21 | return; | ||
22 | } | ||
23 | |||
24 | + isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1); | ||
25 | s->isa_irqs_in = i8259_init(isa_bus, *isa_irq); | ||
26 | + qemu_free_irqs(isa_irq, 1); | ||
27 | isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in); | ||
28 | i8254_pit_init(isa_bus, 0x40, 0, NULL); | ||
29 | i8257_dma_init(OBJECT(d), isa_bus, 0); | ||
30 | |||
31 | -- | ||
32 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | hw/ppc/spapr_vof.c | 2 +- | ||
6 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
7 | |||
8 | diff --git a/hw/ppc/spapr_vof.c b/hw/ppc/spapr_vof.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/hw/ppc/spapr_vof.c | ||
11 | +++ b/hw/ppc/spapr_vof.c | ||
12 | @@ -XXX,XX +XXX,XX @@ target_ulong spapr_h_vof_client(PowerPCCPU *cpu, SpaprMachineState *spapr, | ||
13 | |||
14 | void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt) | ||
15 | { | ||
16 | - char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus); | ||
17 | + g_autofree char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus); | ||
18 | |||
19 | vof_build_dt(fdt, spapr->vof); | ||
20 | |||
21 | |||
22 | -- | ||
23 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | FDT properties are aligned by 4 bytes, not 8 bytes. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | hw/ppc/vof.c | 2 +- | ||
6 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
7 | |||
8 | diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/hw/ppc/vof.c | ||
11 | +++ b/hw/ppc/vof.c | ||
12 | @@ -XXX,XX +XXX,XX @@ static void vof_dt_memory_available(void *fdt, GArray *claimed, uint64_t base) | ||
13 | mem0_reg = fdt_getprop(fdt, offset, "reg", &proplen); | ||
14 | g_assert(mem0_reg && proplen == sizeof(uint32_t) * (ac + sc)); | ||
15 | if (sc == 2) { | ||
16 | - mem0_end = be64_to_cpu(*(uint64_t *)(mem0_reg + sizeof(uint32_t) * ac)); | ||
17 | + mem0_end = ldq_be_p(mem0_reg + sizeof(uint32_t) * ac); | ||
18 | } else { | ||
19 | mem0_end = be32_to_cpu(*(uint32_t *)(mem0_reg + sizeof(uint32_t) * ac)); | ||
20 | } | ||
21 | |||
22 | -- | ||
23 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | hw/virtio/vhost-user-base.c | 2 ++ | ||
6 | 1 file changed, 2 insertions(+) | ||
7 | |||
8 | diff --git a/hw/virtio/vhost-user-base.c b/hw/virtio/vhost-user-base.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/hw/virtio/vhost-user-base.c | ||
11 | +++ b/hw/virtio/vhost-user-base.c | ||
12 | @@ -XXX,XX +XXX,XX @@ static void vub_disconnect(DeviceState *dev) | ||
13 | { | ||
14 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); | ||
15 | VHostUserBase *vub = VHOST_USER_BASE(vdev); | ||
16 | + struct vhost_virtqueue *vhost_vqs = vub->vhost_dev.vqs; | ||
17 | |||
18 | if (!vub->connected) { | ||
19 | return; | ||
20 | @@ -XXX,XX +XXX,XX @@ static void vub_disconnect(DeviceState *dev) | ||
21 | |||
22 | vub_stop(vdev); | ||
23 | vhost_dev_cleanup(&vub->vhost_dev); | ||
24 | + g_free(vhost_vqs); | ||
25 | |||
26 | /* Re-instate the event handler for new connections */ | ||
27 | qemu_chr_fe_set_handlers(&vub->chardev, | ||
28 | |||
29 | -- | ||
30 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | migration/savevm.c | 2 ++ | ||
6 | 1 file changed, 2 insertions(+) | ||
7 | |||
8 | diff --git a/migration/savevm.c b/migration/savevm.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/migration/savevm.c | ||
11 | +++ b/migration/savevm.c | ||
12 | @@ -XXX,XX +XXX,XX @@ int vmstate_replace_hack_for_ppc(VMStateIf *obj, int instance_id, | ||
13 | |||
14 | if (se) { | ||
15 | savevm_state_handler_remove(se); | ||
16 | + g_free(se->compat); | ||
17 | + g_free(se); | ||
18 | } | ||
19 | return vmstate_register(obj, instance_id, vmsd, opaque); | ||
20 | } | ||
21 | |||
22 | -- | ||
23 | 2.45.2 | diff view generated by jsdifflib |
1 | These GThreads are never referenced. | 1 | Do not refer to "memory region's reference count" |
---|---|---|---|
2 | ------------------------------------------------- | ||
3 | |||
4 | Now MemoryRegions do have their own reference counts, but they will not | ||
5 | be used when their owners are not themselves. However, the documentation | ||
6 | of memory_region_ref() says it adds "1 to a memory region's reference | ||
7 | count", which is confusing. Avoid referring to "memory region's | ||
8 | reference count" and just say: "Add a reference to a memory region". | ||
9 | Make a similar change to memory_region_unref() too. | ||
10 | |||
11 | Refer to docs/devel/memory.rst for "owner" | ||
12 | ------------------------------------------ | ||
13 | |||
14 | memory_region_ref() and memory_region_unref() used to have their own | ||
15 | descriptions of "owner", but they are somewhat out-of-date and | ||
16 | misleading. | ||
17 | |||
18 | In particular, they say "whenever memory regions are accessed outside | ||
19 | the BQL, they need to be preserved against hot-unplug", but protecting | ||
20 | against hot-unplug is not mandatory if it is known that they will never | ||
21 | be hot-unplugged. They also say "MemoryRegions actually do not have | ||
22 | their own reference count", but they actually do. They just will not be | ||
23 | used unless their owners are not themselves. | ||
24 | |||
25 | Refer to docs/devel/memory.rst as the single source of truth instead of | ||
26 | maintaining duplicate descriptions of "owner". | ||
27 | |||
28 | Clarify that owner may be missing | ||
29 | |||
30 | --------------------------------- | ||
31 | A memory region may not have an owner, and memory_region_ref() and | ||
32 | memory_region_unref() do nothing for such. | ||
33 | |||
34 | memory: Clarify owner must not call memory_region_ref() | ||
35 | -------------------------------------------------------- | ||
36 | |||
37 | The owner must not call this function as it results in a circular | ||
38 | reference. | ||
2 | 39 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | 40 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> |
41 | Reviewed-by: Peter Xu <peterx@redhat.com> | ||
4 | --- | 42 | --- |
5 | tests/qtest/vhost-user-test.c | 6 +++--- | 43 | include/exec/memory.h | 59 ++++++++++++++++++++++++--------------------------- |
6 | 1 file changed, 3 insertions(+), 3 deletions(-) | 44 | 1 file changed, 28 insertions(+), 31 deletions(-) |
7 | 45 | ||
8 | diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c | 46 | diff --git a/include/exec/memory.h b/include/exec/memory.h |
9 | index XXXXXXX..XXXXXXX 100644 | 47 | index XXXXXXX..XXXXXXX 100644 |
10 | --- a/tests/qtest/vhost-user-test.c | 48 | --- a/include/exec/memory.h |
11 | +++ b/tests/qtest/vhost-user-test.c | 49 | +++ b/include/exec/memory.h |
12 | @@ -XXX,XX +XXX,XX @@ static void *vhost_user_test_setup_reconnect(GString *cmd_line, void *arg) | 50 | @@ -XXX,XX +XXX,XX @@ void memory_region_section_free_copy(MemoryRegionSection *s); |
13 | { | 51 | * memory_region_add_subregion() to add subregions. |
14 | TestServer *s = test_server_new("reconnect", arg); | 52 | * |
15 | 53 | * @mr: the #MemoryRegion to be initialized | |
16 | - g_thread_new("connect", connect_thread, s); | 54 | - * @owner: the object that tracks the region's reference count |
17 | + g_thread_unref(g_thread_new("connect", connect_thread, s)); | 55 | + * @owner: the object that keeps the region alive |
18 | append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO); | 56 | * @name: used for debugging; not visible to the user or ABI |
19 | s->vu_ops->append_opts(s, cmd_line, ",server=on"); | 57 | * @size: size of the region; any subregions beyond this size will be clipped |
20 | 58 | */ | |
21 | @@ -XXX,XX +XXX,XX @@ static void *vhost_user_test_setup_connect_fail(GString *cmd_line, void *arg) | 59 | @@ -XXX,XX +XXX,XX @@ void memory_region_init(MemoryRegion *mr, |
22 | 60 | uint64_t size); | |
23 | s->test_fail = true; | 61 | |
24 | 62 | /** | |
25 | - g_thread_new("connect", connect_thread, s); | 63 | - * memory_region_ref: Add 1 to a memory region's reference count |
26 | + g_thread_unref(g_thread_new("connect", connect_thread, s)); | 64 | + * memory_region_ref: Add a reference to the owner of a memory region |
27 | append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO); | 65 | * |
28 | s->vu_ops->append_opts(s, cmd_line, ",server=on"); | 66 | - * Whenever memory regions are accessed outside the BQL, they need to be |
29 | 67 | - * preserved against hot-unplug. MemoryRegions actually do not have their | |
30 | @@ -XXX,XX +XXX,XX @@ static void *vhost_user_test_setup_flags_mismatch(GString *cmd_line, void *arg) | 68 | - * own reference count; they piggyback on a QOM object, their "owner". |
31 | 69 | - * This function adds a reference to the owner. | |
32 | s->test_flags = TEST_FLAGS_DISCONNECT; | 70 | - * |
33 | 71 | - * All MemoryRegions must have an owner if they can disappear, even if the | |
34 | - g_thread_new("connect", connect_thread, s); | 72 | - * device they belong to operates exclusively under the BQL. This is because |
35 | + g_thread_unref(g_thread_new("connect", connect_thread, s)); | 73 | - * the region could be returned at any time by memory_region_find, and this |
36 | append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO); | 74 | - * is usually under guest control. |
37 | s->vu_ops->append_opts(s, cmd_line, ",server=on"); | 75 | + * This function adds a reference to the owner of a memory region to keep the |
38 | 76 | + * memory region alive. It does nothing if the owner is not present as a memory | |
77 | + * region without owner will never die. | ||
78 | + * For references internal to the owner, use object_ref() instead to avoid a | ||
79 | + * circular reference. | ||
80 | + * See docs/devel/memory.rst to know about owner. | ||
81 | * | ||
82 | * @mr: the #MemoryRegion | ||
83 | */ | ||
84 | void memory_region_ref(MemoryRegion *mr); | ||
85 | |||
86 | /** | ||
87 | - * memory_region_unref: Remove 1 to a memory region's reference count | ||
88 | + * memory_region_unref: Remove a reference to the memory region of the owner | ||
89 | * | ||
90 | - * Whenever memory regions are accessed outside the BQL, they need to be | ||
91 | - * preserved against hot-unplug. MemoryRegions actually do not have their | ||
92 | - * own reference count; they piggyback on a QOM object, their "owner". | ||
93 | - * This function removes a reference to the owner and possibly destroys it. | ||
94 | + * This function removes a reference to the owner of a memory region and | ||
95 | + * possibly destroys the owner along with the memory region. It does nothing if | ||
96 | + * the owner is not present. | ||
97 | + * See docs/devel/memory.rst to know about owner. | ||
98 | * | ||
99 | * @mr: the #MemoryRegion | ||
100 | */ | ||
101 | @@ -XXX,XX +XXX,XX @@ void memory_region_unref(MemoryRegion *mr); | ||
102 | * if @size is nonzero, subregions will be clipped to @size. | ||
103 | * | ||
104 | * @mr: the #MemoryRegion to be initialized. | ||
105 | - * @owner: the object that tracks the region's reference count | ||
106 | + * @owner: the object that keeps the region alive | ||
107 | * @ops: a structure containing read and write callbacks to be used when | ||
108 | * I/O is performed on the region. | ||
109 | * @opaque: passed to the read and write callbacks of the @ops structure. | ||
110 | @@ -XXX,XX +XXX,XX @@ void memory_region_init_io(MemoryRegion *mr, | ||
111 | * directly. | ||
112 | * | ||
113 | * @mr: the #MemoryRegion to be initialized. | ||
114 | - * @owner: the object that tracks the region's reference count | ||
115 | + * @owner: the object that keeps the region alive | ||
116 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
117 | * must be unique within any device | ||
118 | * @size: size of the region. | ||
119 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_ram_nomigrate(MemoryRegion *mr, | ||
120 | * modify memory directly. | ||
121 | * | ||
122 | * @mr: the #MemoryRegion to be initialized. | ||
123 | - * @owner: the object that tracks the region's reference count | ||
124 | + * @owner: the object that keeps the region alive | ||
125 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
126 | * must be unique within any device | ||
127 | * @size: size of the region. | ||
128 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_ram_flags_nomigrate(MemoryRegion *mr, | ||
129 | * canceled. | ||
130 | * | ||
131 | * @mr: the #MemoryRegion to be initialized. | ||
132 | - * @owner: the object that tracks the region's reference count | ||
133 | + * @owner: the object that keeps the region alive | ||
134 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
135 | * must be unique within any device | ||
136 | * @size: used size of the region. | ||
137 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr, | ||
138 | * mmap-ed backend. | ||
139 | * | ||
140 | * @mr: the #MemoryRegion to be initialized. | ||
141 | - * @owner: the object that tracks the region's reference count | ||
142 | + * @owner: the object that keeps the region alive | ||
143 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
144 | * must be unique within any device | ||
145 | * @size: size of the region. | ||
146 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_ram_from_file(MemoryRegion *mr, | ||
147 | * mmap-ed backend. | ||
148 | * | ||
149 | * @mr: the #MemoryRegion to be initialized. | ||
150 | - * @owner: the object that tracks the region's reference count | ||
151 | + * @owner: the object that keeps the region alive | ||
152 | * @name: the name of the region. | ||
153 | * @size: size of the region. | ||
154 | * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM, | ||
155 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_ram_from_fd(MemoryRegion *mr, | ||
156 | * region will modify memory directly. | ||
157 | * | ||
158 | * @mr: the #MemoryRegion to be initialized. | ||
159 | - * @owner: the object that tracks the region's reference count | ||
160 | + * @owner: the object that keeps the region alive | ||
161 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
162 | * must be unique within any device | ||
163 | * @size: size of the region. | ||
164 | @@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_ptr(MemoryRegion *mr, | ||
165 | * skip_dump flag. | ||
166 | * | ||
167 | * @mr: the #MemoryRegion to be initialized. | ||
168 | - * @owner: the object that tracks the region's reference count | ||
169 | + * @owner: the object that keeps the region alive | ||
170 | * @name: the name of the region. | ||
171 | * @size: size of the region. | ||
172 | * @ptr: memory to be mapped; must contain at least @size bytes. | ||
173 | @@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_device_ptr(MemoryRegion *mr, | ||
174 | * part of another memory region. | ||
175 | * | ||
176 | * @mr: the #MemoryRegion to be initialized. | ||
177 | - * @owner: the object that tracks the region's reference count | ||
178 | + * @owner: the object that keeps the region alive | ||
179 | * @name: used for debugging; not visible to the user or ABI | ||
180 | * @orig: the region to be referenced; @mr will be equivalent to | ||
181 | * @orig between @offset and @offset + @size - 1. | ||
182 | @@ -XXX,XX +XXX,XX @@ void memory_region_init_alias(MemoryRegion *mr, | ||
183 | * of the caller. | ||
184 | * | ||
185 | * @mr: the #MemoryRegion to be initialized. | ||
186 | - * @owner: the object that tracks the region's reference count | ||
187 | + * @owner: the object that keeps the region alive | ||
188 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
189 | * must be unique within any device | ||
190 | * @size: size of the region. | ||
191 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_rom_nomigrate(MemoryRegion *mr, | ||
192 | * of the caller. | ||
193 | * | ||
194 | * @mr: the #MemoryRegion to be initialized. | ||
195 | - * @owner: the object that tracks the region's reference count | ||
196 | + * @owner: the object that keeps the region alive | ||
197 | * @ops: callbacks for write access handling (must not be NULL). | ||
198 | * @opaque: passed to the read and write callbacks of the @ops structure. | ||
199 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
200 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_rom_device_nomigrate(MemoryRegion *mr, | ||
201 | * @_iommu_mr: the #IOMMUMemoryRegion to be initialized | ||
202 | * @instance_size: the IOMMUMemoryRegion subclass instance size | ||
203 | * @mrtypename: the type name of the #IOMMUMemoryRegion | ||
204 | - * @owner: the object that tracks the region's reference count | ||
205 | + * @owner: the object that keeps the region alive | ||
206 | * @name: used for debugging; not visible to the user or ABI | ||
207 | * @size: size of the region. | ||
208 | */ | ||
209 | @@ -XXX,XX +XXX,XX @@ void memory_region_init_iommu(void *_iommu_mr, | ||
210 | * region will modify memory directly. | ||
211 | * | ||
212 | * @mr: the #MemoryRegion to be initialized | ||
213 | - * @owner: the object that tracks the region's reference count (must be | ||
214 | + * @owner: the object that keeps the region alive (must be | ||
215 | * TYPE_DEVICE or a subclass of TYPE_DEVICE, or NULL) | ||
216 | * @name: name of the memory region | ||
217 | * @size: size of the region in bytes | ||
218 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_ram_guest_memfd(MemoryRegion *mr, | ||
219 | * If you pass a non-NULL non-device @owner then we will assert. | ||
220 | * | ||
221 | * @mr: the #MemoryRegion to be initialized. | ||
222 | - * @owner: the object that tracks the region's reference count | ||
223 | + * @owner: the object that keeps the region alive | ||
224 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
225 | * must be unique within any device | ||
226 | * @size: size of the region. | ||
227 | @@ -XXX,XX +XXX,XX @@ bool memory_region_init_rom(MemoryRegion *mr, | ||
228 | * If you pass a non-NULL non-device @owner then we will assert. | ||
229 | * | ||
230 | * @mr: the #MemoryRegion to be initialized. | ||
231 | - * @owner: the object that tracks the region's reference count | ||
232 | + * @owner: the object that keeps the region alive | ||
233 | * @ops: callbacks for write access handling (must not be NULL). | ||
234 | * @opaque: passed to the read and write callbacks of the @ops structure. | ||
235 | * @name: Region name, becomes part of RAMBlock name used in migration stream | ||
39 | 236 | ||
40 | -- | 237 | -- |
41 | 2.45.2 | 238 | 2.47.1 | diff view generated by jsdifflib |
1 | A memory region does not use their own reference counters, but instead | 1 | memory_region_update_container_subregions() used to call |
---|---|---|---|
2 | piggybacks on another QOM object, "owner" (unless the owner is not the | 2 | memory_region_ref(), which creates a reference to the owner of the |
3 | memory region itself). When creating a subregion, a new reference to the | 3 | subregion, on behalf of the owner of the container. This results in a |
4 | owner of the container must be created. However, if the subregion is | 4 | circular reference if the subregion and container have the same owner. |
5 | owned by the same QOM object, this result in a self-reference, and make | 5 | |
6 | the owner immortal. Avoid such a self-reference. | 6 | memory_region_ref() creates a reference to the owner instead of the |
7 | memory region to match the lifetime of the owner and memory region. We | ||
8 | do not need such a hack if the subregion and container have the same | ||
9 | owner because the owner will be alive as long as the container is. | ||
10 | Therefore, create a reference to the subregion itself instead ot its | ||
11 | owner in such a case; the reference to the subregion is still necessary | ||
12 | to ensure that the subregion gets finalized after the container. | ||
7 | 13 | ||
8 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | 14 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> |
9 | --- | 15 | --- |
10 | system/memory.c | 11 +++++++++-- | 16 | system/memory.c | 24 ++++++++++++++++++++++-- |
11 | 1 file changed, 9 insertions(+), 2 deletions(-) | 17 | 1 file changed, 22 insertions(+), 2 deletions(-) |
12 | 18 | ||
13 | diff --git a/system/memory.c b/system/memory.c | 19 | diff --git a/system/memory.c b/system/memory.c |
14 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/system/memory.c | 21 | --- a/system/memory.c |
16 | +++ b/system/memory.c | 22 | +++ b/system/memory.c |
17 | @@ -XXX,XX +XXX,XX @@ static void memory_region_update_container_subregions(MemoryRegion *subregion) | 23 | @@ -XXX,XX +XXX,XX @@ void memory_region_unref(MemoryRegion *mr) |
18 | 24 | } | |
19 | memory_region_transaction_begin(); | 25 | } |
20 | 26 | ||
21 | - memory_region_ref(subregion); | 27 | +static void memory_region_ref_subregion(MemoryRegion *subregion) |
22 | + if (mr->owner != subregion->owner) { | 28 | +{ |
29 | + if (subregion->container->owner == subregion->owner) { | ||
30 | + object_ref(OBJECT(subregion)); | ||
31 | + } else { | ||
23 | + memory_region_ref(subregion); | 32 | + memory_region_ref(subregion); |
24 | + } | 33 | + } |
34 | +} | ||
35 | + | ||
36 | +static void memory_region_unref_subregion(MemoryRegion *subregion) | ||
37 | +{ | ||
38 | + if (subregion->container->owner == subregion->owner) { | ||
39 | + object_unref(OBJECT(subregion)); | ||
40 | + } else { | ||
41 | + memory_region_unref(subregion); | ||
42 | + } | ||
43 | +} | ||
44 | + | ||
45 | uint64_t memory_region_size(MemoryRegion *mr) | ||
46 | { | ||
47 | if (int128_eq(mr->size, int128_2_64())) { | ||
48 | @@ -XXX,XX +XXX,XX @@ static void memory_region_update_container_subregions(MemoryRegion *subregion) | ||
49 | |||
50 | memory_region_transaction_begin(); | ||
51 | |||
52 | - memory_region_ref(subregion); | ||
53 | + memory_region_ref_subregion(subregion); | ||
25 | + | 54 | + |
26 | QTAILQ_FOREACH(other, &mr->subregions, subregions_link) { | 55 | QTAILQ_FOREACH(other, &mr->subregions, subregions_link) { |
27 | if (subregion->priority >= other->priority) { | 56 | if (subregion->priority >= other->priority) { |
28 | QTAILQ_INSERT_BEFORE(other, subregion, subregions_link); | 57 | QTAILQ_INSERT_BEFORE(other, subregion, subregions_link); |
29 | @@ -XXX,XX +XXX,XX @@ void memory_region_del_subregion(MemoryRegion *mr, | 58 | @@ -XXX,XX +XXX,XX @@ void memory_region_del_subregion(MemoryRegion *mr, |
30 | assert(alias->mapped_via_alias >= 0); | 59 | assert(alias->mapped_via_alias >= 0); |
31 | } | 60 | } |
32 | QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link); | 61 | QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link); |
33 | - memory_region_unref(subregion); | 62 | - memory_region_unref(subregion); |
34 | + | 63 | + memory_region_unref_subregion(subregion); |
35 | + if (mr->owner != subregion->owner) { | ||
36 | + memory_region_unref(subregion); | ||
37 | + } | ||
38 | + | 64 | + |
39 | memory_region_update_pending |= mr->enabled && subregion->enabled; | 65 | memory_region_update_pending |= mr->enabled && subregion->enabled; |
40 | memory_region_transaction_commit(); | 66 | memory_region_transaction_commit(); |
41 | } | 67 | } |
42 | 68 | ||
43 | -- | 69 | -- |
44 | 2.45.2 | 70 | 2.47.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | A test function may not be executed depending on the test command line | ||
2 | so it is wrong to free data with a test function. Use | ||
3 | qtest_add_data_func_full() to register a function to free data. | ||
4 | 1 | ||
5 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
6 | --- | ||
7 | tests/qtest/device-introspect-test.c | 7 +++---- | ||
8 | 1 file changed, 3 insertions(+), 4 deletions(-) | ||
9 | |||
10 | diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/tests/qtest/device-introspect-test.c | ||
13 | +++ b/tests/qtest/device-introspect-test.c | ||
14 | @@ -XXX,XX +XXX,XX @@ static void test_device_intro_concrete(const void *args) | ||
15 | |||
16 | qobject_unref(types); | ||
17 | qtest_quit(qts); | ||
18 | - g_free((void *)args); | ||
19 | } | ||
20 | |||
21 | static void test_abstract_interfaces(void) | ||
22 | @@ -XXX,XX +XXX,XX @@ static void add_machine_test_case(const char *mname) | ||
23 | |||
24 | path = g_strdup_printf("device/introspect/concrete/defaults/%s", mname); | ||
25 | args = g_strdup_printf("-M %s", mname); | ||
26 | - qtest_add_data_func(path, args, test_device_intro_concrete); | ||
27 | + qtest_add_data_func_full(path, args, test_device_intro_concrete, g_free); | ||
28 | g_free(path); | ||
29 | |||
30 | path = g_strdup_printf("device/introspect/concrete/nodefaults/%s", mname); | ||
31 | args = g_strdup_printf("-nodefaults -M %s", mname); | ||
32 | - qtest_add_data_func(path, args, test_device_intro_concrete); | ||
33 | + qtest_add_data_func_full(path, args, test_device_intro_concrete, g_free); | ||
34 | g_free(path); | ||
35 | } | ||
36 | |||
37 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
38 | qtest_add_func("device/introspect/abstract-interfaces", test_abstract_interfaces); | ||
39 | if (g_test_quick()) { | ||
40 | qtest_add_data_func("device/introspect/concrete/defaults/none", | ||
41 | - g_strdup(common_args), test_device_intro_concrete); | ||
42 | + common_args, test_device_intro_concrete); | ||
43 | } else { | ||
44 | qtest_cb_for_every_machine(add_machine_test_case, true); | ||
45 | } | ||
46 | |||
47 | -- | ||
48 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | tests/qtest/libqtest.c | 2 ++ | ||
6 | 1 file changed, 2 insertions(+) | ||
7 | |||
8 | diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/tests/qtest/libqtest.c | ||
11 | +++ b/tests/qtest/libqtest.c | ||
12 | @@ -XXX,XX +XXX,XX @@ QDict *qtest_qmp_receive(QTestState *s) | ||
13 | response, s->eventData)) { | ||
14 | /* Stash the event for a later consumption */ | ||
15 | s->pending_events = g_list_append(s->pending_events, response); | ||
16 | + } else { | ||
17 | + qobject_unref(response); | ||
18 | } | ||
19 | } | ||
20 | } | ||
21 | |||
22 | -- | ||
23 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | tests/qtest/libqtest.c | 1 + | ||
6 | 1 file changed, 1 insertion(+) | ||
7 | |||
8 | diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/tests/qtest/libqtest.c | ||
11 | +++ b/tests/qtest/libqtest.c | ||
12 | @@ -XXX,XX +XXX,XX @@ static struct MachInfo *qtest_get_machines(const char *var) | ||
13 | int idx; | ||
14 | |||
15 | if (g_strcmp0(qemu_var, var)) { | ||
16 | + g_free(qemu_var); | ||
17 | qemu_var = g_strdup(var); | ||
18 | |||
19 | /* new qemu, clear the cache */ | ||
20 | |||
21 | -- | ||
22 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | A test run may create boot files several times. Delete the previous boot | ||
2 | file before creating a new one. | ||
3 | 1 | ||
4 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
5 | --- | ||
6 | tests/qtest/migration-test.c | 18 +++++++++++------- | ||
7 | 1 file changed, 11 insertions(+), 7 deletions(-) | ||
8 | |||
9 | diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c | ||
10 | index XXXXXXX..XXXXXXX 100644 | ||
11 | --- a/tests/qtest/migration-test.c | ||
12 | +++ b/tests/qtest/migration-test.c | ||
13 | @@ -XXX,XX +XXX,XX @@ static char *bootpath; | ||
14 | #include "tests/migration/aarch64/a-b-kernel.h" | ||
15 | #include "tests/migration/s390x/a-b-bios.h" | ||
16 | |||
17 | +static void bootfile_delete(void) | ||
18 | +{ | ||
19 | + unlink(bootpath); | ||
20 | + g_free(bootpath); | ||
21 | + bootpath = NULL; | ||
22 | +} | ||
23 | + | ||
24 | static void bootfile_create(char *dir, bool suspend_me) | ||
25 | { | ||
26 | const char *arch = qtest_get_arch(); | ||
27 | unsigned char *content; | ||
28 | size_t len; | ||
29 | |||
30 | + if (bootpath) { | ||
31 | + bootfile_delete(); | ||
32 | + } | ||
33 | + | ||
34 | bootpath = g_strdup_printf("%s/bootsect", dir); | ||
35 | if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { | ||
36 | /* the assembled x86 boot sector should be exactly one sector large */ | ||
37 | @@ -XXX,XX +XXX,XX @@ static void bootfile_create(char *dir, bool suspend_me) | ||
38 | fclose(bootfile); | ||
39 | } | ||
40 | |||
41 | -static void bootfile_delete(void) | ||
42 | -{ | ||
43 | - unlink(bootpath); | ||
44 | - g_free(bootpath); | ||
45 | - bootpath = NULL; | ||
46 | -} | ||
47 | - | ||
48 | /* | ||
49 | * Wait for some output in the serial output file, | ||
50 | * we get an 'A' followed by an endless string of 'B's | ||
51 | |||
52 | -- | ||
53 | 2.45.2 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This suppresses LeakSanitizer warnings. | ||
2 | 1 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
4 | --- | ||
5 | tests/qtest/qos-test.c | 16 ++++++++++++---- | ||
6 | 1 file changed, 12 insertions(+), 4 deletions(-) | ||
7 | |||
8 | diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/tests/qtest/qos-test.c | ||
11 | +++ b/tests/qtest/qos-test.c | ||
12 | @@ -XXX,XX +XXX,XX @@ | ||
13 | static char *old_path; | ||
14 | |||
15 | |||
16 | - | ||
17 | /** | ||
18 | * qos_set_machines_devices_available(): sets availability of qgraph | ||
19 | * machines and devices. | ||
20 | @@ -XXX,XX +XXX,XX @@ static void subprocess_run_one_test(const void *arg) | ||
21 | g_test_trap_assert_passed(); | ||
22 | } | ||
23 | |||
24 | +static void destroy_pathv(void *arg) | ||
25 | +{ | ||
26 | + g_free(((char **)arg)[0]); | ||
27 | + g_free(arg); | ||
28 | +} | ||
29 | + | ||
30 | /* | ||
31 | * in this function, 2 path will be built: | ||
32 | * path_str, a one-string path (ex "pc/i440FX-pcihost/...") | ||
33 | @@ -XXX,XX +XXX,XX @@ static void walk_path(QOSGraphNode *orig_path, int len) | ||
34 | if (path->u.test.subprocess) { | ||
35 | gchar *subprocess_path = g_strdup_printf("/%s/%s/subprocess", | ||
36 | qtest_get_arch(), path_str); | ||
37 | - qtest_add_data_func(path_str, subprocess_path, subprocess_run_one_test); | ||
38 | - g_test_add_data_func(subprocess_path, path_vec, run_one_test); | ||
39 | + qtest_add_data_func_full(path_str, subprocess_path, | ||
40 | + subprocess_run_one_test, g_free); | ||
41 | + g_test_add_data_func_full(subprocess_path, path_vec, | ||
42 | + run_one_test, destroy_pathv); | ||
43 | } else { | ||
44 | - qtest_add_data_func(path_str, path_vec, run_one_test); | ||
45 | + qtest_add_data_func_full(path_str, path_vec, | ||
46 | + run_one_test, destroy_pathv); | ||
47 | } | ||
48 | |||
49 | g_free(path_str); | ||
50 | |||
51 | -- | ||
52 | 2.45.2 | diff view generated by jsdifflib |