From: "Alex Bennée" <alex.bennee@linaro.org>
To: "Philippe Mathieu-Daudé" <philmd@redhat.com>
Cc: qemu-devel@nongnu.org, "Paolo Bonzini" <pbonzini@redhat.com>,
"Richard Henderson" <richard.henderson@linaro.org>,
"Daniel P. Berrangé" <berrange@redhat.com>,
"Eduardo Habkost" <ehabkost@redhat.com>
Subject: Re: [PATCH v3] hw/core/qdev-properties-system: Rewrite set_pci_host_devaddr using GLib
Date: Mon, 18 Jan 2021 14:16:40 +0000 [thread overview]
Message-ID: <87v9buuwys.fsf@linaro.org> (raw)
In-Reply-To: <20201125083300.861206-1-philmd@redhat.com>
Philippe Mathieu-Daudé <philmd@redhat.com> writes:
> set_pci_host_devaddr() is hard to follow, thus bug-prone.
>
> For example, a bug was introduced in commit bccb20c49df, as
> the same line might be used to parse a bus (up to 0xff) or
> a slot (up to 0x1f).
>
> Instead of making things worst, rewrite using g_strsplit().
This no longer applies to my tip of tree but in general I'm a fan. Do we
have any unit tests for the qdev parsing? I couldn't see any but I'm not
sure if the generic QOM tests would exercise this code.
Generally when re-writing a parser it's nice to have a unit test just so
you can check you've covered all the corner cases (witness the number of
iterations the dfilter logic took to get right :-/).
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
> v3: Rebased
> v2: Free g_strsplit() with g_auto(GStrv) (Daniel)
> ---
> hw/core/qdev-properties-system.c | 62 ++++++++++++++------------------
> 1 file changed, 27 insertions(+), 35 deletions(-)
>
> diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
> index 9d80a07d26f..79408e32289 100644
> --- a/hw/core/qdev-properties-system.c
> +++ b/hw/core/qdev-properties-system.c
> @@ -857,11 +857,11 @@ static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
> DeviceState *dev = DEVICE(obj);
> Property *prop = opaque;
> PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
> - char *str, *p;
> - char *e;
> + g_autofree char *str = NULL;
> + g_auto(GStrv) col_s0 = NULL;
> + g_auto(GStrv) dot_s = NULL;
> + char **col_s;
> unsigned long val;
> - unsigned long dom = 0, bus = 0;
> - unsigned int slot = 0, func = 0;
>
> if (dev->realized) {
> qdev_prop_set_after_realize(dev, name, errp);
> @@ -872,58 +872,50 @@ static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
> return;
> }
>
> - p = str;
> - val = strtoul(p, &e, 16);
> - if (e == p || *e != ':') {
> + col_s = col_s0 = g_strsplit(str, ":", 3);
> + if (!col_s || !col_s[0] || !col_s[1]) {
I'm not sure you want max_tokens 3 because 1:2:3:4 would end up with the
malformed ["1", "2", "3:4"]. You could just make your test:
cols_s = g_strsplit(str, ":", -1);
if (!cols_s || g_strv_length(cols_s) != 3) {
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
return;
}
> goto inval;
> }
> - bus = val;
>
> - p = e + 1;
> - val = strtoul(p, &e, 16);
> - if (e == p) {
> - goto inval;
> - }
> - if (*e == ':') {
> - dom = bus;
> - bus = val;
> - p = e + 1;
> - val = strtoul(p, &e, 16);
> - if (e == p) {
> + /* domain */
> + if (col_s[2]) {
> + if (qemu_strtoul(col_s[0], NULL, 16, &val) < 0 || val > 0xffff) {
> goto inval;
> }
> + addr->domain = val;
> + col_s++;
> + } else {
> + addr->domain = 0;
> }
> - slot = val;
Hmm ok PCI ids are more complex than I knew. Maybe the test above needs
to be:
cols_s = g_strsplit(str, ":", -1);
cols_l = g_strv_length(cols_s);
if (!cols_s || !(cols_l == 2 || cols_l ==3)) {
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
return;
}
>
> - if (*e != '.') {
> + /* bus */
> + if (qemu_strtoul(col_s[0], NULL, 16, &val) < 0 || val > 0xff) {
> goto inval;
> }
> - p = e + 1;
> - val = strtoul(p, &e, 10);
> - if (e == p) {
> - goto inval;
> - }
> - func = val;
> + addr->bus = val;
>
> - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
> + /* <slot>.<func> */
> + dot_s = g_strsplit(col_s[1], ".", 2);
> + if (!dot_s || !dot_s[0] || !dot_s[1]) {
> goto inval;
> }
I think there is a similar length validation needed here.
>
> - if (*e) {
> + /* slot */
> + if (qemu_strtoul(dot_s[0], NULL, 16, &val) < 0 || val > 0x1f) {
> goto inval;
> }
> + addr->slot = val;
>
> - addr->domain = dom;
> - addr->bus = bus;
> - addr->slot = slot;
> - addr->function = func;
> + /* func */
> + if (qemu_strtoul(dot_s[1], NULL, 10, &val) < 0 || val > 7) {
> + goto inval;
> + }
> + addr->function = val;
>
> - g_free(str);
> return;
>
> inval:
> error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
> - g_free(str);
> }
>
> const PropertyInfo qdev_prop_pci_host_devaddr = {
--
Alex Bennée
prev parent reply other threads:[~2021-01-18 14:44 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-25 8:33 [PATCH v3] hw/core/qdev-properties-system: Rewrite set_pci_host_devaddr using GLib Philippe Mathieu-Daudé
2021-01-08 16:02 ` Philippe Mathieu-Daudé
2021-01-18 13:16 ` Philippe Mathieu-Daudé
2021-01-18 14:16 ` Alex Bennée [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87v9buuwys.fsf@linaro.org \
--to=alex.bennee@linaro.org \
--cc=berrange@redhat.com \
--cc=ehabkost@redhat.com \
--cc=pbonzini@redhat.com \
--cc=philmd@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.