On Sat, May 16, 2026 at 6:02 PM Marc-André Lureau <[email protected]> wrote: > > 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[]") > Signed-off-by: Marc-André Lureau <[email protected]>
Reviewed-by: Alistair Francis <[email protected]> Alistair > --- > target/riscv/cpu.h | 3 ++- > target/riscv/cpu.c | 53 > ++++++++++++++++++++++++++++------------------ > target/riscv/kvm/kvm-cpu.c | 6 +++--- > 3 files changed, 37 insertions(+), 25 deletions(-) > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index fae839cade4..86a38a7288b 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -546,6 +546,7 @@ struct ArchCPU { > uint32_t pmu_avail_ctrs; > /* Mapping of events to counters */ > GHashTable *pmu_event_ctr_map; > + GHashTable *user_options; > const GPtrArray *decoders; > }; > > @@ -619,7 +620,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int > size, > bool probe, uintptr_t retaddr); > char *riscv_isa_string(RISCVCPU *cpu); > int riscv_cpu_max_xlen(RISCVCPUClass *mcc); > -bool riscv_cpu_option_set(const char *optname); > +bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname); > > #ifndef CONFIG_USER_ONLY > void riscv_cpu_do_interrupt(CPUState *cpu); > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > index 506a018d52b..bbdc9d8f5de 100644 > --- a/target/riscv/cpu.c > +++ b/target/riscv/cpu.c > @@ -27,6 +27,7 @@ > #include "qapi/error.h" > #include "qapi/visitor.h" > #include "qemu/error-report.h" > +#include "qemu/timer.h" > #include "hw/core/qdev-properties.h" > #include "hw/core/qdev-prop-internal.h" > #include "migration/vmstate.h" > @@ -59,18 +60,16 @@ bool riscv_cpu_is_32bit(RISCVCPU *cpu) > return riscv_cpu_mxl(&cpu->env) == MXL_RV32; > } > > -/* Hash that stores general user set numeric options */ > -static GHashTable *general_user_opts; > - > -static void cpu_option_add_user_setting(const char *optname, uint32_t value) > +static void cpu_option_add_user_setting(RISCVCPU *cpu, const char *optname, > + uint32_t value) > { > - g_hash_table_insert(general_user_opts, (gpointer)optname, > + g_hash_table_insert(cpu->user_options, (gpointer)optname, > GUINT_TO_POINTER(value)); > } > > -bool riscv_cpu_option_set(const char *optname) > +bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname) > { > - return g_hash_table_contains(general_user_opts, optname); > + return g_hash_table_contains(cpu->user_options, optname); > } > > #ifndef CONFIG_USER_ONLY > @@ -1103,7 +1102,7 @@ static void riscv_cpu_init(Object *obj) > "riscv.cpu.rnmi", RNMI_MAX); > #endif /* CONFIG_USER_ONLY */ > > - general_user_opts = g_hash_table_new(g_str_hash, g_str_equal); > + cpu->user_options = g_hash_table_new(g_str_hash, g_str_equal); > > /* > * The timer and performance counters extensions were supported > @@ -1453,7 +1452,7 @@ static void prop_pmu_num_set(Object *obj, Visitor *v, > const char *name, > > warn_report("\"pmu-num\" property is deprecated; use \"pmu-mask\""); > cpu->cfg.pmu_mask = pmu_mask; > - cpu_option_add_user_setting("pmu-mask", pmu_mask); > + cpu_option_add_user_setting(cpu, "pmu-mask", pmu_mask); > } > > static void prop_pmu_num_get(Object *obj, Visitor *v, const char *name, > @@ -1495,7 +1494,7 @@ static void prop_pmu_mask_set(Object *obj, Visitor *v, > const char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.pmu_mask = value; > } > > @@ -1527,7 +1526,7 @@ static void prop_mmu_set(Object *obj, Visitor *v, const > char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.mmu = value; > } > > @@ -1559,7 +1558,7 @@ static void prop_pmp_set(Object *obj, Visitor *v, const > char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.pmp = value; > } > > @@ -1599,7 +1598,7 @@ static void prop_num_pmp_regions_set(Object *obj, > Visitor *v, const char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.pmp_regions = value; > } > > @@ -1637,7 +1636,7 @@ static void prop_pmp_granularity_set(Object *obj, > Visitor *v, const char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.pmp_granularity = value; > } > > @@ -1710,7 +1709,7 @@ static void prop_priv_spec_set(Object *obj, Visitor *v, > const char *name, > return; > } > > - cpu_option_add_user_setting(name, priv_version); > + cpu_option_add_user_setting(cpu, name, priv_version); > cpu->env.priv_ver = priv_version; > } > > @@ -1744,7 +1743,7 @@ static void prop_vext_spec_set(Object *obj, Visitor *v, > const char *name, > return; > } > > - cpu_option_add_user_setting(name, VEXT_VERSION_1_00_0); > + cpu_option_add_user_setting(cpu, name, VEXT_VERSION_1_00_0); > cpu->env.vext_ver = VEXT_VERSION_1_00_0; > } > > @@ -1787,7 +1786,7 @@ static void prop_vlen_set(Object *obj, Visitor *v, > const char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.vlenb = value >> 3; > } > > @@ -1828,7 +1827,7 @@ static void prop_elen_set(Object *obj, Visitor *v, > const char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.elen = value; > } > > @@ -1864,7 +1863,7 @@ static void prop_cbom_blksize_set(Object *obj, Visitor > *v, const char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.cbom_blocksize = value; > } > > @@ -1900,7 +1899,7 @@ static void prop_cbop_blksize_set(Object *obj, Visitor > *v, const char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.cbop_blocksize = value; > } > > @@ -1936,7 +1935,7 @@ static void prop_cboz_blksize_set(Object *obj, Visitor > *v, const char *name, > return; > } > > - cpu_option_add_user_setting(name, value); > + cpu_option_add_user_setting(cpu, name, value); > cpu->cfg.cboz_blocksize = value; > } > > @@ -2975,6 +2974,17 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, > char *nodename) > DEFINE_RISCV_CPU(type_name, parent_type_name, \ > .profile = &(profile_)) > > +static void riscv_cpu_instance_finalize(Object *obj) > +{ > + RISCVCPU *cpu = RISCV_CPU(obj); > + > +#ifndef CONFIG_USER_ONLY > + g_clear_pointer(&cpu->pmu_timer, timer_free); > + g_clear_pointer(&cpu->pmu_event_ctr_map, g_hash_table_destroy); > +#endif > + g_clear_pointer(&cpu->user_options, g_hash_table_destroy); > +} > + > static const TypeInfo riscv_cpu_type_infos[] = { > { > .name = TYPE_RISCV_CPU, > @@ -2982,6 +2992,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { > .instance_size = sizeof(RISCVCPU), > .instance_align = __alignof(RISCVCPU), > .instance_init = riscv_cpu_init, > + .instance_finalize = riscv_cpu_instance_finalize, > .abstract = true, > .class_size = sizeof(RISCVCPUClass), > .class_init = riscv_cpu_common_class_init, > diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c > index b047ffa9c0c..e0241870ada 100644 > --- a/target/riscv/kvm/kvm-cpu.c > +++ b/target/riscv/kvm/kvm-cpu.c > @@ -2025,7 +2025,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, > Error **errp) > } > > if (cpu->cfg.ext_zicbom && > - riscv_cpu_option_set(kvm_cbom_blocksize.name)) { > + riscv_cpu_option_set(cpu, kvm_cbom_blocksize.name)) { > > reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, > kvm_cbom_blocksize.kvm_reg_id); > @@ -2044,7 +2044,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, > Error **errp) > } > > if (cpu->cfg.ext_zicboz && > - riscv_cpu_option_set(kvm_cboz_blocksize.name)) { > + riscv_cpu_option_set(cpu, kvm_cboz_blocksize.name)) { > > reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, > kvm_cboz_blocksize.kvm_reg_id); > @@ -2063,7 +2063,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, > Error **errp) > } > > /* Users are setting vlen, not vlenb */ > - if (riscv_has_ext(env, RVV) && riscv_cpu_option_set("vlen")) { > + if (riscv_has_ext(env, RVV) && riscv_cpu_option_set(cpu, "vlen")) { > if (!kvm_v_vlenb.supported) { > error_setg(errp, "Unable to set 'vlenb': register not > supported"); > return; > > -- > 2.54.0 > >
