@samitouri / QOSamiQemu / commits / 3febc1f6e2

target/riscv: fix general_user_opts hash table leak

The global general_user_opts hash table is recreated on every riscv_cpu_init() call, leaking the previous one. Furthermore, the CPU settings should be associated with their instance and not global. Add a finalize() to free associated instances. Fixes: d167a2247ede ("target/riscv: move 'pmu-mask' and 'pmu-num' to riscv_cpu_properties[]") Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Marc-André Lureau committed Apr 27, 2026 at 16:31 UTC 3febc1f6e2efa95333805b058fb305686d302f4f
3 files changed +38 -26
target/riscv/cpu.c
+32 -21
@@ -27,6 +27,7 @@
27 #include "qapi/error.h"
28 #include "qapi/visitor.h"
29 #include "qemu/error-report.h"
30 +#include "qemu/timer.h"
31 #include "hw/core/qdev-properties.h"
32 #include "hw/core/qdev-prop-internal.h"
33 #include "migration/vmstate.h"
@@ -59,18 +60,16 @@ bool riscv_cpu_is_32bit(RISCVCPU *cpu)
60 return riscv_cpu_mxl(&cpu->env) == MXL_RV32;
61 }
62
62 -/* Hash that stores general user set numeric options */
63 -static GHashTable *general_user_opts;
64 -
65 -static void cpu_option_add_user_setting(const char *optname, uint32_t value)
63 +static void cpu_option_add_user_setting(RISCVCPU *cpu, const char *optname,
64 + uint32_t value)
65 {
67 - g_hash_table_insert(general_user_opts, (gpointer)optname,
66 + g_hash_table_insert(cpu->user_options, (gpointer)optname,
67 GUINT_TO_POINTER(value));
68 }
69
71 -bool riscv_cpu_option_set(const char *optname)
70 +bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname)
71 {
73 - return g_hash_table_contains(general_user_opts, optname);
72 + return g_hash_table_contains(cpu->user_options, optname);
73 }
74
75 #ifndef CONFIG_USER_ONLY
@@ -1126,7 +1125,7 @@ static void riscv_cpu_init(Object *obj)
1125 "riscv.cpu.rnmi", RNMI_MAX);
1126 #endif /* CONFIG_USER_ONLY */
1127
1129 - general_user_opts = g_hash_table_new(g_str_hash, g_str_equal);
1128 + cpu->user_options = g_hash_table_new(g_str_hash, g_str_equal);
1129
1130 /*
1131 * The timer and performance counters extensions were supported
@@ -1291,7 +1290,7 @@ static void prop_pmu_num_set(Object *obj, Visitor *v, const char *name,
1290
1291 warn_report("\"pmu-num\" property is deprecated; use \"pmu-mask\"");
1292 cpu->cfg.pmu_mask = pmu_mask;
1294 - cpu_option_add_user_setting("pmu-mask", pmu_mask);
1293 + cpu_option_add_user_setting(cpu, "pmu-mask", pmu_mask);
1294 }
1295
1296 static void prop_pmu_num_get(Object *obj, Visitor *v, const char *name,
@@ -1333,7 +1332,7 @@ static void prop_pmu_mask_set(Object *obj, Visitor *v, const char *name,
1332 return;
1333 }
1334
1336 - cpu_option_add_user_setting(name, value);
1335 + cpu_option_add_user_setting(cpu, name, value);
1336 cpu->cfg.pmu_mask = value;
1337 }
1338
@@ -1365,7 +1364,7 @@ static void prop_mmu_set(Object *obj, Visitor *v, const char *name,
1364 return;
1365 }
1366
1368 - cpu_option_add_user_setting(name, value);
1367 + cpu_option_add_user_setting(cpu, name, value);
1368 cpu->cfg.mmu = value;
1369 }
1370
@@ -1397,7 +1396,7 @@ static void prop_pmp_set(Object *obj, Visitor *v, const char *name,
1396 return;
1397 }
1398
1400 - cpu_option_add_user_setting(name, value);
1399 + cpu_option_add_user_setting(cpu, name, value);
1400 cpu->cfg.pmp = value;
1401 }
1402
@@ -1437,7 +1436,7 @@ static void prop_num_pmp_regions_set(Object *obj, Visitor *v, const char *name,
1436 return;
1437 }
1438
1440 - cpu_option_add_user_setting(name, value);
1439 + cpu_option_add_user_setting(cpu, name, value);
1440 cpu->cfg.pmp_regions = value;
1441 }
1442
@@ -1475,7 +1474,7 @@ static void prop_pmp_granularity_set(Object *obj, Visitor *v, const char *name,
1474 return;
1475 }
1476
1478 - cpu_option_add_user_setting(name, value);
1477 + cpu_option_add_user_setting(cpu, name, value);
1478 cpu->cfg.pmp_granularity = value;
1479 }
1480
@@ -1548,7 +1547,7 @@ static void prop_priv_spec_set(Object *obj, Visitor *v, const char *name,
1547 return;
1548 }
1549
1551 - cpu_option_add_user_setting(name, priv_version);
1550 + cpu_option_add_user_setting(cpu, name, priv_version);
1551 cpu->env.priv_ver = priv_version;
1552 }
1553
@@ -1582,7 +1581,7 @@ static void prop_vext_spec_set(Object *obj, Visitor *v, const char *name,
1581 return;
1582 }
1583
1585 - cpu_option_add_user_setting(name, VEXT_VERSION_1_00_0);
1584 + cpu_option_add_user_setting(cpu, name, VEXT_VERSION_1_00_0);
1585 cpu->env.vext_ver = VEXT_VERSION_1_00_0;
1586 }
1587
@@ -1625,7 +1624,7 @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name,
1624 return;
1625 }
1626
1628 - cpu_option_add_user_setting(name, value);
1627 + cpu_option_add_user_setting(cpu, name, value);
1628 cpu->cfg.vlenb = value >> 3;
1629 }
1630
@@ -1666,7 +1665,7 @@ static void prop_elen_set(Object *obj, Visitor *v, const char *name,
1665 return;
1666 }
1667
1669 - cpu_option_add_user_setting(name, value);
1668 + cpu_option_add_user_setting(cpu, name, value);
1669 cpu->cfg.elen = value;
1670 }
1671
@@ -1702,7 +1701,7 @@ static void prop_cbom_blksize_set(Object *obj, Visitor *v, const char *name,
1701 return;
1702 }
1703
1705 - cpu_option_add_user_setting(name, value);
1704 + cpu_option_add_user_setting(cpu, name, value);
1705 cpu->cfg.cbom_blocksize = value;
1706 }
1707
@@ -1738,7 +1737,7 @@ static void prop_cbop_blksize_set(Object *obj, Visitor *v, const char *name,
1737 return;
1738 }
1739
1741 - cpu_option_add_user_setting(name, value);
1740 + cpu_option_add_user_setting(cpu, name, value);
1741 cpu->cfg.cbop_blocksize = value;
1742 }
1743
@@ -1774,7 +1773,7 @@ static void prop_cboz_blksize_set(Object *obj, Visitor *v, const char *name,
1773 return;
1774 }
1775
1777 - cpu_option_add_user_setting(name, value);
1776 + cpu_option_add_user_setting(cpu, name, value);
1777 cpu->cfg.cboz_blocksize = value;
1778 }
1779
@@ -2834,6 +2833,17 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename)
2833 DEFINE_RISCV_CPU(type_name, parent_type_name, \
2834 .profile = &(profile_))
2835
2836 +static void riscv_cpu_instance_finalize(Object *obj)
2837 +{
2838 + RISCVCPU *cpu = RISCV_CPU(obj);
2839 +
2840 +#ifndef CONFIG_USER_ONLY
2841 + g_clear_pointer(&cpu->pmu_timer, timer_free);
2842 + g_clear_pointer(&cpu->pmu_event_ctr_map, g_hash_table_destroy);
2843 +#endif
2844 + g_clear_pointer(&cpu->user_options, g_hash_table_destroy);
2845 +}
2846 +
2847 static const TypeInfo riscv_cpu_type_infos[] = {
2848 {
2849 .name = TYPE_RISCV_CPU,
@@ -2841,6 +2851,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
2851 .instance_size = sizeof(RISCVCPU),
2852 .instance_align = __alignof(RISCVCPU),
2853 .instance_init = riscv_cpu_init,
2854 + .instance_finalize = riscv_cpu_instance_finalize,
2855 .abstract = true,
2856 .class_size = sizeof(RISCVCPUClass),
2857 .class_init = riscv_cpu_common_class_init,
target/riscv/cpu.h
+2 -1
@@ -547,6 +547,7 @@ struct ArchCPU {
547 uint32_t pmu_avail_ctrs;
548 /* Mapping of events to counters */
549 GHashTable *pmu_event_ctr_map;
550 + GHashTable *user_options;
551 const GPtrArray *decoders;
552 };
553
@@ -620,7 +621,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
621 bool probe, uintptr_t retaddr);
622 char *riscv_isa_string(RISCVCPU *cpu);
623 int riscv_cpu_max_xlen(RISCVCPUClass *mcc);
623 -bool riscv_cpu_option_set(const char *optname);
624 +bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname);
625
626 #ifndef CONFIG_USER_ONLY
627 void riscv_cpu_do_interrupt(CPUState *cpu);
target/riscv/kvm/kvm-cpu.c
+4 -4
@@ -2034,7 +2034,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
2034 }
2035
2036 if (cpu->cfg.ext_zicbom &&
2037 - riscv_cpu_option_set(kvm_cbom_blocksize.name)) {
2037 + riscv_cpu_option_set(cpu, kvm_cbom_blocksize.name)) {
2038
2039 reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
2040 kvm_cbom_blocksize.kvm_reg_id);
@@ -2053,7 +2053,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
2053 }
2054
2055 if (cpu->cfg.ext_zicboz &&
2056 - riscv_cpu_option_set(kvm_cboz_blocksize.name)) {
2056 + riscv_cpu_option_set(cpu, kvm_cboz_blocksize.name)) {
2057
2058 reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
2059 kvm_cboz_blocksize.kvm_reg_id);
@@ -2072,7 +2072,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
2072 }
2073
2074 if (cpu->cfg.ext_zicbop &&
2075 - riscv_cpu_option_set(kvm_cbop_blocksize.name)) {
2075 + riscv_cpu_option_set(cpu, kvm_cbop_blocksize.name)) {
2076
2077 reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
2078 kvm_cbop_blocksize.kvm_reg_id);
@@ -2091,7 +2091,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
2091 }
2092
2093 /* Users are setting vlen, not vlenb */
2094 - if (riscv_has_ext(env, RVV) && riscv_cpu_option_set("vlen")) {
2094 + if (riscv_has_ext(env, RVV) && riscv_cpu_option_set(cpu, "vlen")) {
2095 if (!kvm_v_vlenb.supported) {
2096 error_setg(errp, "Unable to set 'vlenb': register not supported");
2097 return;