* [PATCH v2] migration/options: Fix leaks in StrOrNull qdev accessors @ 2026-01-27 15:09 Fabiano Rosas 2026-01-27 15:26 ` Peter Xu 2026-02-13 9:09 ` Markus Armbruster 0 siblings, 2 replies; 5+ messages in thread From: Fabiano Rosas @ 2026-01-27 15:09 UTC (permalink / raw) To: qemu-devel; +Cc: peterx, armbru, ppandit, Peter Maydell Fix a couple of leaks detected by Coverity. Both are currently harmless. - set_StrOrNull: the visitor should never fail unless there's a programming error and a property of different type has been passed in. Change it to only allocate memory after the visit call has returned successfully. - get_StrOrNull: the whole of the getter is unused, it's only purpose at the moment is to provide a complete implementation of the StrOrNull property. If it were used, it would always receive a non-NULL pointer because this property is part of s->parameters and always initialized by the setter. Assert non-NULL instead of allocating a new object. Fixes: CID 1643919 Fixes: CID 1643920 Reported-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Fabiano Rosas <farosas@suse.de> --- migration/options.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/migration/options.c b/migration/options.c index 1ffe85a2d8..93d11bba60 100644 --- a/migration/options.c +++ b/migration/options.c @@ -216,36 +216,36 @@ const size_t migration_properties_count = ARRAY_SIZE(migration_properties); static void get_StrOrNull(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - const Property *prop = opaque; - StrOrNull **ptr = object_field_prop_ptr(obj, prop); + StrOrNull **ptr = object_field_prop_ptr(obj, opaque); StrOrNull *str_or_null = *ptr; - if (!str_or_null) { - str_or_null = g_new0(StrOrNull, 1); - str_or_null->type = QTYPE_QSTRING; - str_or_null->u.s = g_strdup(""); - } else { - /* the setter doesn't allow QNULL */ - assert(str_or_null->type != QTYPE_QNULL); - } + /* + * The property should never be NULL because it's part of + * s->parameters and a default value is always set. It should also + * never be QNULL as the setter doesn't allow it. + */ + assert(str_or_null && str_or_null->type != QTYPE_QNULL); visit_type_str(v, name, &str_or_null->u.s, errp); } static void set_StrOrNull(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - const Property *prop = opaque; - StrOrNull **ptr = object_field_prop_ptr(obj, prop); - StrOrNull *str_or_null = g_new0(StrOrNull, 1); + StrOrNull **ptr = object_field_prop_ptr(obj, opaque); + StrOrNull *str_or_null; + char *str; + + if (!visit_type_str(v, name, &str, errp)) { + return; + } /* * Only str to keep compatibility, QNULL was never used via * command line. */ + str_or_null = g_new0(StrOrNull, 1); str_or_null->type = QTYPE_QSTRING; - if (!visit_type_str(v, name, &str_or_null->u.s, errp)) { - return; - } + str_or_null->u.s = str; qapi_free_StrOrNull(*ptr); *ptr = str_or_null; -- 2.51.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2] migration/options: Fix leaks in StrOrNull qdev accessors 2026-01-27 15:09 [PATCH v2] migration/options: Fix leaks in StrOrNull qdev accessors Fabiano Rosas @ 2026-01-27 15:26 ` Peter Xu 2026-02-13 9:09 ` Markus Armbruster 1 sibling, 0 replies; 5+ messages in thread From: Peter Xu @ 2026-01-27 15:26 UTC (permalink / raw) To: Fabiano Rosas; +Cc: qemu-devel, armbru, ppandit, Peter Maydell On Tue, Jan 27, 2026 at 12:09:16PM -0300, Fabiano Rosas wrote: > Fix a couple of leaks detected by Coverity. Both are currently > harmless. > > - set_StrOrNull: the visitor should never fail unless there's a > programming error and a property of different type has been passed in. > > Change it to only allocate memory after the visit call has returned > successfully. > > - get_StrOrNull: the whole of the getter is unused, it's only purpose at > the moment is to provide a complete implementation of the StrOrNull > property. If it were used, it would always receive a non-NULL pointer > because this property is part of s->parameters and always initialized > by the setter. > > Assert non-NULL instead of allocating a new object. > > Fixes: CID 1643919 > Fixes: CID 1643920 > Reported-by: Peter Maydell <peter.maydell@linaro.org> > Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> -- Peter Xu ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] migration/options: Fix leaks in StrOrNull qdev accessors 2026-01-27 15:09 [PATCH v2] migration/options: Fix leaks in StrOrNull qdev accessors Fabiano Rosas 2026-01-27 15:26 ` Peter Xu @ 2026-02-13 9:09 ` Markus Armbruster 2026-02-13 12:39 ` Fabiano Rosas 1 sibling, 1 reply; 5+ messages in thread From: Markus Armbruster @ 2026-02-13 9:09 UTC (permalink / raw) To: Fabiano Rosas; +Cc: qemu-devel, peterx, ppandit, Peter Maydell Fabiano Rosas <farosas@suse.de> writes: > Fix a couple of leaks detected by Coverity. Both are currently > harmless. Details? See below. > - set_StrOrNull: the visitor should never fail unless there's a > programming error and a property of different type has been passed in. Really? See below. > Change it to only allocate memory after the visit call has returned > successfully. > > - get_StrOrNull: the whole of the getter is unused, it's only purpose at > the moment is to provide a complete implementation of the StrOrNull > property. If it were used, it would always receive a non-NULL pointer > because this property is part of s->parameters and always initialized > by the setter. Which "received" pointer exactly would always be non-null? See below. > Assert non-NULL instead of allocating a new object. > > Fixes: CID 1643919 > Fixes: CID 1643920 > Reported-by: Peter Maydell <peter.maydell@linaro.org> > Signed-off-by: Fabiano Rosas <farosas@suse.de> > --- > migration/options.c | 32 ++++++++++++++++---------------- > 1 file changed, 16 insertions(+), 16 deletions(-) > > diff --git a/migration/options.c b/migration/options.c > index 1ffe85a2d8..93d11bba60 100644 > --- a/migration/options.c > +++ b/migration/options.c > @@ -216,36 +216,36 @@ const size_t migration_properties_count = ARRAY_SIZE(migration_properties); > static void get_StrOrNull(Object *obj, Visitor *v, const char *name, > void *opaque, Error **errp) > { > - const Property *prop = opaque; Yes, we don't actually need the variable. However, it serves as documentation of what @opaque is supposed to be. For what it's worth, the property accessors defined in hw/core all declare the variable > - StrOrNull **ptr = object_field_prop_ptr(obj, prop); > + StrOrNull **ptr = object_field_prop_ptr(obj, opaque); > StrOrNull *str_or_null = *ptr; > > - if (!str_or_null) { > - str_or_null = g_new0(StrOrNull, 1); > - str_or_null->type = QTYPE_QSTRING; > - str_or_null->u.s = g_strdup(""); The memory allocated here is never freed. Harmless, because the code is unreachable. > - } else { > - /* the setter doesn't allow QNULL */ > - assert(str_or_null->type != QTYPE_QNULL); > - } > + /* > + * The property should never be NULL because it's part of > + * s->parameters and a default value is always set. It should also > + * never be QNULL as the setter doesn't allow it. > + */ > + assert(str_or_null && str_or_null->type != QTYPE_QNULL); Actually, @str_or_null cannot be null, because @obj isn't null, and object_field_prop_ptr(obj, prop) returns a pointer into @obj. > visit_type_str(v, name, &str_or_null->u.s, errp); > } > > static void set_StrOrNull(Object *obj, Visitor *v, const char *name, > void *opaque, Error **errp) > { > - const Property *prop = opaque; > - StrOrNull **ptr = object_field_prop_ptr(obj, prop); > - StrOrNull *str_or_null = g_new0(StrOrNull, 1); > + StrOrNull **ptr = object_field_prop_ptr(obj, opaque); > + StrOrNull *str_or_null; > + char *str; > + > + if (!visit_type_str(v, name, &str, errp)) { > + return; > + } > > /* > * Only str to keep compatibility, QNULL was never used via > * command line. > */ This comment is from Fabiano's recent commit be346eb6673 (migration: Add a qdev property for StrOrNull). Fabiano, did you mean to write "Only StrOrNull to keep compatibility"? > + str_or_null = g_new0(StrOrNull, 1); > str_or_null->type = QTYPE_QSTRING; > - if (!visit_type_str(v, name, &str_or_null->u.s, errp)) { We leak @str_or_null here. You plug the leak by delaying the allocation until after visit_type_str(). Good. > - return; > - } > + str_or_null->u.s = str; > > qapi_free_StrOrNull(*ptr); > *ptr = str_or_null; The function fails only when visit_type_str() fails, and visit_type_str() fails only when v->type_str() fails. Why are you certain it won't? ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] migration/options: Fix leaks in StrOrNull qdev accessors 2026-02-13 9:09 ` Markus Armbruster @ 2026-02-13 12:39 ` Fabiano Rosas 2026-02-17 13:47 ` Markus Armbruster 0 siblings, 1 reply; 5+ messages in thread From: Fabiano Rosas @ 2026-02-13 12:39 UTC (permalink / raw) To: Markus Armbruster; +Cc: qemu-devel, peterx, ppandit, Peter Maydell Markus Armbruster <armbru@redhat.com> writes: > Fabiano Rosas <farosas@suse.de> writes: > >> Fix a couple of leaks detected by Coverity. Both are currently >> harmless. > > Details? See below. > >> - set_StrOrNull: the visitor should never fail unless there's a >> programming error and a property of different type has been passed in. > > Really? See below. > >> Change it to only allocate memory after the visit call has returned >> successfully. >> >> - get_StrOrNull: the whole of the getter is unused, it's only purpose at >> the moment is to provide a complete implementation of the StrOrNull >> property. If it were used, it would always receive a non-NULL pointer >> because this property is part of s->parameters and always initialized >> by the setter. > > Which "received" pointer exactly would always be non-null? See below. > Not technically "received", but derived from what has been received. >> Assert non-NULL instead of allocating a new object. >> >> Fixes: CID 1643919 >> Fixes: CID 1643920 >> Reported-by: Peter Maydell <peter.maydell@linaro.org> >> Signed-off-by: Fabiano Rosas <farosas@suse.de> >> --- >> migration/options.c | 32 ++++++++++++++++---------------- >> 1 file changed, 16 insertions(+), 16 deletions(-) >> >> diff --git a/migration/options.c b/migration/options.c >> index 1ffe85a2d8..93d11bba60 100644 >> --- a/migration/options.c >> +++ b/migration/options.c >> @@ -216,36 +216,36 @@ const size_t migration_properties_count = ARRAY_SIZE(migration_properties); >> static void get_StrOrNull(Object *obj, Visitor *v, const char *name, >> void *opaque, Error **errp) >> { >> - const Property *prop = opaque; > > Yes, we don't actually need the variable. However, it serves as > documentation of what @opaque is supposed to be. > > For what it's worth, the property accessors defined in hw/core all > declare the variable > >> - StrOrNull **ptr = object_field_prop_ptr(obj, prop); >> + StrOrNull **ptr = object_field_prop_ptr(obj, opaque); >> StrOrNull *str_or_null = *ptr; >> >> - if (!str_or_null) { >> - str_or_null = g_new0(StrOrNull, 1); >> - str_or_null->type = QTYPE_QSTRING; >> - str_or_null->u.s = g_strdup(""); > > The memory allocated here is never freed. Harmless, because the code is > unreachable. > >> - } else { >> - /* the setter doesn't allow QNULL */ >> - assert(str_or_null->type != QTYPE_QNULL); >> - } >> + /* >> + * The property should never be NULL because it's part of >> + * s->parameters and a default value is always set. It should also >> + * never be QNULL as the setter doesn't allow it. >> + */ >> + assert(str_or_null && str_or_null->type != QTYPE_QNULL); > > Actually, @str_or_null cannot be null, because @obj isn't null, and > object_field_prop_ptr(obj, prop) returns a pointer into @obj. > And that pointer must point to zeroes at some time. It cannot be that it comes pre-set with the property value. I'm describing that it won't point to zeroes anymore because the setter called from .set_default_value will have already set that memory to some meaningful value. >> visit_type_str(v, name, &str_or_null->u.s, errp); >> } >> >> static void set_StrOrNull(Object *obj, Visitor *v, const char *name, >> void *opaque, Error **errp) >> { >> - const Property *prop = opaque; >> - StrOrNull **ptr = object_field_prop_ptr(obj, prop); >> - StrOrNull *str_or_null = g_new0(StrOrNull, 1); >> + StrOrNull **ptr = object_field_prop_ptr(obj, opaque); >> + StrOrNull *str_or_null; >> + char *str; >> + >> + if (!visit_type_str(v, name, &str, errp)) { >> + return; >> + } >> >> /* >> * Only str to keep compatibility, QNULL was never used via >> * command line. >> */ > > This comment is from Fabiano's recent commit be346eb6673 (migration: Add > a qdev property for StrOrNull). Fabiano, did you mean to write "Only > StrOrNull to keep compatibility"? > No, it's "only str" indeed. The point is that -global tls-creds NULL was never supported, so now that we have a property, this setter will never create a QNULL to avoid ever passing a QNULL to code that used to consume tls-creds and doesn't expect a QNULL value (the "compatibility" part). >> + str_or_null = g_new0(StrOrNull, 1); >> str_or_null->type = QTYPE_QSTRING; >> - if (!visit_type_str(v, name, &str_or_null->u.s, errp)) { > > We leak @str_or_null here. You plug the leak by delaying the allocation > until after visit_type_str(). Good. > >> - return; >> - } >> + str_or_null->u.s = str; >> >> qapi_free_StrOrNull(*ptr); >> *ptr = str_or_null; > > The function fails only when visit_type_str() fails, and > visit_type_str() fails only when v->type_str() fails. > > Why are you certain it won't? By inspection, I only see the failure points at qobject_input_type_str: QObject *qobj = qobject_input_get_object(qiv, name, true, errp); ... if (!qobj) { return false; } qstr = qobject_to(QString, qobj); if (!qstr) { error_setg(errp, "Invalid parameter type for '%s', expected: string", full_name(qiv, name)); return false; } I'm relying on qdev's boilerplate not allowing incorrect invocations from the user. If code has been written that allows the .set function to be reached with a wrong type or a incorrect member name inside of a struct, for instance, then I'm calling it a programming error. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] migration/options: Fix leaks in StrOrNull qdev accessors 2026-02-13 12:39 ` Fabiano Rosas @ 2026-02-17 13:47 ` Markus Armbruster 0 siblings, 0 replies; 5+ messages in thread From: Markus Armbruster @ 2026-02-17 13:47 UTC (permalink / raw) To: Fabiano Rosas; +Cc: qemu-devel, peterx, ppandit, Peter Maydell Fabiano Rosas <farosas@suse.de> writes: > Markus Armbruster <armbru@redhat.com> writes: > >> Fabiano Rosas <farosas@suse.de> writes: >> >>> Fix a couple of leaks detected by Coverity. Both are currently >>> harmless. >> >> Details? See below. >> >>> - set_StrOrNull: the visitor should never fail unless there's a >>> programming error and a property of different type has been passed in. >> >> Really? See below. >> >>> Change it to only allocate memory after the visit call has returned >>> successfully. >>> >>> - get_StrOrNull: the whole of the getter is unused, it's only purpose at >>> the moment is to provide a complete implementation of the StrOrNull >>> property. If it were used, it would always receive a non-NULL pointer >>> because this property is part of s->parameters and always initialized >>> by the setter. >> >> Which "received" pointer exactly would always be non-null? See below. >> > > Not technically "received", but derived from what has been received. > >>> Assert non-NULL instead of allocating a new object. >>> >>> Fixes: CID 1643919 >>> Fixes: CID 1643920 >>> Reported-by: Peter Maydell <peter.maydell@linaro.org> >>> Signed-off-by: Fabiano Rosas <farosas@suse.de> >>> --- >>> migration/options.c | 32 ++++++++++++++++---------------- >>> 1 file changed, 16 insertions(+), 16 deletions(-) >>> >>> diff --git a/migration/options.c b/migration/options.c >>> index 1ffe85a2d8..93d11bba60 100644 >>> --- a/migration/options.c >>> +++ b/migration/options.c >>> @@ -216,36 +216,36 @@ const size_t migration_properties_count = ARRAY_SIZE(migration_properties); >>> static void get_StrOrNull(Object *obj, Visitor *v, const char *name, >>> void *opaque, Error **errp) >>> { >>> - const Property *prop = opaque; >> >> Yes, we don't actually need the variable. However, it serves as >> documentation of what @opaque is supposed to be. >> >> For what it's worth, the property accessors defined in hw/core all >> declare the variable >> >>> - StrOrNull **ptr = object_field_prop_ptr(obj, prop); >>> + StrOrNull **ptr = object_field_prop_ptr(obj, opaque); >>> StrOrNull *str_or_null = *ptr; >>> >>> - if (!str_or_null) { >>> - str_or_null = g_new0(StrOrNull, 1); >>> - str_or_null->type = QTYPE_QSTRING; >>> - str_or_null->u.s = g_strdup(""); >> >> The memory allocated here is never freed. Harmless, because the code is >> unreachable. >> >>> - } else { >>> - /* the setter doesn't allow QNULL */ >>> - assert(str_or_null->type != QTYPE_QNULL); >>> - } >>> + /* >>> + * The property should never be NULL because it's part of >>> + * s->parameters and a default value is always set. It should also >>> + * never be QNULL as the setter doesn't allow it. >>> + */ >>> + assert(str_or_null && str_or_null->type != QTYPE_QNULL); >> >> Actually, @str_or_null cannot be null, because @obj isn't null, and >> object_field_prop_ptr(obj, prop) returns a pointer into @obj. >> > > And that pointer must point to zeroes at some time. It cannot be that it > comes pre-set with the property value. I'm describing that it won't > point to zeroes anymore because the setter called from > .set_default_value will have already set that memory to some meaningful > value. The comment's "should never be NULL" part does not make sense to me. Can we phrase it more clearly? >>> visit_type_str(v, name, &str_or_null->u.s, errp); >>> } >>> >>> static void set_StrOrNull(Object *obj, Visitor *v, const char *name, >>> void *opaque, Error **errp) >>> { >>> - const Property *prop = opaque; >>> - StrOrNull **ptr = object_field_prop_ptr(obj, prop); >>> - StrOrNull *str_or_null = g_new0(StrOrNull, 1); >>> + StrOrNull **ptr = object_field_prop_ptr(obj, opaque); >>> + StrOrNull *str_or_null; >>> + char *str; >>> + >>> + if (!visit_type_str(v, name, &str, errp)) { >>> + return; >>> + } >>> >>> /* >>> * Only str to keep compatibility, QNULL was never used via >>> * command line. >>> */ >> >> This comment is from Fabiano's recent commit be346eb6673 (migration: Add >> a qdev property for StrOrNull). Fabiano, did you mean to write "Only >> StrOrNull to keep compatibility"? >> > > No, it's "only str" indeed. The point is that -global tls-creds NULL was > never supported, so now that we have a property, this setter will never > create a QNULL to avoid ever passing a QNULL to code that used to > consume tls-creds and doesn't expect a QNULL value (the "compatibility" > part). The comment confuses me. I interpreted its first part as "This is only str to keep compatibility" and went "wait, it's StrOrNull only for compatibility!" Can we phrase this more clearly? >>> + str_or_null = g_new0(StrOrNull, 1); >>> str_or_null->type = QTYPE_QSTRING; >>> - if (!visit_type_str(v, name, &str_or_null->u.s, errp)) { >> >> We leak @str_or_null here. You plug the leak by delaying the allocation >> until after visit_type_str(). Good. >> >>> - return; >>> - } >>> + str_or_null->u.s = str; >>> >>> qapi_free_StrOrNull(*ptr); >>> *ptr = str_or_null; >> >> The function fails only when visit_type_str() fails, and >> visit_type_str() fails only when v->type_str() fails. >> >> Why are you certain it won't? > > By inspection, I only see the failure points at qobject_input_type_str: > > QObject *qobj = qobject_input_get_object(qiv, name, true, errp); > ... > if (!qobj) { > return false; > } > > qstr = qobject_to(QString, qobj); > if (!qstr) { > error_setg(errp, "Invalid parameter type for '%s', expected: string", > full_name(qiv, name)); > return false; > } > > I'm relying on qdev's boilerplate not allowing incorrect invocations > from the user. If code has been written that allows the .set function to > be reached with a wrong type or a incorrect member name inside of a > struct, for instance, then I'm calling it a programming error. Alright, you're constructing a non-local argument to show the memory leak is actually unreachable. Please work this more verbose version of the argument into the commit message. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-02-17 13:48 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-01-27 15:09 [PATCH v2] migration/options: Fix leaks in StrOrNull qdev accessors Fabiano Rosas 2026-01-27 15:26 ` Peter Xu 2026-02-13 9:09 ` Markus Armbruster 2026-02-13 12:39 ` Fabiano Rosas 2026-02-17 13:47 ` Markus Armbruster
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.