Marc-André Lureau <marcandre.lur...@redhat.com> writes: > Switch to use QNum/uint where appropriate to remove i64 limitation. > > The input visitor will cast i64 input to u64 for compatibility > reasons (existing json QMP client already use negative i64 for large > u64, and expect an implicit cast in qemu). > > Note: before the patch, uint64_t values above INT64_MAX are sent over > json QMP as negative values, e.g. UINT64_MAX is sent as -1. After the > patch, they are sent unmodified. Clearly a bug fix, but we have to > consider compatibility issues anyway. libvirt should cope fine, > because its parsing of unsigned integers accepts negative values > modulo 2^64. There's hope that other clients will, too. > > Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com> > Reviewed-by: Markus Armbruster <arm...@redhat.com> > --- > hw/i386/acpi-build.c | 2 +- > qapi/qobject-input-visitor.c | 21 ++++++++++++++++----- > qapi/qobject-output-visitor.c | 3 +-- > tests/test-qobject-input-visitor.c | 7 ++----- > tests/test-qobject-output-visitor.c | 20 ++++++++++++++++---- > 5 files changed, 36 insertions(+), 17 deletions(-) > > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > index d7d2b65fe4..3eb43677f0 100644 > --- a/hw/i386/acpi-build.c > +++ b/hw/i386/acpi-build.c > @@ -2614,7 +2614,7 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) > if (!o) { > return false; > } > - mcfg->mcfg_base = qnum_get_int(qobject_to_qnum(o)); > + mcfg->mcfg_base = qnum_get_uint(qobject_to_qnum(o)); > qobject_decref(o); > > o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL); > diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c > index 539b3b825d..35aff78f2b 100644 > --- a/qapi/qobject-input-visitor.c > +++ b/qapi/qobject-input-visitor.c > @@ -417,7 +417,6 @@ static void qobject_input_type_int64_keyval(Visitor *v, > const char *name, > static void qobject_input_type_uint64(Visitor *v, const char *name, > uint64_t *obj, Error **errp) > { > - /* FIXME: qobject_to_qnum mishandles values over INT64_MAX */ > QObjectInputVisitor *qiv = to_qiv(v); > QObject *qobj = qobject_input_get_object(qiv, name, true, errp); > QNum *qnum; > @@ -427,11 +426,23 @@ static void qobject_input_type_uint64(Visitor *v, const > char *name, > return; > } > qnum = qobject_to_qnum(qobj); > - if (!qnum || !qnum_get_try_int(qnum, &val)) { > - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, > - full_name(qiv, name), "integer"); > + if (!qnum) { > + goto err; > + } > + > + if (qnum_get_try_uint(qnum, obj)) { > + return; > } > - *obj = val; > + > + /* Need to accept negative values for backward compatibility */ > + if (qnum_get_try_int(qnum, &val)) { > + *obj = val; > + return; > + } > + > +err: > + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, > + full_name(qiv, name), "uint64"); > } > > static void qobject_input_type_uint64_keyval(Visitor *v, const char *name, > diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c > index 2ca5093b22..70be84ccb5 100644 > --- a/qapi/qobject-output-visitor.c > +++ b/qapi/qobject-output-visitor.c > @@ -150,9 +150,8 @@ static void qobject_output_type_int64(Visitor *v, const > char *name, > static void qobject_output_type_uint64(Visitor *v, const char *name, > uint64_t *obj, Error **errp) > { > - /* FIXME values larger than INT64_MAX become negative */ > QObjectOutputVisitor *qov = to_qov(v); > - qobject_output_add(qov, name, qnum_from_int(*obj)); > + qobject_output_add(qov, name, qnum_from_uint(*obj)); > } > > static void qobject_output_type_bool(Visitor *v, const char *name, bool *obj, > diff --git a/tests/test-qobject-input-visitor.c > b/tests/test-qobject-input-visitor.c > index 40a135db89..3bcdb9a045 100644 > --- a/tests/test-qobject-input-visitor.c > +++ b/tests/test-qobject-input-visitor.c > @@ -123,7 +123,6 @@ static void test_visitor_in_int(TestInputVisitorData > *data, > static void test_visitor_in_uint(TestInputVisitorData *data, > const void *unused) > { > - Error *err = NULL; > uint64_t res = 0; > int64_t i64; > double dbl; > @@ -147,12 +146,10 @@ static void test_visitor_in_uint(TestInputVisitorData > *data, > visit_type_uint64(v, NULL, &res, &error_abort); > g_assert_cmpuint(res, ==, (uint64_t)-value); > > - /* BUG: value between INT64_MAX+1 and UINT64_MAX rejected */ > - > v = visitor_input_test_init(data, "18446744073709551574"); > > - visit_type_uint64(v, NULL, &res, &err); > - error_free_or_abort(&err); > + visit_type_uint64(v, NULL, &res, &error_abort); > + g_assert_cmpuint(res, ==, 18446744073709551574U); > > visit_type_number(v, NULL, &dbl, &error_abort); > } > diff --git a/tests/test-qobject-output-visitor.c > b/tests/test-qobject-output-visitor.c > index a16c8f663f..d23c8eb352 100644 > --- a/tests/test-qobject-output-visitor.c > +++ b/tests/test-qobject-output-visitor.c > @@ -602,14 +602,26 @@ static void check_native_list(QObject *qobj, > qlist = qlist_copy(qobject_to_qlist(qdict_get(qdict, "data"))); > > switch (kind) { > - case USER_DEF_NATIVE_LIST_UNION_KIND_S8: > - case USER_DEF_NATIVE_LIST_UNION_KIND_S16: > - case USER_DEF_NATIVE_LIST_UNION_KIND_S32: > - case USER_DEF_NATIVE_LIST_UNION_KIND_S64: > case USER_DEF_NATIVE_LIST_UNION_KIND_U8: > case USER_DEF_NATIVE_LIST_UNION_KIND_U16: > case USER_DEF_NATIVE_LIST_UNION_KIND_U32: > case USER_DEF_NATIVE_LIST_UNION_KIND_U64: > + for (i = 0; i < 32; i++) { > + QObject *tmp; > + QNum *qvalue; > + > + tmp = qlist_peek(qlist); > + g_assert(tmp); > + qvalue = qobject_to_qnum(tmp); > + g_assert_cmpuint(qnum_get_uint(qvalue), ==, i);
You use qnum_get_uint() here, but... > + qobject_decref(qlist_pop(qlist)); > + } > + break; > + > + case USER_DEF_NATIVE_LIST_UNION_KIND_S8: > + case USER_DEF_NATIVE_LIST_UNION_KIND_S16: > + case USER_DEF_NATIVE_LIST_UNION_KIND_S32: > + case USER_DEF_NATIVE_LIST_UNION_KIND_S64: > /* > * All integer elements in JSON arrays get stored into QNums > * when we convert to QObjects, so we can check them all in * the same fashion, so simply fall through here. */ case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: for (i = 0; i < 32; i++) { QObject *tmp; QNum *qvalue; int64_t val; tmp = qlist_peek(qlist); g_assert(tmp); qvalue = qobject_to_qnum(tmp); g_assert(qnum_get_try_int(qvalue, &val)); qnum_get_try_int() here. Either is fine with me, but let's to it the same way. You seem to prefer qnum_get_try_int() elsewhere in tests, probably because it fails more nicely, at the cost of one extra line. I don't mind. g_assert_cmpint(val, ==, i); qobject_decref(qlist_pop(qlist)); } break; With that tidied up, my R-by stands.