Re: [PATCH v2 42/46] target/riscv: fix general_user_opts hash table leak

2026-05-04 Thread Marc-André Lureau
Hi

On Mon, May 4, 2026 at 3:39 PM Marc-André Lureau
 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 
> ---
>  target/riscv/cpu.h |  3 ++-
>  target/riscv/cpu.c | 51 
> +++---
>  target/riscv/kvm/kvm-cpu.c |  6 +++---
>  3 files changed, 35 insertions(+), 25 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 81c41e34296..55a26aeb5be 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 ce15a17c37d..be9a3ac13e7 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;
>  }
>
> @@ 

[PATCH v2 42/46] target/riscv: fix general_user_opts hash table leak

2026-05-04 Thread Marc-André Lureau
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 
---
 target/riscv/cpu.h |  3 ++-
 target/riscv/cpu.c | 51 +++---
 target/riscv/kvm/kvm-cpu.c |  6 +++---
 3 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 81c41e34296..55a26aeb5be 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 ce15a17c37d..be9a3ac13e7 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