All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Eric Blake <eblake@redhat.com>
Cc: qemu-devel@nongnu.org, Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCH v6 01/23] qapi: Make all visitors supply int64/uint64 callbacks
Date: Fri, 27 Nov 2015 12:17:47 +0100	[thread overview]
Message-ID: <8737vr6690.fsf@blackfin.pond.sub.org> (raw)
In-Reply-To: <1448497401-27784-2-git-send-email-eblake@redhat.com> (Eric Blake's message of "Wed, 25 Nov 2015 17:22:58 -0700")

Eric Blake <eblake@redhat.com> writes:

> Our qapi visitor contract supports multiple integer visitors:
> type_int (64-bit signed; mandatory), type_int64 (64-bit signed,
> optional), type_uint64 (64-bit unsigned, optional), and
> type_size (64-bit unsigned, optional, with the possibility of
> parsing differently than type_uint64 for the case of suffixed
> sizes).  But the default code treats any implementation without
> type_uint64 as just falling back on type_int, which can cause
> confusing results for values larger than LLONG_MAX (such as
> having to pass in a negative 2s complement value on input,
> and getting a negative result on output).

The visit_type_FOO() functions use their first argument's methods to do
their job.  For the integer visits, this involves picking the most
appropriate method from a set of candidates.  The set varies, because
some methods are optional.

Let me quickly review the state of things before this patch:

* visit_type_int() visits an int64_t and simply calls mandatory method
  type_int().

* The visit_type_intN() visit an intN_t.  They call optional method
  type_intN if it's there, else they use type_int() and check the result
  is in the type's range.

  Why optional type_int64() would ever differ from mandatory type_int()
  is anybody's guess.

* The visit_type_uintN() visit an uintN_t.  They call optional method
  type_uintN if it's there, else they use type_int() and check the
  result is in the type's range.  Except for type_uint64(), which simply
  converts the visited uint64_t to and from int64_t.  That's the issue
  you mentioned above.

* visit_type_size() visits an uint64_t.  It calls optional method
  type_size() if it's there, else optional type_uint64(), else
  type_int().  The latter again converts the visited uint64_t to and
  from int64_t.

Any change around here is prone to affect the weird cases, which always
confuse me, and that's why I'm going to read the patch very slowly.

> This patch does not fully address the disparity in parsing,
> but does move towards a cleaner situation where EVERY visitor
> provides both signed and unsigned variants as entry points;

Namely both type_int64() and type_uint64().

> then each client can either implement sane differences between
> the two, or document in place with a FIXME that there is
> munging going on for large values.  The next patch will then
> clean up the code to no longer allow conditional type_uint64.

I hope it also ditches type_int() as superfluous.

> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v6: new patch, but stems from v5 23/46
> ---
>  qapi/opts-visitor.c          |  5 +++--
>  qapi/qapi-dealloc-visitor.c  | 19 ++++++++++---------
>  qapi/qmp-input-visitor.c     | 23 ++++++++++++++++++++---
>  qapi/qmp-output-visitor.c    | 15 ++++++++++++---
>  qapi/string-input-visitor.c  | 22 +++++++++++++++++++---
>  qapi/string-output-visitor.c | 16 +++++++++++++---
>  6 files changed, 77 insertions(+), 23 deletions(-)
>
> diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
> index ef5fb8b..bc2b976 100644
> --- a/qapi/opts-visitor.c
> +++ b/qapi/opts-visitor.c
> @@ -354,7 +354,7 @@ opts_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
>
>
>  static void
> -opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
> +opts_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp)
>  {
>      OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);
>      const QemuOpt *opt;
> @@ -522,7 +522,8 @@ opts_visitor_new(const QemuOpts *opts)
>       */
>      ov->visitor.type_enum = &input_type_enum;
>
> -    ov->visitor.type_int    = &opts_type_int;
> +    ov->visitor.type_int    = &opts_type_int64;
> +    ov->visitor.type_int64  = &opts_type_int64;
>      ov->visitor.type_uint64 = &opts_type_uint64;
>      ov->visitor.type_size   = &opts_type_size;
>      ov->visitor.type_bool   = &opts_type_bool;

Straightforward.  Note that type_int == type_int64 now.  Same for the
other visitors, actually.

> diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
> index 737deab..5d1b2e6 100644
> --- a/qapi/qapi-dealloc-visitor.c
> +++ b/qapi/qapi-dealloc-visitor.c
> @@ -136,8 +136,13 @@ static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name,
>      }
>  }
>
> -static void qapi_dealloc_type_int(Visitor *v, int64_t *obj, const char *name,
> -                                  Error **errp)
> +static void qapi_dealloc_type_int64(Visitor *v, int64_t *obj,
> +                                    const char *name, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_uint64(Visitor *v, uint64_t *obj,
> +                                     const char *name, Error **errp)
>  {
>  }
>
> @@ -159,11 +164,6 @@ static void qapi_dealloc_type_anything(Visitor *v, QObject **obj,
>      }
>  }
>
> -static void qapi_dealloc_type_size(Visitor *v, uint64_t *obj, const char *name,
> -                                   Error **errp)
> -{
> -}
> -
>  static void qapi_dealloc_type_enum(Visitor *v, int *obj,
>                                     const char * const strings[],
>                                     const char *kind, const char *name,
> @@ -220,12 +220,13 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
>      v->visitor.next_list = qapi_dealloc_next_list;
>      v->visitor.end_list = qapi_dealloc_end_list;
>      v->visitor.type_enum = qapi_dealloc_type_enum;
> -    v->visitor.type_int = qapi_dealloc_type_int;
> +    v->visitor.type_int = qapi_dealloc_type_int64;
> +    v->visitor.type_int64 = qapi_dealloc_type_int64;
> +    v->visitor.type_uint64 = qapi_dealloc_type_uint64;
>      v->visitor.type_bool = qapi_dealloc_type_bool;
>      v->visitor.type_str = qapi_dealloc_type_str;
>      v->visitor.type_number = qapi_dealloc_type_number;
>      v->visitor.type_any = qapi_dealloc_type_anything;
> -    v->visitor.type_size = qapi_dealloc_type_size;
>      v->visitor.start_union = qapi_dealloc_start_union;
>
>      QTAILQ_INIT(&v->stack);

Same straightforward change to make type_int == type_int64.

Additionally, define type_uint64() instead of type_size().  No change
for visit_type_size().  visit_type_uint64() will now call type_uint64()
to do nothing instead of type_int().  Good.

> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
> index 932b5f3..96dafcb 100644
> --- a/qapi/qmp-input-visitor.c
> +++ b/qapi/qmp-input-visitor.c
> @@ -224,8 +224,23 @@ static void qmp_input_get_next_type(Visitor *v, QType *type, bool promote_int,
>      }
>  }
>
> -static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
> -                               Error **errp)
> +static void qmp_input_type_int64(Visitor *v, int64_t *obj, const char *name,
> +                                 Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
> +
> +    if (!qint) {
> +        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
> +                   "integer");
> +        return;
> +    }
> +
> +    *obj = qint_get_int(qint);
> +}
> +
> +static void qmp_input_type_uint64(Visitor *v, uint64_t *obj, const char *name,
> +                                  Error **errp)
>  {
>      QmpInputVisitor *qiv = to_qiv(v);
>      QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));

Diff obscures what actually happens here, namely:

* Rename qmp_input_type_int() to qmp_input_type_int64().

* New qmp_input_type_uint64(), only difference to qmp_input_type_int64()
  is uint64_t instead of int64_t.  Note that QInt can only hold int64_t,
  so this still converts from int64_t to uint64_t, except it now does it
  in qmp_input_type_uint64() instead of visit_type_uint64().  Worth a
  FIXME?

> @@ -341,7 +356,9 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
>      v->visitor.next_list = qmp_input_next_list;
>      v->visitor.end_list = qmp_input_end_list;
>      v->visitor.type_enum = input_type_enum;
> -    v->visitor.type_int = qmp_input_type_int;
> +    v->visitor.type_int = qmp_input_type_int64;
> +    v->visitor.type_int64 = qmp_input_type_int64;
> +    v->visitor.type_uint64 = qmp_input_type_uint64;
>      v->visitor.type_bool = qmp_input_type_bool;
>      v->visitor.type_str = qmp_input_type_str;
>      v->visitor.type_number = qmp_input_type_number;
> diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
> index 29899ac..a52f26f 100644
> --- a/qapi/qmp-output-visitor.c
> +++ b/qapi/qmp-output-visitor.c
> @@ -158,8 +158,15 @@ static void qmp_output_end_list(Visitor *v, Error **errp)
>      qmp_output_pop(qov);
>  }
>
> -static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name,
> -                                Error **errp)
> +static void qmp_output_type_int64(Visitor *v, int64_t *obj, const char *name,
> +                                  Error **errp)
> +{
> +    QmpOutputVisitor *qov = to_qov(v);
> +    qmp_output_add(qov, name, qint_from_int(*obj));
> +}
> +
> +static void qmp_output_type_uint64(Visitor *v, uint64_t *obj, const char *name,
> +                                   Error **errp)
>  {
>      QmpOutputVisitor *qov = to_qov(v);
>      qmp_output_add(qov, name, qint_from_int(*obj));

Again, diff obscures the actual change:

* Rename qmp_output_type_int() to qmp_output_type_int64().

* New qmp_output_type_uint64(), like qmp_output_type_int64(), but with
  uint64_t instead of int64_t.  As above, this still converts from
  uint64_t to int64_t, except it now does it in qmp_output_type_int64()
  instead of visit_type_uint64().  Worth a FIXME?

> @@ -241,7 +248,9 @@ QmpOutputVisitor *qmp_output_visitor_new(void)
>      v->visitor.next_list = qmp_output_next_list;
>      v->visitor.end_list = qmp_output_end_list;
>      v->visitor.type_enum = output_type_enum;
> -    v->visitor.type_int = qmp_output_type_int;
> +    v->visitor.type_int = qmp_output_type_int64;
> +    v->visitor.type_int64 = qmp_output_type_int64;
> +    v->visitor.type_uint64 = qmp_output_type_uint64;
>      v->visitor.type_bool = qmp_output_type_bool;
>      v->visitor.type_str = qmp_output_type_str;
>      v->visitor.type_number = qmp_output_type_number;
> diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
> index dee780a..0931321 100644
> --- a/qapi/string-input-visitor.c
> +++ b/qapi/string-input-visitor.c
> @@ -179,8 +179,8 @@ end_list(Visitor *v, Error **errp)
>      siv->head = true;
>  }
>
> -static void parse_type_int(Visitor *v, int64_t *obj, const char *name,
> -                           Error **errp)
> +static void parse_type_int64(Visitor *v, int64_t *obj, const char *name,
> +                             Error **errp)
>  {
>      StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
>
> @@ -221,6 +221,20 @@ error:
>                 "an int64 value or range");
>  }
>
> +static void parse_type_uint64(Visitor *v, uint64_t *obj, const char *name,
> +                              Error **errp)
> +{
> +    /* FIXME - don't handle numbers > INT64_MAX as negative */
> +    int64_t i;
> +    Error *err = NULL;

Blank line here, please.

> +    parse_type_int64(v, &i, name, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +    } else {
> +        *obj = i;
> +    }
> +}
> +
>  static void parse_type_size(Visitor *v, uint64_t *obj, const char *name,
>                              Error **errp)
>  {
> @@ -330,7 +344,9 @@ StringInputVisitor *string_input_visitor_new(const char *str)
>      v = g_malloc0(sizeof(*v));
>
>      v->visitor.type_enum = input_type_enum;
> -    v->visitor.type_int = parse_type_int;
> +    v->visitor.type_int = parse_type_int64;
> +    v->visitor.type_int64 = parse_type_int64;
> +    v->visitor.type_uint64 = parse_type_uint64;
>      v->visitor.type_size = parse_type_size;
>      v->visitor.type_bool = parse_type_bool;
>      v->visitor.type_str = parse_type_str;
> diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c
> index b86ce2c..83ca6cc 100644
> --- a/qapi/string-output-visitor.c
> +++ b/qapi/string-output-visitor.c
> @@ -116,8 +116,8 @@ static void format_string(StringOutputVisitor *sov, Range *r, bool next,
>      }
>  }
>
> -static void print_type_int(Visitor *v, int64_t *obj, const char *name,
> -                           Error **errp)
> +static void print_type_int64(Visitor *v, int64_t *obj, const char *name,
> +                             Error **errp)
>  {
>      StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
>      GList *l;
> @@ -192,6 +192,14 @@ static void print_type_int(Visitor *v, int64_t *obj, const char *name,
>      }
>  }
>
> +static void print_type_uint64(Visitor *v, uint64_t *obj, const char *name,
> +                             Error **errp)
> +{
> +    /* FIXME - don't handle numbers > INT64_MAX as negative */
> +    int64_t i = *obj;
> +    print_type_int64(v, &i, name, errp);
> +}
> +
>  static void print_type_size(Visitor *v, uint64_t *obj, const char *name,
>                             Error **errp)
>  {
> @@ -340,7 +348,9 @@ StringOutputVisitor *string_output_visitor_new(bool human)
>      v->string = g_string_new(NULL);
>      v->human = human;
>      v->visitor.type_enum = output_type_enum;
> -    v->visitor.type_int = print_type_int;
> +    v->visitor.type_int = print_type_int64;
> +    v->visitor.type_int64 = print_type_int64;
> +    v->visitor.type_uint64 = print_type_uint64;
>      v->visitor.type_size = print_type_size;
>      v->visitor.type_bool = print_type_bool;
>      v->visitor.type_str = print_type_str;

  reply	other threads:[~2015-11-27 11:18 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-26  0:22 [Qemu-devel] [PATCH v6 00/23] qapi visitor cleanups (post-introspection cleanups subset E) Eric Blake
2015-11-26  0:22 ` [Qemu-devel] [PATCH v6 01/23] qapi: Make all visitors supply int64/uint64 callbacks Eric Blake
2015-11-27 11:17   ` Markus Armbruster [this message]
2015-11-26  0:22 ` [Qemu-devel] [PATCH v6 02/23] qapi: Require int64/uint64 implementation Eric Blake
2015-11-27 12:05   ` Markus Armbruster
2015-12-02 21:25     ` Eric Blake
2015-12-03  8:30       ` Markus Armbruster
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 03/23] qapi: Consolidate visitor integer callbacks Eric Blake
2015-11-27 12:11   ` Markus Armbruster
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 04/23] qapi: Don't cast Enum* to int* Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 05/23] qmp: Fix reference-counting of qnull on empty output visit Eric Blake
2015-11-27 13:06   ` Markus Armbruster
2015-12-02 23:10     ` Eric Blake
2015-12-03 17:50       ` Markus Armbruster
2015-12-04  3:01         ` Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 06/23] qapi: Don't abuse stack to track qmp-output root Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 07/23] qapi: Document visitor interfaces Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 08/23] qapi: Drop unused error argument for list and implicit struct Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 09/23] hmp: Improve use of qapi visitor Eric Blake
2015-12-04 21:18   ` Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 10/23] vl: " Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 11/23] ppc: Improve use of qapi visitors Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 12/23] balloon: Improve use of qapi visitor Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 13/23] qapi: Add type.is_empty() helper Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 14/23] qapi: Fix command with named empty argument type Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 15/23] qapi: Improve generated event use of qapi visitor Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 16/23] qapi: Track all failures between visit_start/stop Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 17/23] qapi: Eliminate empty visit_type_FOO_fields Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 18/23] qapi: Canonicalize missing object to :empty Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 19/23] qapi-visit: Unify struct and union visit Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 20/23] qapi: Rework deallocation of partial struct Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 21/23] qapi: Simplify extra member error reporting in input visitors Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 22/23] qapi: Split visit_end_struct() into pieces Eric Blake
2015-11-26  0:23 ` [Qemu-devel] [PATCH v6 23/23] qapi: Change visit_type_FOO() to no longer return partial objects Eric Blake

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=8737vr6690.fsf@blackfin.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=eblake@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.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.