[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 07/12] json-parser: always set an error if retur
From: |
Marc-André Lureau |
Subject: |
Re: [Qemu-devel] [PATCH 07/12] json-parser: always set an error if return NULL |
Date: |
Thu, 19 Jul 2018 18:59:41 +0200 |
Hi
On Tue, Jul 17, 2018 at 9:06 AM, Markus Armbruster <address@hidden> wrote:
> Marc-André Lureau <address@hidden> writes:
>
>> Let's make json_parser_parse_err() suck less, and simplify caller
>> error handling.
>
> Missing:
>
> * monitor.c handle_qmp_command(): drop workaround
>
>> * qga/main.c process_event() doesn't need further changes after
>> previous cleanup.
>
> "Doesn't need further changes" yes, but I think it could use one.
> Consider:
>
> obj = json_parser_parse_err(tokens, NULL, &err);
> if (err) {
> goto err;
> }
> qdict = qobject_to(QDict, obj);
> if (!qdict) {
> error_setg(&err, QERR_JSON_PARSING);
> goto err;
> }
>
> Before this patch, we get to the error_setg() when
> json_parser_parse_err() fails without setting an error, and when it
> succeeds but returns anything but a dictionary. QERR_JSON_PARSING is
> appropriate for the first case, but not the second.
>
> This patch removes the first case. Please improve the error message.
>
ok, replaced with
error_setg(&err, "Input must be a JSON object");
>> * qobject/json-parser.c json_parser_parse()
>> Ignores the error.
>
> Stupid wrapper that's used exactly once, in libqtest.c. Let's use
> json_parser_parse_err() there, and drop the wrapper. Let's rename
> json_parser_parse_err() to json_parser_parse() then.
>
>> * qobject/qjson.c qobject_from_jsonv() via parse_json()
>> - qobject_from_json()
>> ~ block.c parse_json_filename() - removed workaround
>> ~ block/rbd.c - abort (generated json - should never fail)
>> ~ qapi/qobject-input-visitor.c - removed workaround
>> ~ tests/check-qjson.c - abort, ok
>
> To be precise, we pass &error_abort and either assert or crash when it
> returns null. Okay. Same for other instances of "abort, ok" below.
>
> There are a few instances that don't abort. First one when !utf8_out:
>
> obj = qobject_from_json(json_in, utf8_out ? &error_abort : NULL);
> if (utf8_out) {
> str = qobject_to(QString, obj);
> g_assert(str);
> g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
> } else {
> g_assert(!obj);
> }
> qobject_unref(obj);
>
> It ignores the error. Okay.
>
> Next one:
>
> static void unterminated_string(void)
> {
> Error *err = NULL;
> QObject *obj = qobject_from_json("\"abc", &err);
> g_assert(!err); /* BUG */
> g_assert(obj == NULL);
> }
>
> This patch should fix the BUG. We'll see at [*] below why it doens't.
>
>> ~ tests/test-visitor-serialization.c - abort, ok
>>
>> - qobject_from_jsonf()
>
> This is called qobject_from_jsonf_nofail() since commit f3e9cc9f7a1, and
> became the obvious wrapper around qobject_from_vjsonf_nofail() in commit
> 74670550ee0. Please mention both new names.
Hmm this is not upstream yet :)
> I guess the commit message needs more updates for these recent changes
> below, but I'm glossing over that now, along with much of the patch,
> because I think I've found something more serious, explained at the end
> of the patch.
>
>> Now dies in error_handle_fatal() instead of the assertion.
>
> Which assertion? Ah, the one in qobject_from_vjsonf_nofail().
>
> The assertion is now dead, isn't it?
not upstream at least
>
>> Only used in tests, ok.
>>
>> - tests/test-qobject-input-visitor.c
>> - tests/libqtest.c qmp_fd_sendv()
>> Passes &error_abort, does nothing when qobject_from_jsonv() returns
>> null. The fix makes this catch invalid JSON instead of silently
>> ignoring it.
>>
>> Signed-off-by: Marc-André Lureau <address@hidden>
>> ---
>> block.c | 5 -----
>> monitor.c | 4 ----
>> qapi/qobject-input-visitor.c | 5 -----
>> qobject/json-parser.c | 8 +++++++-
>> 4 files changed, 7 insertions(+), 15 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index ac8b3a3511..9046d66465 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -1478,11 +1478,6 @@ static QDict *parse_json_filename(const char
>> *filename, Error **errp)
>>
>> options_obj = qobject_from_json(filename, errp);
>> if (!options_obj) {
>> - /* Work around qobject_from_json() lossage TODO fix that */
>> - if (errp && !*errp) {
>> - error_setg(errp, "Could not parse the JSON options");
>> - return NULL;
>> - }
>> error_prepend(errp, "Could not parse the JSON options: ");
>> return NULL;
>> }
>> diff --git a/monitor.c b/monitor.c
>> index ec40a80d81..a3efe96d1d 100644
>> --- a/monitor.c
>> +++ b/monitor.c
>> @@ -4112,10 +4112,6 @@ static void handle_qmp_command(JSONMessageParser
>> *parser, GQueue *tokens)
>> QMPRequest *req_obj;
>>
>> req = json_parser_parse_err(tokens, NULL, &err);
>> - if (!req && !err) {
>> - /* json_parser_parse_err() sucks: can fail without setting @err */
>> - error_setg(&err, QERR_JSON_PARSING);
>> - }
>>
>> qdict = qobject_to(QDict, req);
>> if (qdict) {
>> diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
>> index da57f4cc24..3e88b27f9e 100644
>> --- a/qapi/qobject-input-visitor.c
>> +++ b/qapi/qobject-input-visitor.c
>> @@ -725,11 +725,6 @@ Visitor *qobject_input_visitor_new_str(const char *str,
>> if (is_json) {
>> obj = qobject_from_json(str, errp);
>> if (!obj) {
>> - /* Work around qobject_from_json() lossage TODO fix that */
>> - if (errp && !*errp) {
>> - error_setg(errp, "JSON parse error");
>> - return NULL;
>> - }
>> return NULL;
>> }
>> args = qobject_to(QDict, obj);
>> diff --git a/qobject/json-parser.c b/qobject/json-parser.c
>> index a5aa790d62..82c3167629 100644
>> --- a/qobject/json-parser.c
>> +++ b/qobject/json-parser.c
>> @@ -24,6 +24,7 @@
>> #include "qapi/qmp/json-parser.h"
>> #include "qapi/qmp/json-lexer.h"
>> #include "qapi/qmp/json-streamer.h"
>> +#include "qapi/qmp/qerror.h"
>>
>> typedef struct JSONParserContext
>> {
>> @@ -591,7 +592,12 @@ QObject *json_parser_parse_err(GQueue *tokens, va_list
>> *ap, Error **errp)
> QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp)
> {
> JSONParserContext *ctxt = parser_context_new(tokens);
> QObject *result;
>
> if (!ctxt) {
> return NULL;
>
> [*] Still returns null without setting an error. Two cases lumped into
> one: "no tokens due to empty input (not an error)", and "no tokens due
> to lexical error". This is not the spot to distinguish the two, it
> needs to be done in its callers. I figure the sane contract for
I tried to tackle that in the next iteration, but it's harder than it
looks like somehow ;)
> json_parser_parse_err() would be
>
> * If @tokens is null, return null.
> * Else if @tokens parse okay, return the parse tree.
> * Else set an error and return null.
>
> But then "always set an error if return NULL" is not possible. Ideas?
That's okay, I'll document the function that way
>
> }
>>
>> result = parse_value(ctxt, ap);
>>
>> - error_propagate(errp, ctxt->err);
>> + if (!result && !ctxt->err) {
>> + /* TODO: improve error reporting */
>> + error_setg(errp, QERR_JSON_PARSING);
>> + } else {
>> + error_propagate(errp, ctxt->err);
>> + }
>>
>> parser_context_free(ctxt);
>
--
Marc-André Lureau
[Qemu-devel] [PATCH 05/12] monitor: no need to save need_resume, Marc-André Lureau, 2018/07/06
[Qemu-devel] [PATCH 06/12] qga: process_event() simplification and leak fix, Marc-André Lureau, 2018/07/06