[Qemu-devel] [PATCH v2] qapi: Fix error handling code on alternate conflict

Eduardo Habkost posted 1 patch 6 years, 8 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20170717180926.14924-1-ehabkost@redhat.com
Test FreeBSD passed
Test checkpatch passed
Test docker passed
Test s390x passed
scripts/qapi.py                                       | 8 ++++----
tests/Makefile.include                                | 2 ++
tests/qapi-schema/alternate-conflict-bool-string.err  | 1 +
tests/qapi-schema/alternate-conflict-bool-string.exit | 1 +
tests/qapi-schema/alternate-conflict-bool-string.json | 4 ++++
tests/qapi-schema/alternate-conflict-bool-string.out  | 0
tests/qapi-schema/alternate-conflict-num-string.err   | 1 +
tests/qapi-schema/alternate-conflict-num-string.exit  | 1 +
tests/qapi-schema/alternate-conflict-num-string.json  | 4 ++++
tests/qapi-schema/alternate-conflict-num-string.out   | 0
tests/qapi-schema/alternate-multi-conflict.json       | 0
11 files changed, 18 insertions(+), 4 deletions(-)
create mode 100644 tests/qapi-schema/alternate-conflict-bool-string.err
create mode 100644 tests/qapi-schema/alternate-conflict-bool-string.exit
create mode 100644 tests/qapi-schema/alternate-conflict-bool-string.json
create mode 100644 tests/qapi-schema/alternate-conflict-bool-string.out
create mode 100644 tests/qapi-schema/alternate-conflict-num-string.err
create mode 100644 tests/qapi-schema/alternate-conflict-num-string.exit
create mode 100644 tests/qapi-schema/alternate-conflict-num-string.json
create mode 100644 tests/qapi-schema/alternate-conflict-num-string.out
create mode 100644 tests/qapi-schema/alternate-multi-conflict.json
[Qemu-devel] [PATCH v2] qapi: Fix error handling code on alternate conflict
Posted by Eduardo Habkost 6 years, 8 months ago
The conflict check added by commit c0644771 ("qapi: Reject
alternates that can't work with keyval_parse()") doesn't work
with the following declaration:

  { 'alternate': 'Alt',
    'data': { 'one': 'bool',
              'two': 'str' } }

It crashes with:

  Traceback (most recent call last):
    File "./scripts/qapi-types.py", line 295, in <module>
      schema = QAPISchema(input_file)
    File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 1468, in __init__
      self.exprs = check_exprs(parser.exprs)
    File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 958, in check_exprs
      check_alternate(expr, info)
    File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 830, in check_alternate
      % (name, key, types_seen[qtype]))
  KeyError: 'QTYPE_QSTRING'

This happens because the previously-seen conflicting member
('one') can't be found at types_seen[qtype], but at
types_seen['QTYPE_BOOL'].

Fix the bug by moving the error check to the same loop that adds
new items to types_seen, raising an exception if types_seen[qt]
is already set.

Add two additional test cases that can detect the bug.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
Changes v1 -> v2:
* Fix mistake on *.err files (wrong line number on error message)
---
 scripts/qapi.py                                       | 8 ++++----
 tests/Makefile.include                                | 2 ++
 tests/qapi-schema/alternate-conflict-bool-string.err  | 1 +
 tests/qapi-schema/alternate-conflict-bool-string.exit | 1 +
 tests/qapi-schema/alternate-conflict-bool-string.json | 4 ++++
 tests/qapi-schema/alternate-conflict-bool-string.out  | 0
 tests/qapi-schema/alternate-conflict-num-string.err   | 1 +
 tests/qapi-schema/alternate-conflict-num-string.exit  | 1 +
 tests/qapi-schema/alternate-conflict-num-string.json  | 4 ++++
 tests/qapi-schema/alternate-conflict-num-string.out   | 0
 tests/qapi-schema/alternate-multi-conflict.json       | 0
 11 files changed, 18 insertions(+), 4 deletions(-)
 create mode 100644 tests/qapi-schema/alternate-conflict-bool-string.err
 create mode 100644 tests/qapi-schema/alternate-conflict-bool-string.exit
 create mode 100644 tests/qapi-schema/alternate-conflict-bool-string.json
 create mode 100644 tests/qapi-schema/alternate-conflict-bool-string.out
 create mode 100644 tests/qapi-schema/alternate-conflict-num-string.err
 create mode 100644 tests/qapi-schema/alternate-conflict-num-string.exit
 create mode 100644 tests/qapi-schema/alternate-conflict-num-string.json
 create mode 100644 tests/qapi-schema/alternate-conflict-num-string.out
 create mode 100644 tests/qapi-schema/alternate-multi-conflict.json

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 84e2eb4..a9c12e5 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -824,11 +824,11 @@ def check_alternate(expr, info):
             else:
                 conflicting.add('QTYPE_QNUM')
                 conflicting.add('QTYPE_QBOOL')
-        if conflicting & set(types_seen):
-            raise QAPISemError(info, "Alternate '%s' member '%s' can't "
-                               "be distinguished from member '%s'"
-                               % (name, key, types_seen[qtype]))
         for qt in conflicting:
+            if qt in types_seen:
+                raise QAPISemError(info, "Alternate '%s' member '%s' can't "
+                                   "be distinguished from member '%s'"
+                                   % (name, key, types_seen[qt]))
             types_seen[qt] = key
 
 
diff --git a/tests/Makefile.include b/tests/Makefile.include
index cfbb689..16d7a3a 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -346,6 +346,8 @@ qapi-schema += alternate-conflict-dict.json
 qapi-schema += alternate-conflict-enum-bool.json
 qapi-schema += alternate-conflict-enum-int.json
 qapi-schema += alternate-conflict-string.json
+qapi-schema += alternate-conflict-bool-string.json
+qapi-schema += alternate-conflict-num-string.json
 qapi-schema += alternate-empty.json
 qapi-schema += alternate-nested.json
 qapi-schema += alternate-unknown.json
diff --git a/tests/qapi-schema/alternate-conflict-bool-string.err b/tests/qapi-schema/alternate-conflict-bool-string.err
new file mode 100644
index 0000000..e52fee7
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-bool-string.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-conflict-bool-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/tests/qapi-schema/alternate-conflict-bool-string.exit b/tests/qapi-schema/alternate-conflict-bool-string.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-bool-string.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/alternate-conflict-bool-string.json b/tests/qapi-schema/alternate-conflict-bool-string.json
new file mode 100644
index 0000000..0544de1
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-bool-string.json
@@ -0,0 +1,4 @@
+# alternate branches of 'str' type conflict with all scalar types
+{ 'alternate': 'Alt',
+  'data': { 'one': 'bool',
+            'two': 'str' } }
diff --git a/tests/qapi-schema/alternate-conflict-bool-string.out b/tests/qapi-schema/alternate-conflict-bool-string.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/alternate-conflict-num-string.err b/tests/qapi-schema/alternate-conflict-num-string.err
new file mode 100644
index 0000000..5ba3827
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-num-string.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-conflict-num-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/tests/qapi-schema/alternate-conflict-num-string.exit b/tests/qapi-schema/alternate-conflict-num-string.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-num-string.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/alternate-conflict-num-string.json b/tests/qapi-schema/alternate-conflict-num-string.json
new file mode 100644
index 0000000..ae90144
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-num-string.json
@@ -0,0 +1,4 @@
+# alternate branches of 'str' type conflict with all scalar types
+{ 'alternate': 'Alt',
+  'data': { 'one': 'number',
+            'two': 'str' } }
diff --git a/tests/qapi-schema/alternate-conflict-num-string.out b/tests/qapi-schema/alternate-conflict-num-string.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/alternate-multi-conflict.json b/tests/qapi-schema/alternate-multi-conflict.json
new file mode 100644
index 0000000..e69de29
-- 
2.9.4


Re: [Qemu-devel] [PATCH v2] qapi: Fix error handling code on alternate conflict
Posted by Eric Blake 6 years, 8 months ago
On 07/17/2017 01:09 PM, Eduardo Habkost wrote:
> The conflict check added by commit c0644771 ("qapi: Reject
> alternates that can't work with keyval_parse()") doesn't work
> with the following declaration:
> 
>   { 'alternate': 'Alt',
>     'data': { 'one': 'bool',
>               'two': 'str' } }
> 
> It crashes with:
> 
>   Traceback (most recent call last):
>     File "./scripts/qapi-types.py", line 295, in <module>
>       schema = QAPISchema(input_file)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 1468, in __init__
>       self.exprs = check_exprs(parser.exprs)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 958, in check_exprs
>       check_alternate(expr, info)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 830, in check_alternate
>       % (name, key, types_seen[qtype]))
>   KeyError: 'QTYPE_QSTRING'
> 
> This happens because the previously-seen conflicting member
> ('one') can't be found at types_seen[qtype], but at
> types_seen['QTYPE_BOOL'].
> 
> Fix the bug by moving the error check to the same loop that adds
> new items to types_seen, raising an exception if types_seen[qt]
> is already set.
> 
> Add two additional test cases that can detect the bug.
> 
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> ---

If this misses tomorrow's freeze deadline, it's borderline for inclusion
in 2.10 (it does not change the qemu binary proper, but rather fixes a
build tool crash, where the crash is only provoked by bad input and we
won't have any bad input at the time of the freeze) - I'll leave it up
to Markus on whether to take now or defer to 2.11.  But either way:

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

Re: [Qemu-devel] [PATCH v2] qapi: Fix error handling code on alternate conflict
Posted by Markus Armbruster 6 years, 8 months ago
Eduardo Habkost <ehabkost@redhat.com> writes:

> The conflict check added by commit c0644771 ("qapi: Reject
> alternates that can't work with keyval_parse()") doesn't work
> with the following declaration:
>
>   { 'alternate': 'Alt',
>     'data': { 'one': 'bool',
>               'two': 'str' } }
>
> It crashes with:
>
>   Traceback (most recent call last):
>     File "./scripts/qapi-types.py", line 295, in <module>
>       schema = QAPISchema(input_file)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 1468, in __init__
>       self.exprs = check_exprs(parser.exprs)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 958, in check_exprs
>       check_alternate(expr, info)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 830, in check_alternate
>       % (name, key, types_seen[qtype]))
>   KeyError: 'QTYPE_QSTRING'
>
> This happens because the previously-seen conflicting member
> ('one') can't be found at types_seen[qtype], but at
> types_seen['QTYPE_BOOL'].

Good catch.

> Fix the bug by moving the error check to the same loop that adds
> new items to types_seen, raising an exception if types_seen[qt]
> is already set.
>
> Add two additional test cases that can detect the bug.
>
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>

Re: [Qemu-devel] [PATCH v2] qapi: Fix error handling code on alternate conflict
Posted by Markus Armbruster 6 years, 8 months ago
Eduardo Habkost <ehabkost@redhat.com> writes:

> The conflict check added by commit c0644771 ("qapi: Reject
> alternates that can't work with keyval_parse()") doesn't work
> with the following declaration:
>
>   { 'alternate': 'Alt',
>     'data': { 'one': 'bool',
>               'two': 'str' } }
>
> It crashes with:
>
>   Traceback (most recent call last):
>     File "./scripts/qapi-types.py", line 295, in <module>
>       schema = QAPISchema(input_file)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 1468, in __init__
>       self.exprs = check_exprs(parser.exprs)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 958, in check_exprs
>       check_alternate(expr, info)
>     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 830, in check_alternate
>       % (name, key, types_seen[qtype]))
>   KeyError: 'QTYPE_QSTRING'
>
> This happens because the previously-seen conflicting member
> ('one') can't be found at types_seen[qtype], but at
> types_seen['QTYPE_BOOL'].
>
> Fix the bug by moving the error check to the same loop that adds
> new items to types_seen, raising an exception if types_seen[qt]
> is already set.
>
> Add two additional test cases that can detect the bug.
>
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
[...]
> diff --git a/tests/qapi-schema/alternate-conflict-num-string.out b/tests/qapi-schema/alternate-conflict-num-string.out
> new file mode 100644
> index 0000000..e69de29
> diff --git a/tests/qapi-schema/alternate-multi-conflict.json b/tests/qapi-schema/alternate-multi-conflict.json
> new file mode 100644
> index 0000000..e69de29

Accident?  Can drop on commit.

Re: [Qemu-devel] [PATCH v2] qapi: Fix error handling code on alternate conflict
Posted by Eduardo Habkost 6 years, 8 months ago
On Thu, Jul 20, 2017 at 06:14:44PM +0200, Markus Armbruster wrote:
> Eduardo Habkost <ehabkost@redhat.com> writes:
> 
> > The conflict check added by commit c0644771 ("qapi: Reject
> > alternates that can't work with keyval_parse()") doesn't work
> > with the following declaration:
> >
> >   { 'alternate': 'Alt',
> >     'data': { 'one': 'bool',
> >               'two': 'str' } }
> >
> > It crashes with:
> >
> >   Traceback (most recent call last):
> >     File "./scripts/qapi-types.py", line 295, in <module>
> >       schema = QAPISchema(input_file)
> >     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 1468, in __init__
> >       self.exprs = check_exprs(parser.exprs)
> >     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 958, in check_exprs
> >       check_alternate(expr, info)
> >     File "/home/ehabkost/rh/proj/virt/qemu/scripts/qapi.py", line 830, in check_alternate
> >       % (name, key, types_seen[qtype]))
> >   KeyError: 'QTYPE_QSTRING'
> >
> > This happens because the previously-seen conflicting member
> > ('one') can't be found at types_seen[qtype], but at
> > types_seen['QTYPE_BOOL'].
> >
> > Fix the bug by moving the error check to the same loop that adds
> > new items to types_seen, raising an exception if types_seen[qt]
> > is already set.
> >
> > Add two additional test cases that can detect the bug.
> >
> > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> [...]
> > diff --git a/tests/qapi-schema/alternate-conflict-num-string.out b/tests/qapi-schema/alternate-conflict-num-string.out
> > new file mode 100644
> > index 0000000..e69de29
> > diff --git a/tests/qapi-schema/alternate-multi-conflict.json b/tests/qapi-schema/alternate-multi-conflict.json
> > new file mode 100644
> > index 0000000..e69de29
> 
> Accident?  Can drop on commit.

Yes, sorry.  Thanks for spotting it.

-- 
Eduardo