On Wed, 17 Jun 2026, Paolo Bonzini wrote:
On 6/16/26 17:55, Daniel P. Berrangé wrote:
Prepare for the move to dynamically allocated memory regions by
introducing memory_region_new and memory_region_new_io functions
which call through to object_new instead of object_initialize.

TBD: add "new" variants for all the other memory_region_init
variants.

Signed-off-by: Daniel P. Berrangé <[email protected]>

Zoltan already proposed this, but I really think it's a bad idea.

MemoryRegionOps callback will certainly access fields in the parent. Having a separate object gives you no benefit because you still have the same use-after-free if the MemoryRegion outlives the device. Likewise for buses.

For buses, the fact that the parent and child live at the same time is explicitly tracked with mutual refcount and unparent. If it's not, we have the hack that Akihiko mentioned (https://lists.gnu.org/archive/html/qemu-devel/2026-06/msg03459.html):

However, this is insufficient to avoid calling object_ref() for all
embedded objects. For example, consider an embedded Device that has a
MemoryRegion. When referencing a MemoryRegion for guest memory access,
QEMU automatically references the owning Device to keep the MemoryRegion
alive. However, that reference is ineffective if the Device itself is
embedded, because object_ref() does not keep the containing storage
alive.

If the device itself is embedded, then all the invariants must hold recursively:

- the device must be kept alive by mutual references between the device itself and its parent;

- unparent for the device should wait for all guest memory accesses to be either completed or cancelled.

So, the problem is that "QEMU automatically references the owning Device to keep the MemoryRegion alive" is a hack that should die. I added it, mea culpa.

The model is that if it makes sense to have B outlive A, you use new. If it doesn't, you use init. For MemoryRegions or anything that has callbacks, it makes no sense to outlive the implementor of the callbacks. There are exceptions if the number of objects is dynamic but they're very rare.

I agree that there's extra complexity added by embedding; but I disagree that removing embedding will fix any bugs, and because it will hide a relationship between objects, I believe the complexity is not accidental.

The problem is that memory regions cannot be ref counted because they are piggybacking on their owner's ref count instead of using their own. So while memory regions are QOM objects and the code is there to ref count and free them with their owners this can't be used and we hack around that by referencing the owner instead. If there's a dependency on the parent then maybe the memory region should take a ref of the parent so it does not go away until the memory region is freed or the owner relation needs to be taken into account instead of using the parent ref count and forbidding to make memory regions proper QOM objects which is very confusing and leads to all sorts of other hacks.

And it also forces me to embed a bunch of memory regions in device states that are otherwise not needed and already stored as PCI BARs or sysbus regions so I should not need them in my device state. This added complexity was my motivation but it turned out to be a larger issue and I think restoring the ability to ref count memory regions and clean up the hacks of keeping the parent alive with every object using its own ref counts would be cleaner than keeping to the current way.

Regards,
BALATON Zoltan

Reply via email to