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
>
>

Reply via email to