[PATCH 2/4] hw/arm: use g_autofree for fdt in arm_load_dtb

Alex Bennée posted 4 patches 3 weeks, 6 days ago
There is a newer version of this series
[PATCH 2/4] hw/arm: use g_autofree for fdt in arm_load_dtb
Posted by Alex Bennée 3 weeks, 6 days ago
With the fdt being protected by g_autofree we can skip the goto fail
and bail out straight away. The only thing we must take care of is
stealing the pointer in the one case when we do need it to survive.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 hw/arm/boot.c | 29 ++++++++++++-----------------
 1 file changed, 12 insertions(+), 17 deletions(-)

diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 56fd13b9f7c..749f2d08341 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -519,7 +519,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
                  hwaddr addr_limit, AddressSpace *as, MachineState *ms,
                  ARMCPU *cpu)
 {
-    void *fdt = NULL;
+    g_autofree void *fdt = NULL;
     int size, rc, n = 0;
     uint32_t acells, scells;
     unsigned int i;
@@ -538,13 +538,13 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
         fdt = load_device_tree(filename, &size);
         if (!fdt) {
             fprintf(stderr, "Couldn't open dtb file %s\n", filename);
-            goto fail;
+            return -1;
         }
     } else {
         fdt = binfo->get_dtb(binfo, &size);
         if (!fdt) {
             fprintf(stderr, "Board was unable to create a dtb blob\n");
-            goto fail;
+            return -1;
         }
     }
 
@@ -553,7 +553,6 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
          * Whether this constitutes failure is up to the caller to decide,
          * so just return 0 as size, i.e., no error.
          */
-        g_free(fdt);
         return 0;
     }
 
@@ -563,7 +562,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
                                    NULL, &error_fatal);
     if (acells == 0 || scells == 0) {
         fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
-        goto fail;
+        return -1;
     }
 
     if (scells < 2 && binfo->ram_size >= 4 * GiB) {
@@ -572,14 +571,14 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
          */
         fprintf(stderr, "qemu: dtb file not compatible with "
                 "RAM size > 4GB\n");
-        goto fail;
+        return -1;
     }
 
     /* nop all root nodes matching /memory or /memory@unit-address */
     node_path = qemu_fdt_node_unit_path(fdt, "memory", &err);
     if (err) {
         error_report_err(err);
-        goto fail;
+        return -1;
     }
     while (node_path[n]) {
         if (g_str_has_prefix(node_path[n], "/memory")) {
@@ -611,7 +610,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
             if (rc < 0) {
                 fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n",
                         mem_base);
-                goto fail;
+                return -1;
             }
 
             mem_base += mem_len;
@@ -622,7 +621,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
         if (rc < 0) {
             fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n",
                     binfo->loader_start);
-            goto fail;
+            return -1;
         }
     }
 
@@ -636,7 +635,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
                                      ms->kernel_cmdline);
         if (rc < 0) {
             fprintf(stderr, "couldn't set /chosen/bootargs\n");
-            goto fail;
+            return -1;
         }
     }
 
@@ -645,7 +644,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
                                           acells, binfo->initrd_start);
         if (rc < 0) {
             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
-            goto fail;
+            return -1;
         }
 
         rc = qemu_fdt_setprop_sized_cells(fdt, "/chosen", "linux,initrd-end",
@@ -654,7 +653,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
                                           binfo->initrd_size);
         if (rc < 0) {
             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
-            goto fail;
+            return -1;
         }
     }
 
@@ -673,14 +672,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
 
     if (fdt != ms->fdt) {
         g_free(ms->fdt);
-        ms->fdt = fdt;
+        ms->fdt = g_steal_pointer(&fdt);
     }
 
     return size;
-
-fail:
-    g_free(fdt);
-    return -1;
 }
 
 static void do_cpu_reset(void *opaque)
-- 
2.47.2


Re: [PATCH 2/4] hw/arm: use g_autofree for fdt in arm_load_dtb
Posted by Peter Maydell 3 weeks, 5 days ago
On Mon, 1 Sept 2025 at 13:53, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> With the fdt being protected by g_autofree we can skip the goto fail
> and bail out straight away. The only thing we must take care of is
> stealing the pointer in the one case when we do need it to survive.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  hw/arm/boot.c | 29 ++++++++++++-----------------
>  1 file changed, 12 insertions(+), 17 deletions(-)
>
> diff --git a/hw/arm/boot.c b/hw/arm/boot.c
> index 56fd13b9f7c..749f2d08341 100644
> --- a/hw/arm/boot.c
> +++ b/hw/arm/boot.c
> @@ -519,7 +519,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>                   hwaddr addr_limit, AddressSpace *as, MachineState *ms,
>                   ARMCPU *cpu)
>  {
> -    void *fdt = NULL;
> +    g_autofree void *fdt = NULL;
>      int size, rc, n = 0;
>      uint32_t acells, scells;
>      unsigned int i;


> @@ -673,14 +672,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>
>      if (fdt != ms->fdt) {
>          g_free(ms->fdt);
> -        ms->fdt = fdt;
> +        ms->fdt = g_steal_pointer(&fdt);
>      }
>
>      return size;
> -> -fail:
> -    g_free(fdt);
> -    return -1;
>  }

Previously, if we get to the end of the function and fdt == ms->fdt
then we continue to use that DTB, and we don't free it.
After this change, if fdt == ms->fdt then we will skip the
g_steal_pointer() and the g_autofree will free the memory,
but leave ms->fdt still pointing to it.

Since arm_load_dtb() is only called once it's a bit unclear
to me whether this can happen -- I think you would need to have
a board-specific arm_boot_info::get_dtb function which returned
the MachineState::fdt pointer. But as this is supposed to
just be a refactoring patch and the previous code clearly was
written to account for the possibility of fdt == ms->fdt,
I think we should continue to handle that case.

thanks
-- PMM
Re: [PATCH 2/4] hw/arm: use g_autofree for fdt in arm_load_dtb
Posted by Alex Bennée 3 weeks, 4 days ago
Peter Maydell <peter.maydell@linaro.org> writes:

> On Mon, 1 Sept 2025 at 13:53, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> With the fdt being protected by g_autofree we can skip the goto fail
>> and bail out straight away. The only thing we must take care of is
>> stealing the pointer in the one case when we do need it to survive.
>>
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> ---
>>  hw/arm/boot.c | 29 ++++++++++++-----------------
>>  1 file changed, 12 insertions(+), 17 deletions(-)
>>
>> diff --git a/hw/arm/boot.c b/hw/arm/boot.c
>> index 56fd13b9f7c..749f2d08341 100644
>> --- a/hw/arm/boot.c
>> +++ b/hw/arm/boot.c
>> @@ -519,7 +519,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>>                   hwaddr addr_limit, AddressSpace *as, MachineState *ms,
>>                   ARMCPU *cpu)
>>  {
>> -    void *fdt = NULL;
>> +    g_autofree void *fdt = NULL;
>>      int size, rc, n = 0;
>>      uint32_t acells, scells;
>>      unsigned int i;
>
>
>> @@ -673,14 +672,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>>
>>      if (fdt != ms->fdt) {
>>          g_free(ms->fdt);
>> -        ms->fdt = fdt;
>> +        ms->fdt = g_steal_pointer(&fdt);
>>      }
>>
>>      return size;
>> -> -fail:
>> -    g_free(fdt);
>> -    return -1;
>>  }
>
> Previously, if we get to the end of the function and fdt == ms->fdt
> then we continue to use that DTB, and we don't free it.
> After this change, if fdt == ms->fdt then we will skip the
> g_steal_pointer() and the g_autofree will free the memory,
> but leave ms->fdt still pointing to it.
>
> Since arm_load_dtb() is only called once it's a bit unclear
> to me whether this can happen -- I think you would need to have
> a board-specific arm_boot_info::get_dtb function which returned
> the MachineState::fdt pointer. But as this is supposed to
> just be a refactoring patch and the previous code clearly was
> written to account for the possibility of fdt == ms->fdt,
> I think we should continue to handle that case.

Hmm I was thinking we could assert if ms->fdt is set because we clearly
shouldn't be loading one. For arm the only thing that sets ms->fdt is
create_fdt which also implies:

  vms->bootinfo.skip_dtb_autoload = true;

so on start-up we should either create or load - not both.

but then I am confused about why we do another arm_load_dtb in the
machine_done notifier.

Either way I can't see how fdt = g_malloc0(dt_size) could ever match
what might already be in ms->fdt.


>
> thanks
> -- PMM

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro
Re: [PATCH 2/4] hw/arm: use g_autofree for fdt in arm_load_dtb
Posted by Alex Bennée 3 weeks, 4 days ago
Alex Bennée <alex.bennee@linaro.org> writes:

> Peter Maydell <peter.maydell@linaro.org> writes:
>
>> On Mon, 1 Sept 2025 at 13:53, Alex Bennée <alex.bennee@linaro.org> wrote:
>>>
>>> With the fdt being protected by g_autofree we can skip the goto fail
>>> and bail out straight away. The only thing we must take care of is
>>> stealing the pointer in the one case when we do need it to survive.
>>>
>>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>> ---
>>>  hw/arm/boot.c | 29 ++++++++++++-----------------
>>>  1 file changed, 12 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/hw/arm/boot.c b/hw/arm/boot.c
>>> index 56fd13b9f7c..749f2d08341 100644
>>> --- a/hw/arm/boot.c
>>> +++ b/hw/arm/boot.c
>>> @@ -519,7 +519,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>>>                   hwaddr addr_limit, AddressSpace *as, MachineState *ms,
>>>                   ARMCPU *cpu)
>>>  {
>>> -    void *fdt = NULL;
>>> +    g_autofree void *fdt = NULL;
>>>      int size, rc, n = 0;
>>>      uint32_t acells, scells;
>>>      unsigned int i;
>>
>>
>>> @@ -673,14 +672,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>>>
>>>      if (fdt != ms->fdt) {
>>>          g_free(ms->fdt);
>>> -        ms->fdt = fdt;
>>> +        ms->fdt = g_steal_pointer(&fdt);
>>>      }
>>>
>>>      return size;
>>> -> -fail:
>>> -    g_free(fdt);
>>> -    return -1;
>>>  }
>>
>> Previously, if we get to the end of the function and fdt == ms->fdt
>> then we continue to use that DTB, and we don't free it.
>> After this change, if fdt == ms->fdt then we will skip the
>> g_steal_pointer() and the g_autofree will free the memory,
>> but leave ms->fdt still pointing to it.
>>
>> Since arm_load_dtb() is only called once it's a bit unclear
>> to me whether this can happen -- I think you would need to have
>> a board-specific arm_boot_info::get_dtb function which returned
>> the MachineState::fdt pointer. But as this is supposed to
>> just be a refactoring patch and the previous code clearly was
>> written to account for the possibility of fdt == ms->fdt,
>> I think we should continue to handle that case.
>
> Hmm I was thinking we could assert if ms->fdt is set because we clearly
> shouldn't be loading one. For arm the only thing that sets ms->fdt is
> create_fdt which also implies:
>
>   vms->bootinfo.skip_dtb_autoload = true;
>
> so on start-up we should either create or load - not both.
>
> but then I am confused about why we do another arm_load_dtb in the
> machine_done notifier.
>
> Either way I can't see how fdt = g_malloc0(dt_size) could ever match
> what might already be in ms->fdt.

Ahh I see it now.
>
>
>>
>> thanks
>> -- PMM

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro
Re: [PATCH 2/4] hw/arm: use g_autofree for fdt in arm_load_dtb
Posted by Peter Maydell 3 weeks, 4 days ago
On Wed, 3 Sept 2025 at 09:16, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Peter Maydell <peter.maydell@linaro.org> writes:
>
> > On Mon, 1 Sept 2025 at 13:53, Alex Bennée <alex.bennee@linaro.org> wrote:
> >>
> >> With the fdt being protected by g_autofree we can skip the goto fail
> >> and bail out straight away. The only thing we must take care of is
> >> stealing the pointer in the one case when we do need it to survive.
> >>
> >> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> >> ---
> >>  hw/arm/boot.c | 29 ++++++++++++-----------------
> >>  1 file changed, 12 insertions(+), 17 deletions(-)
> >>
> >> diff --git a/hw/arm/boot.c b/hw/arm/boot.c
> >> index 56fd13b9f7c..749f2d08341 100644
> >> --- a/hw/arm/boot.c
> >> +++ b/hw/arm/boot.c
> >> @@ -519,7 +519,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
> >>                   hwaddr addr_limit, AddressSpace *as, MachineState *ms,
> >>                   ARMCPU *cpu)
> >>  {
> >> -    void *fdt = NULL;
> >> +    g_autofree void *fdt = NULL;
> >>      int size, rc, n = 0;
> >>      uint32_t acells, scells;
> >>      unsigned int i;
> >
> >
> >> @@ -673,14 +672,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
> >>
> >>      if (fdt != ms->fdt) {
> >>          g_free(ms->fdt);
> >> -        ms->fdt = fdt;
> >> +        ms->fdt = g_steal_pointer(&fdt);
> >>      }
> >>
> >>      return size;
> >> -> -fail:
> >> -    g_free(fdt);
> >> -    return -1;
> >>  }
> >
> > Previously, if we get to the end of the function and fdt == ms->fdt
> > then we continue to use that DTB, and we don't free it.
> > After this change, if fdt == ms->fdt then we will skip the
> > g_steal_pointer() and the g_autofree will free the memory,
> > but leave ms->fdt still pointing to it.
> >
> > Since arm_load_dtb() is only called once it's a bit unclear
> > to me whether this can happen -- I think you would need to have
> > a board-specific arm_boot_info::get_dtb function which returned
> > the MachineState::fdt pointer. But as this is supposed to
> > just be a refactoring patch and the previous code clearly was
> > written to account for the possibility of fdt == ms->fdt,
> > I think we should continue to handle that case.
>
> Hmm I was thinking we could assert if ms->fdt is set because we clearly
> shouldn't be loading one. For arm the only thing that sets ms->fdt is
> create_fdt which also implies:
>
>   vms->bootinfo.skip_dtb_autoload = true;
>
> so on start-up we should either create or load - not both.
>
> but then I am confused about why we do another arm_load_dtb in the
> machine_done notifier.
>
> Either way I can't see how fdt = g_malloc0(dt_size) could ever match
> what might already be in ms->fdt.

Yeah, I don't think it's really going to happen (at least at the
moment: if somebody refactored hw/arm/sbsa-ref.c so that it used
MachineState::fdt rather than having a sort-of-duplicate
SBSAMachinestate::fdt then I think you can end up here).
But mostly my point is that I don't want to have to think about
this and audit all the arm boards with a get_dtb method when
I'm reviewing a patch which is supposed to just be switching this
function from explicit-free to g_autofree...

-- PMM
Re: [PATCH 2/4] hw/arm: use g_autofree for fdt in arm_load_dtb
Posted by Manos Pitsidianakis 3 weeks, 6 days ago
On Mon, Sep 1, 2025 at 3:53 PM Alex Bennée <alex.bennee@linaro.org> wrote:
>
> With the fdt being protected by g_autofree we can skip the goto fail
> and bail out straight away. The only thing we must take care of is
> stealing the pointer in the one case when we do need it to survive.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>


>  hw/arm/boot.c | 29 ++++++++++++-----------------
>  1 file changed, 12 insertions(+), 17 deletions(-)
>
> diff --git a/hw/arm/boot.c b/hw/arm/boot.c
> index 56fd13b9f7c..749f2d08341 100644
> --- a/hw/arm/boot.c
> +++ b/hw/arm/boot.c
> @@ -519,7 +519,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>                   hwaddr addr_limit, AddressSpace *as, MachineState *ms,
>                   ARMCPU *cpu)
>  {
> -    void *fdt = NULL;
> +    g_autofree void *fdt = NULL;
>      int size, rc, n = 0;
>      uint32_t acells, scells;
>      unsigned int i;
> @@ -538,13 +538,13 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>          fdt = load_device_tree(filename, &size);
>          if (!fdt) {
>              fprintf(stderr, "Couldn't open dtb file %s\n", filename);
> -            goto fail;
> +            return -1;
>          }
>      } else {
>          fdt = binfo->get_dtb(binfo, &size);
>          if (!fdt) {
>              fprintf(stderr, "Board was unable to create a dtb blob\n");
> -            goto fail;
> +            return -1;
>          }
>      }
>
> @@ -553,7 +553,6 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>           * Whether this constitutes failure is up to the caller to decide,
>           * so just return 0 as size, i.e., no error.
>           */
> -        g_free(fdt);
>          return 0;
>      }
>
> @@ -563,7 +562,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>                                     NULL, &error_fatal);
>      if (acells == 0 || scells == 0) {
>          fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
> -        goto fail;
> +        return -1;
>      }
>
>      if (scells < 2 && binfo->ram_size >= 4 * GiB) {
> @@ -572,14 +571,14 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>           */
>          fprintf(stderr, "qemu: dtb file not compatible with "
>                  "RAM size > 4GB\n");
> -        goto fail;
> +        return -1;
>      }
>
>      /* nop all root nodes matching /memory or /memory@unit-address */
>      node_path = qemu_fdt_node_unit_path(fdt, "memory", &err);
>      if (err) {
>          error_report_err(err);
> -        goto fail;
> +        return -1;
>      }
>      while (node_path[n]) {
>          if (g_str_has_prefix(node_path[n], "/memory")) {
> @@ -611,7 +610,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>              if (rc < 0) {
>                  fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n",
>                          mem_base);
> -                goto fail;
> +                return -1;
>              }
>
>              mem_base += mem_len;
> @@ -622,7 +621,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>          if (rc < 0) {
>              fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n",
>                      binfo->loader_start);
> -            goto fail;
> +            return -1;
>          }
>      }
>
> @@ -636,7 +635,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>                                       ms->kernel_cmdline);
>          if (rc < 0) {
>              fprintf(stderr, "couldn't set /chosen/bootargs\n");
> -            goto fail;
> +            return -1;
>          }
>      }
>
> @@ -645,7 +644,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>                                            acells, binfo->initrd_start);
>          if (rc < 0) {
>              fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
> -            goto fail;
> +            return -1;
>          }
>
>          rc = qemu_fdt_setprop_sized_cells(fdt, "/chosen", "linux,initrd-end",
> @@ -654,7 +653,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>                                            binfo->initrd_size);
>          if (rc < 0) {
>              fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
> -            goto fail;
> +            return -1;
>          }
>      }
>
> @@ -673,14 +672,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
>
>      if (fdt != ms->fdt) {
>          g_free(ms->fdt);
> -        ms->fdt = fdt;
> +        ms->fdt = g_steal_pointer(&fdt);
>      }
>
>      return size;
> -
> -fail:
> -    g_free(fdt);
> -    return -1;
>  }
>
>  static void do_cpu_reset(void *opaque)
> --
> 2.47.2
>
>