aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-07-01 11:18:00 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-07-01 11:18:01 +0100
commit1fb4c13e4f92bda047f30177d5b8c2b4ca42e8b8 (patch)
tree1a364b8593876135e3490a850d687569b79aa772
parentddf31aa853a32925f8141dbcb66fdc84f999ece1 (diff)
parentdb486cc334aafd3dbdaf107388e37fc3d6d3e171 (diff)
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2016-06-30' into staging
QAPI patches 2016-06-30 # gpg: Signature made Thu 30 Jun 2016 14:29:43 BST # gpg: using RSA key 0x3870B400EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2016-06-30: qapi: Fix memleak in string visitors on int lists qapi: Simplify use of range.h range: Create range.c for code that should not be inline qapi: Fix crash on missing alternate member of QAPI struct checkpatch: There is no qemu_strtod() qobject: Correct JSON lexer grammar comments json-streamer: Don't leak tokens on incomplete parse Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--include/qemu/range.h91
-rw-r--r--qapi/string-input-visitor.c17
-rw-r--r--qapi/string-output-visitor.c4
-rw-r--r--qobject/json-lexer.c19
-rw-r--r--qobject/json-streamer.c6
-rwxr-xr-xscripts/checkpatch.pl2
-rw-r--r--scripts/qapi-visit.py6
-rw-r--r--tests/test-qmp-input-visitor.c12
-rw-r--r--util/Makefile.objs1
-rw-r--r--util/range.c76
10 files changed, 143 insertions, 91 deletions
diff --git a/include/qemu/range.h b/include/qemu/range.h
index c903eb574a..3970f00089 100644
--- a/include/qemu/range.h
+++ b/include/qemu/range.h
@@ -1,3 +1,23 @@
+/*
+ * QEMU 64-bit address ranges
+ *
+ * Copyright (c) 2015-2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
#ifndef QEMU_RANGE_H
#define QEMU_RANGE_H
@@ -59,75 +79,6 @@ static inline int ranges_overlap(uint64_t first1, uint64_t len1,
return !(last2 < first1 || last1 < first2);
}
-/* 0,1 can merge with 1,2 but don't overlap */
-static inline bool ranges_can_merge(Range *range1, Range *range2)
-{
- return !(range1->end < range2->begin || range2->end < range1->begin);
-}
-
-static inline int range_merge(Range *range1, Range *range2)
-{
- if (ranges_can_merge(range1, range2)) {
- if (range1->end < range2->end) {
- range1->end = range2->end;
- }
- if (range1->begin > range2->begin) {
- range1->begin = range2->begin;
- }
- return 0;
- }
-
- return -1;
-}
-
-static inline GList *g_list_insert_sorted_merged(GList *list,
- gpointer data,
- GCompareFunc func)
-{
- GList *l, *next = NULL;
- Range *r, *nextr;
-
- if (!list) {
- list = g_list_insert_sorted(list, data, func);
- return list;
- }
-
- nextr = data;
- l = list;
- while (l && l != next && nextr) {
- r = l->data;
- if (ranges_can_merge(r, nextr)) {
- range_merge(r, nextr);
- l = g_list_remove_link(l, next);
- next = g_list_next(l);
- if (next) {
- nextr = next->data;
- } else {
- nextr = NULL;
- }
- } else {
- l = g_list_next(l);
- }
- }
-
- if (!l) {
- list = g_list_insert_sorted(list, data, func);
- }
-
- return list;
-}
-
-static inline gint range_compare(gconstpointer a, gconstpointer b)
-{
- Range *ra = (Range *)a, *rb = (Range *)b;
- if (ra->begin == rb->begin && ra->end == rb->end) {
- return 0;
- } else if (range_get_last(ra->begin, ra->end) <
- range_get_last(rb->begin, rb->end)) {
- return -1;
- } else {
- return 1;
- }
-}
+GList *range_list_insert(GList *list, Range *data);
#endif
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index 30b58791c9..b546e5f76a 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -61,8 +61,7 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
cur = g_malloc0(sizeof(*cur));
cur->begin = start;
cur->end = start + 1;
- siv->ranges = g_list_insert_sorted_merged(siv->ranges, cur,
- range_compare);
+ siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
str = NULL;
} else if (*endptr == '-') {
@@ -76,10 +75,7 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
cur = g_malloc0(sizeof(*cur));
cur->begin = start;
cur->end = end + 1;
- siv->ranges =
- g_list_insert_sorted_merged(siv->ranges,
- cur,
- range_compare);
+ siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
str = NULL;
} else if (*endptr == ',') {
@@ -87,10 +83,7 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
cur = g_malloc0(sizeof(*cur));
cur->begin = start;
cur->end = end + 1;
- siv->ranges =
- g_list_insert_sorted_merged(siv->ranges,
- cur,
- range_compare);
+ siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
} else {
goto error;
@@ -103,9 +96,7 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
cur = g_malloc0(sizeof(*cur));
cur->begin = start;
cur->end = start + 1;
- siv->ranges = g_list_insert_sorted_merged(siv->ranges,
- cur,
- range_compare);
+ siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
} else {
goto error;
diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c
index d01319628b..5ea395ab98 100644
--- a/qapi/string-output-visitor.c
+++ b/qapi/string-output-visitor.c
@@ -85,7 +85,7 @@ static void string_output_append(StringOutputVisitor *sov, int64_t a)
Range *r = g_malloc0(sizeof(*r));
r->begin = a;
r->end = a + 1;
- sov->ranges = g_list_insert_sorted_merged(sov->ranges, r, range_compare);
+ sov->ranges = range_list_insert(sov->ranges, r);
}
static void string_output_append_range(StringOutputVisitor *sov,
@@ -94,7 +94,7 @@ static void string_output_append_range(StringOutputVisitor *sov,
Range *r = g_malloc0(sizeof(*r));
r->begin = s;
r->end = e + 1;
- sov->ranges = g_list_insert_sorted_merged(sov->ranges, r, range_compare);
+ sov->ranges = range_list_insert(sov->ranges, r);
}
static void format_string(StringOutputVisitor *sov, Range *r, bool next,
diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
index 496374d9ab..af4a75e05b 100644
--- a/qobject/json-lexer.c
+++ b/qobject/json-lexer.c
@@ -18,11 +18,20 @@
#define MAX_TOKEN_SIZE (64ULL << 20)
/*
- * \"([^\\\"]|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*\"
- * '([^\\']|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*'
- * 0|([1-9][0-9]*(.[0-9]+)?([eE]([-+])?[0-9]+))
+ * Required by JSON (RFC 7159):
+ *
+ * \"([^\\\"]|\\[\"'\\/bfnrt]|\\u[0-9a-fA-F]{4})*\"
+ * -?(0|[1-9][0-9]*)(.[0-9]+)?([eE][-+]?[0-9]+)?
* [{}\[\],:]
- * [a-z]+
+ * [a-z]+ # covers null, true, false
+ *
+ * Extension of '' strings:
+ *
+ * '([^\\']|\\[\"'\\/bfnrt]|\\u[0-9a-fA-F]{4})*'
+ *
+ * Extension for vararg handling in JSON construction:
+ *
+ * %((l|ll|I64)?d|[ipsf])
*
*/
@@ -213,7 +222,7 @@ static const uint8_t json_lexer[][256] = {
['\t'] = IN_WHITESPACE,
['\r'] = IN_WHITESPACE,
['\n'] = IN_WHITESPACE,
- },
+ },
/* escape */
[IN_ESCAPE_LL] = {
diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c
index 02516853a1..7164390cf5 100644
--- a/qobject/json-streamer.c
+++ b/qobject/json-streamer.c
@@ -20,9 +20,15 @@
#define MAX_TOKEN_COUNT (2ULL << 20)
#define MAX_NESTING (1ULL << 10)
+static void json_message_free_token(void *token, void *opaque)
+{
+ g_free(token);
+}
+
static void json_message_free_tokens(JSONMessageParser *parser)
{
if (parser->tokens) {
+ g_queue_foreach(parser->tokens, json_message_free_token, NULL);
g_queue_free(parser->tokens);
parser->tokens = NULL;
}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index c939a325bc..cf32c8f5fa 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2453,7 +2453,7 @@ sub process {
}
# recommend qemu_strto* over strto* for numeric conversions
- if ($line =~ /\b(strto[^k].*?)\s*\(/) {
+ if ($line =~ /\b(strto[^kd].*?)\s*\(/) {
WARN("consider using qemu_$1 in preference to $1\n" . $herecurr);
}
# check for module_init(), use category-specific init macros explicitly please
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 70ea8caef5..ffb635c508 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -172,6 +172,9 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
if (err) {
goto out;
}
+ if (!*obj) {
+ goto out_obj;
+ }
switch ((*obj)->type) {
''',
c_name=c_name(name), promote_int=promote_int)
@@ -206,10 +209,13 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
''')
ret += mcgen('''
+ case QTYPE_NONE:
+ abort();
default:
error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"%(name)s");
}
+out_obj:
visit_end_alternate(v);
if (err && visit_is_input(v)) {
qapi_free_%(c_name)s(*obj);
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index 3b6b39e297..1a4585c553 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -766,6 +766,8 @@ static void test_visitor_in_errors(TestInputVisitorData *data,
Error *err = NULL;
Visitor *v;
strList *q = NULL;
+ UserDefTwo *r = NULL;
+ WrapAlternate *s = NULL;
v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', "
"'string': -42 }");
@@ -778,6 +780,16 @@ static void test_visitor_in_errors(TestInputVisitorData *data,
visit_type_strList(v, NULL, &q, &err);
error_free_or_abort(&err);
assert(!q);
+
+ v = visitor_input_test_init(data, "{ 'str':'hi' }");
+ visit_type_UserDefTwo(v, NULL, &r, &err);
+ error_free_or_abort(&err);
+ assert(!r);
+
+ v = visitor_input_test_init(data, "{ }");
+ visit_type_WrapAlternate(v, NULL, &s, &err);
+ error_free_or_abort(&err);
+ assert(!s);
}
static void test_visitor_in_wrong_type(TestInputVisitorData *data,
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 45f8794864..96cb1e0e58 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -34,3 +34,4 @@ util-obj-y += base64.o
util-obj-y += log.o
util-obj-y += qdist.o
util-obj-y += qht.o
+util-obj-y += range.o
diff --git a/util/range.c b/util/range.c
new file mode 100644
index 0000000000..e90c988dbf
--- /dev/null
+++ b/util/range.c
@@ -0,0 +1,76 @@
+/*
+ * QEMU 64-bit address ranges
+ *
+ * Copyright (c) 2015-2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/range.h"
+
+/*
+ * Operations on 64 bit address ranges.
+ * Notes:
+ * - ranges must not wrap around 0, but can include the last byte ~0x0LL.
+ * - this can not represent a full 0 to ~0x0LL range.
+ */
+
+/* Return -1 if @a < @b, 1 if greater, and 0 if they touch or overlap. */
+static inline int range_compare(Range *a, Range *b)
+{
+ /* Zero a->end is 2**64, and therefore not less than any b->begin */
+ if (a->end && a->end < b->begin) {
+ return -1;
+ }
+ if (b->end && a->begin > b->end) {
+ return 1;
+ }
+ return 0;
+}
+
+/* Insert @data into @list of ranges; caller no longer owns @data */
+GList *range_list_insert(GList *list, Range *data)
+{
+ GList *l;
+
+ /* Range lists require no empty ranges */
+ assert(data->begin < data->end || (data->begin && !data->end));
+
+ /* Skip all list elements strictly less than data */
+ for (l = list; l && range_compare(l->data, data) < 0; l = l->next) {
+ }
+
+ if (!l || range_compare(l->data, data) > 0) {
+ /* Rest of the list (if any) is strictly greater than @data */
+ return g_list_insert_before(list, l, data);
+ }
+
+ /* Current list element overlaps @data, merge the two */
+ range_extend(l->data, data);
+ g_free(data);
+
+ /* Merge any subsequent list elements that now also overlap */
+ while (l->next && range_compare(l->data, l->next->data) == 0) {
+ GList *new_l;
+
+ range_extend(l->data, l->next->data);
+ g_free(l->next->data);
+ new_l = g_list_delete_link(list, l->next);
+ assert(new_l == list);
+ }
+
+ return list;
+}