diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-07-01 11:18:00 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-07-01 11:18:01 +0100 |
commit | 1fb4c13e4f92bda047f30177d5b8c2b4ca42e8b8 (patch) | |
tree | 1a364b8593876135e3490a850d687569b79aa772 | |
parent | ddf31aa853a32925f8141dbcb66fdc84f999ece1 (diff) | |
parent | db486cc334aafd3dbdaf107388e37fc3d6d3e171 (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.h | 91 | ||||
-rw-r--r-- | qapi/string-input-visitor.c | 17 | ||||
-rw-r--r-- | qapi/string-output-visitor.c | 4 | ||||
-rw-r--r-- | qobject/json-lexer.c | 19 | ||||
-rw-r--r-- | qobject/json-streamer.c | 6 | ||||
-rwxr-xr-x | scripts/checkpatch.pl | 2 | ||||
-rw-r--r-- | scripts/qapi-visit.py | 6 | ||||
-rw-r--r-- | tests/test-qmp-input-visitor.c | 12 | ||||
-rw-r--r-- | util/Makefile.objs | 1 | ||||
-rw-r--r-- | util/range.c | 76 |
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; +} |