The slavio_timer device's instance_init function allocates memory for
TimerContext structs and a ptimer, but it never frees this memory, so
we will leak it if the QMP interface does introspection of this
device type, as reported by the clang address sanitizer:
Indirect leak of 4896 byte(s) in 17 object(s) allocated from:
#0 0x5f2948d9b14d in calloc (/home/pm215/qemu/build/san/qemu-system-sparc+0xe0c14d) (BuildId: 7210711bdf6f7fbd0b863bd2dfcc7c42c7175db1)
#1 0x758584b11771 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x63771) (BuildId: 116e142b9b52c8a4dfd403e759e71ab8f95d8bb3)
#2 0x5f2949097b8a in slavio_timer_init /home/pm215/qemu/build/san/../../hw/timer/slavio_timer.c:403:14
#3 0x5f29495d790f in object_initialize_with_type /home/pm215/qemu/build/san/../../qom/object.c:570:5
#4 0x5f29495d96ef in object_new_with_type /home/pm215/qemu/build/san/../../qom/object.c:774:5
#5 0x5f2949a30a26 in qmp_device_list_properties /home/pm215/qemu/build/san/../../qom/qom-qmp-cmds.c:206:11
Indirect leak of 1632 byte(s) in 17 object(s) allocated from:
#0 0x5f2948d9b14d in calloc (/home/pm215/qemu/build/san/qemu-system-sparc+0xe0c14d) (BuildId: 7210711bdf6f7fbd0b863bd2dfcc7c42c7175db1)
#1 0x758584b11771 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x63771) (BuildId: 116e142b9b52c8a4dfd403e759e71ab8f95d8bb3)
#2 0x5f2948f7c65a in ptimer_init /home/pm215/qemu/build/san/../../hw/core/ptimer.c:464:9
#3 0x5f2949097c1f in slavio_timer_init /home/pm215/qemu/build/san/../../hw/timer/slavio_timer.c:407:32
#4 0x5f29495d790f in object_initialize_with_type /home/pm215/qemu/build/san/../../qom/object.c:570:5
#5 0x5f29495d96ef in object_new_with_type /home/pm215/qemu/build/san/../../qom/object.c:774:5
#6 0x5f2949a30a26 in qmp_device_list_properties /home/pm215/qemu/build/san/../../qom/qom-qmp-cmds.c:206:11
Avoid the TimerContext leaks by making them an array inside the
SLAVIO_TimerState struct instead of allocating a compile-time-fixed
number of them each individually with g_new0() and then throwing away
the pointer.
Avoid the ptimer() leak by calling ptimer_free in
instance_finalize().
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/timer/slavio_timer.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index 4a3e227fba..eccdc532fb 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -62,20 +62,21 @@ typedef struct CPUTimerState {
#define TYPE_SLAVIO_TIMER "slavio_timer"
OBJECT_DECLARE_SIMPLE_TYPE(SLAVIO_TIMERState, SLAVIO_TIMER)
+typedef struct TimerContext {
+ MemoryRegion iomem;
+ SLAVIO_TIMERState *s;
+ unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
+} TimerContext;
+
struct SLAVIO_TIMERState {
SysBusDevice parent_obj;
uint32_t num_cpus;
uint32_t cputimer_mode;
CPUTimerState cputimer[MAX_CPUS + 1];
+ TimerContext timer_context[MAX_CPUS + 1];
};
-typedef struct TimerContext {
- MemoryRegion iomem;
- SLAVIO_TIMERState *s;
- unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
-} TimerContext;
-
#define SYS_TIMER_SIZE 0x14
#define CPU_TIMER_SIZE 0x10
@@ -400,7 +401,7 @@ static void slavio_timer_init(Object *obj)
uint64_t size;
char timer_name[20];
- tc = g_new0(TimerContext, 1);
+ tc = &s->timer_context[i];
tc->s = s;
tc->timer_index = i;
@@ -420,6 +421,15 @@ static void slavio_timer_init(Object *obj)
}
}
+static void slavio_timer_finalize(Object *obj)
+{
+ SLAVIO_TIMERState *s = SLAVIO_TIMER(obj);
+
+ for (int i = 0; i <= MAX_CPUS; i++) {
+ ptimer_free(s->cputimer[i].timer);
+ }
+}
+
static const Property slavio_timer_properties[] = {
DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
};
@@ -438,6 +448,7 @@ static const TypeInfo slavio_timer_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SLAVIO_TIMERState),
.instance_init = slavio_timer_init,
+ .instance_finalize = slavio_timer_finalize,
.class_init = slavio_timer_class_init,
};
--
2.43.0
On 07/03/2026 11:29, Peter Maydell wrote:
> The slavio_timer device's instance_init function allocates memory for
> TimerContext structs and a ptimer, but it never frees this memory, so
> we will leak it if the QMP interface does introspection of this
> device type, as reported by the clang address sanitizer:
>
> Indirect leak of 4896 byte(s) in 17 object(s) allocated from:
> #0 0x5f2948d9b14d in calloc (/home/pm215/qemu/build/san/qemu-system-sparc+0xe0c14d) (BuildId: 7210711bdf6f7fbd0b863bd2dfcc7c42c7175db1)
> #1 0x758584b11771 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x63771) (BuildId: 116e142b9b52c8a4dfd403e759e71ab8f95d8bb3)
> #2 0x5f2949097b8a in slavio_timer_init /home/pm215/qemu/build/san/../../hw/timer/slavio_timer.c:403:14
> #3 0x5f29495d790f in object_initialize_with_type /home/pm215/qemu/build/san/../../qom/object.c:570:5
> #4 0x5f29495d96ef in object_new_with_type /home/pm215/qemu/build/san/../../qom/object.c:774:5
> #5 0x5f2949a30a26 in qmp_device_list_properties /home/pm215/qemu/build/san/../../qom/qom-qmp-cmds.c:206:11
>
> Indirect leak of 1632 byte(s) in 17 object(s) allocated from:
> #0 0x5f2948d9b14d in calloc (/home/pm215/qemu/build/san/qemu-system-sparc+0xe0c14d) (BuildId: 7210711bdf6f7fbd0b863bd2dfcc7c42c7175db1)
> #1 0x758584b11771 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x63771) (BuildId: 116e142b9b52c8a4dfd403e759e71ab8f95d8bb3)
> #2 0x5f2948f7c65a in ptimer_init /home/pm215/qemu/build/san/../../hw/core/ptimer.c:464:9
> #3 0x5f2949097c1f in slavio_timer_init /home/pm215/qemu/build/san/../../hw/timer/slavio_timer.c:407:32
> #4 0x5f29495d790f in object_initialize_with_type /home/pm215/qemu/build/san/../../qom/object.c:570:5
> #5 0x5f29495d96ef in object_new_with_type /home/pm215/qemu/build/san/../../qom/object.c:774:5
> #6 0x5f2949a30a26 in qmp_device_list_properties /home/pm215/qemu/build/san/../../qom/qom-qmp-cmds.c:206:11
>
> Avoid the TimerContext leaks by making them an array inside the
> SLAVIO_TimerState struct instead of allocating a compile-time-fixed
> number of them each individually with g_new0() and then throwing away
> the pointer.
>
> Avoid the ptimer() leak by calling ptimer_free in
> instance_finalize().
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/timer/slavio_timer.c | 25 ++++++++++++++++++-------
> 1 file changed, 18 insertions(+), 7 deletions(-)
>
> diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
> index 4a3e227fba..eccdc532fb 100644
> --- a/hw/timer/slavio_timer.c
> +++ b/hw/timer/slavio_timer.c
> @@ -62,20 +62,21 @@ typedef struct CPUTimerState {
> #define TYPE_SLAVIO_TIMER "slavio_timer"
> OBJECT_DECLARE_SIMPLE_TYPE(SLAVIO_TIMERState, SLAVIO_TIMER)
>
> +typedef struct TimerContext {
> + MemoryRegion iomem;
> + SLAVIO_TIMERState *s;
> + unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
> +} TimerContext;
> +
> struct SLAVIO_TIMERState {
> SysBusDevice parent_obj;
>
> uint32_t num_cpus;
> uint32_t cputimer_mode;
> CPUTimerState cputimer[MAX_CPUS + 1];
> + TimerContext timer_context[MAX_CPUS + 1];
> };
>
> -typedef struct TimerContext {
> - MemoryRegion iomem;
> - SLAVIO_TIMERState *s;
> - unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
> -} TimerContext;
> -
> #define SYS_TIMER_SIZE 0x14
> #define CPU_TIMER_SIZE 0x10
>
> @@ -400,7 +401,7 @@ static void slavio_timer_init(Object *obj)
> uint64_t size;
> char timer_name[20];
>
> - tc = g_new0(TimerContext, 1);
> + tc = &s->timer_context[i];
> tc->s = s;
> tc->timer_index = i;
>
> @@ -420,6 +421,15 @@ static void slavio_timer_init(Object *obj)
> }
> }
>
> +static void slavio_timer_finalize(Object *obj)
> +{
> + SLAVIO_TIMERState *s = SLAVIO_TIMER(obj);
> +
> + for (int i = 0; i <= MAX_CPUS; i++) {
> + ptimer_free(s->cputimer[i].timer);
> + }
> +}
> +
> static const Property slavio_timer_properties[] = {
> DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
> };
> @@ -438,6 +448,7 @@ static const TypeInfo slavio_timer_info = {
> .parent = TYPE_SYS_BUS_DEVICE,
> .instance_size = sizeof(SLAVIO_TIMERState),
> .instance_init = slavio_timer_init,
> + .instance_finalize = slavio_timer_finalize,
> .class_init = slavio_timer_class_init,
> };
Reviewed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
ATB,
Mark.
On 7/3/26 12:29, Peter Maydell wrote: > The slavio_timer device's instance_init function allocates memory for > TimerContext structs and a ptimer, but it never frees this memory, so > we will leak it if the QMP interface does introspection of this > device type, as reported by the clang address sanitizer: > > Indirect leak of 4896 byte(s) in 17 object(s) allocated from: > #0 0x5f2948d9b14d in calloc (/home/pm215/qemu/build/san/qemu-system-sparc+0xe0c14d) (BuildId: 7210711bdf6f7fbd0b863bd2dfcc7c42c7175db1) > #1 0x758584b11771 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x63771) (BuildId: 116e142b9b52c8a4dfd403e759e71ab8f95d8bb3) > #2 0x5f2949097b8a in slavio_timer_init /home/pm215/qemu/build/san/../../hw/timer/slavio_timer.c:403:14 > #3 0x5f29495d790f in object_initialize_with_type /home/pm215/qemu/build/san/../../qom/object.c:570:5 > #4 0x5f29495d96ef in object_new_with_type /home/pm215/qemu/build/san/../../qom/object.c:774:5 > #5 0x5f2949a30a26 in qmp_device_list_properties /home/pm215/qemu/build/san/../../qom/qom-qmp-cmds.c:206:11 > > Indirect leak of 1632 byte(s) in 17 object(s) allocated from: > #0 0x5f2948d9b14d in calloc (/home/pm215/qemu/build/san/qemu-system-sparc+0xe0c14d) (BuildId: 7210711bdf6f7fbd0b863bd2dfcc7c42c7175db1) > #1 0x758584b11771 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x63771) (BuildId: 116e142b9b52c8a4dfd403e759e71ab8f95d8bb3) > #2 0x5f2948f7c65a in ptimer_init /home/pm215/qemu/build/san/../../hw/core/ptimer.c:464:9 > #3 0x5f2949097c1f in slavio_timer_init /home/pm215/qemu/build/san/../../hw/timer/slavio_timer.c:407:32 > #4 0x5f29495d790f in object_initialize_with_type /home/pm215/qemu/build/san/../../qom/object.c:570:5 > #5 0x5f29495d96ef in object_new_with_type /home/pm215/qemu/build/san/../../qom/object.c:774:5 > #6 0x5f2949a30a26 in qmp_device_list_properties /home/pm215/qemu/build/san/../../qom/qom-qmp-cmds.c:206:11 > > Avoid the TimerContext leaks by making them an array inside the > SLAVIO_TimerState struct instead of allocating a compile-time-fixed > number of them each individually with g_new0() and then throwing away > the pointer. > > Avoid the ptimer() leak by calling ptimer_free in > instance_finalize(). > > Signed-off-by: Peter Maydell <peter.maydell@linaro.org> > --- > hw/timer/slavio_timer.c | 25 ++++++++++++++++++------- > 1 file changed, 18 insertions(+), 7 deletions(-) Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
© 2016 - 2026 Red Hat, Inc.