qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

json: learn to parse uint64 numbers

Switch strtoll() usage to qemu_strtoi64() helper while at it.

Add a few tests for large numbers.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20170607163635.17635-11-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>

authored by

Marc-André Lureau and committed by
Markus Armbruster
2bc7cfea 61a8f418

+76 -8
+4
qobject/json-lexer.c
··· 227 227 /* escape */ 228 228 [IN_ESCAPE_LL] = { 229 229 ['d'] = JSON_ESCAPE, 230 + ['u'] = JSON_ESCAPE, 230 231 }, 231 232 232 233 [IN_ESCAPE_L] = { 233 234 ['d'] = JSON_ESCAPE, 234 235 ['l'] = IN_ESCAPE_LL, 236 + ['u'] = JSON_ESCAPE, 235 237 }, 236 238 237 239 [IN_ESCAPE_I64] = { 238 240 ['d'] = JSON_ESCAPE, 241 + ['u'] = JSON_ESCAPE, 239 242 }, 240 243 241 244 [IN_ESCAPE_I6] = { ··· 251 254 ['i'] = JSON_ESCAPE, 252 255 ['p'] = JSON_ESCAPE, 253 256 ['s'] = JSON_ESCAPE, 257 + ['u'] = JSON_ESCAPE, 254 258 ['f'] = JSON_ESCAPE, 255 259 ['l'] = IN_ESCAPE_L, 256 260 ['I'] = IN_ESCAPE_I,
+28 -8
qobject/json-parser.c
··· 12 12 */ 13 13 14 14 #include "qemu/osdep.h" 15 + #include "qemu/cutils.h" 15 16 #include "qapi/error.h" 16 17 #include "qemu-common.h" 17 18 #include "qapi/qmp/types.h" ··· 472 473 } else if (!strcmp(token->str, "%lld") || 473 474 !strcmp(token->str, "%I64d")) { 474 475 return QOBJECT(qnum_from_int(va_arg(*ap, long long))); 476 + } else if (!strcmp(token->str, "%u")) { 477 + return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned int))); 478 + } else if (!strcmp(token->str, "%lu")) { 479 + return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned long))); 480 + } else if (!strcmp(token->str, "%llu") || 481 + !strcmp(token->str, "%I64u")) { 482 + return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned long long))); 475 483 } else if (!strcmp(token->str, "%s")) { 476 484 return QOBJECT(qstring_from_str(va_arg(*ap, const char *))); 477 485 } else if (!strcmp(token->str, "%f")) { ··· 493 501 case JSON_INTEGER: { 494 502 /* 495 503 * Represent JSON_INTEGER as QNUM_I64 if possible, else as 496 - * QNUM_DOUBLE. Note that strtoll() fails with ERANGE when 497 - * it's not possible. 504 + * QNUM_U64, else as QNUM_DOUBLE. Note that qemu_strtoi64() 505 + * and qemu_strtou64() fail with ERANGE when it's not 506 + * possible. 498 507 * 499 508 * qnum_get_int() will then work for any signed 64-bit 500 - * JSON_INTEGER, and qnum_get_double() both for any 501 - * JSON_INTEGER and any JSON_FLOAT (with precision loss for 502 - * integers beyond 53 bits) 509 + * JSON_INTEGER, qnum_get_uint() for any unsigned 64-bit 510 + * integer, and qnum_get_double() both for any JSON_INTEGER 511 + * and any JSON_FLOAT (with precision loss for integers beyond 512 + * 53 bits) 503 513 */ 514 + int ret; 504 515 int64_t value; 516 + uint64_t uvalue; 505 517 506 - errno = 0; /* strtoll doesn't set errno on success */ 507 - value = strtoll(token->str, NULL, 10); 508 - if (errno != ERANGE) { 518 + ret = qemu_strtoi64(token->str, NULL, 10, &value); 519 + if (!ret) { 509 520 return QOBJECT(qnum_from_int(value)); 521 + } 522 + assert(ret == -ERANGE); 523 + 524 + if (token->str[0] != '-') { 525 + ret = qemu_strtou64(token->str, NULL, 10, &uvalue); 526 + if (!ret) { 527 + return QOBJECT(qnum_from_uint(uvalue)); 528 + } 529 + assert(ret == -ERANGE); 510 530 } 511 531 /* fall through to JSON_FLOAT */ 512 532 }
+44
tests/check-qjson.c
··· 906 906 } 907 907 } 908 908 909 + static void large_number(void) 910 + { 911 + const char *maxu64 = "18446744073709551615"; /* 2^64-1 */ 912 + const char *gtu64 = "18446744073709551616"; /* 2^64 */ 913 + const char *lti64 = "-9223372036854775809"; /* -2^63 - 1 */ 914 + QNum *qnum; 915 + QString *str; 916 + uint64_t val; 917 + int64_t ival; 918 + 919 + qnum = qobject_to_qnum(qobject_from_json(maxu64, &error_abort)); 920 + g_assert(qnum); 921 + g_assert_cmpuint(qnum_get_uint(qnum), ==, 18446744073709551615U); 922 + g_assert(!qnum_get_try_int(qnum, &ival)); 923 + 924 + str = qobject_to_json(QOBJECT(qnum)); 925 + g_assert_cmpstr(qstring_get_str(str), ==, maxu64); 926 + QDECREF(str); 927 + QDECREF(qnum); 928 + 929 + qnum = qobject_to_qnum(qobject_from_json(gtu64, &error_abort)); 930 + g_assert(qnum); 931 + g_assert_cmpfloat(qnum_get_double(qnum), ==, 18446744073709552e3); 932 + g_assert(!qnum_get_try_uint(qnum, &val)); 933 + g_assert(!qnum_get_try_int(qnum, &ival)); 934 + 935 + str = qobject_to_json(QOBJECT(qnum)); 936 + g_assert_cmpstr(qstring_get_str(str), ==, gtu64); 937 + QDECREF(str); 938 + QDECREF(qnum); 939 + 940 + qnum = qobject_to_qnum(qobject_from_json(lti64, &error_abort)); 941 + g_assert(qnum); 942 + g_assert_cmpfloat(qnum_get_double(qnum), ==, -92233720368547758e2); 943 + g_assert(!qnum_get_try_uint(qnum, &val)); 944 + g_assert(!qnum_get_try_int(qnum, &ival)); 945 + 946 + str = qobject_to_json(QOBJECT(qnum)); 947 + g_assert_cmpstr(qstring_get_str(str), ==, "-9223372036854775808"); 948 + QDECREF(str); 949 + QDECREF(qnum); 950 + } 951 + 909 952 static void float_number(void) 910 953 { 911 954 int i; ··· 1475 1518 g_test_add_func("/literals/string/vararg", vararg_string); 1476 1519 1477 1520 g_test_add_func("/literals/number/simple", simple_number); 1521 + g_test_add_func("/literals/number/large", large_number); 1478 1522 g_test_add_func("/literals/number/float", float_number); 1479 1523 g_test_add_func("/literals/number/vararg", vararg_number); 1480 1524