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

cutils: Fix qemu_strtosz() & friends to reject non-finite sizes

qemu_strtosz() & friends reject NaNs, but happily accept infinities.
They shouldn't. Fix that.

The fix makes use of qemu_strtod_finite(). To avoid ugly casts,
change the @end parameter of qemu_strtosz() & friends from char **
to const char **.

Also, add two test cases, testing that "inf" and "NaN" are properly
rejected. While at it, also fixup the function documentation.

Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20181121164421.20780-3-david@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>

authored by

David Hildenbrand and committed by
Markus Armbruster
af02f4c5 ca28f548

+29 -21
+3 -3
include/qemu/cutils.h
··· 153 153 int base); 154 154 int parse_uint_full(const char *s, unsigned long long *value, int base); 155 155 156 - int qemu_strtosz(const char *nptr, char **end, uint64_t *result); 157 - int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result); 158 - int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result); 156 + int qemu_strtosz(const char *nptr, const char **end, uint64_t *result); 157 + int qemu_strtosz_MiB(const char *nptr, const char **end, uint64_t *result); 158 + int qemu_strtosz_metric(const char *nptr, const char **end, uint64_t *result); 159 159 160 160 /* used to print char* safely */ 161 161 #define STR_OR_NULL(str) ((str) ? (str) : "null")
+1 -1
monitor.c
··· 3232 3232 { 3233 3233 int ret; 3234 3234 uint64_t val; 3235 - char *end; 3235 + const char *end; 3236 3236 3237 3237 while (qemu_isspace(*p)) { 3238 3238 p++;
+17 -7
tests/test-cutils.c
··· 1950 1950 static void test_qemu_strtosz_simple(void) 1951 1951 { 1952 1952 const char *str; 1953 - char *endptr = NULL; 1953 + const char *endptr; 1954 1954 int err; 1955 1955 uint64_t res = 0xbaadf00d; 1956 1956 ··· 2017 2017 const char *p = "1P"; 2018 2018 const char *e = "1E"; 2019 2019 int err; 2020 - char *endptr = NULL; 2020 + const char *endptr; 2021 2021 uint64_t res = 0xbaadf00d; 2022 2022 2023 2023 /* default is M */ ··· 2066 2066 { 2067 2067 const char *str = "12.345M"; 2068 2068 int err; 2069 - char *endptr = NULL; 2069 + const char *endptr; 2070 2070 uint64_t res = 0xbaadf00d; 2071 2071 2072 2072 err = qemu_strtosz(str, &endptr, &res); ··· 2078 2078 static void test_qemu_strtosz_invalid(void) 2079 2079 { 2080 2080 const char *str; 2081 - char *endptr = NULL; 2081 + const char *endptr; 2082 2082 int err; 2083 2083 uint64_t res = 0xbaadf00d; 2084 2084 ··· 2096 2096 err = qemu_strtosz(str, &endptr, &res); 2097 2097 g_assert_cmpint(err, ==, -EINVAL); 2098 2098 g_assert(endptr == str); 2099 + 2100 + str = "inf"; 2101 + err = qemu_strtosz(str, &endptr, &res); 2102 + g_assert_cmpint(err, ==, -EINVAL); 2103 + g_assert(endptr == str); 2104 + 2105 + str = "NaN"; 2106 + err = qemu_strtosz(str, &endptr, &res); 2107 + g_assert_cmpint(err, ==, -EINVAL); 2108 + g_assert(endptr == str); 2099 2109 } 2100 2110 2101 2111 static void test_qemu_strtosz_trailing(void) 2102 2112 { 2103 2113 const char *str; 2104 - char *endptr = NULL; 2114 + const char *endptr; 2105 2115 int err; 2106 2116 uint64_t res = 0xbaadf00d; 2107 2117 ··· 2126 2136 static void test_qemu_strtosz_erange(void) 2127 2137 { 2128 2138 const char *str; 2129 - char *endptr = NULL; 2139 + const char *endptr; 2130 2140 int err; 2131 2141 uint64_t res = 0xbaadf00d; 2132 2142 ··· 2160 2170 { 2161 2171 const char *str = "12345k"; 2162 2172 int err; 2163 - char *endptr = NULL; 2173 + const char *endptr; 2164 2174 uint64_t res = 0xbaadf00d; 2165 2175 2166 2176 err = qemu_strtosz_metric(str, &endptr, &res);
+8 -10
util/cutils.c
··· 203 203 /* 204 204 * Convert string to bytes, allowing either B/b for bytes, K/k for KB, 205 205 * M/m for MB, G/g for GB or T/t for TB. End pointer will be returned 206 - * in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on 206 + * in *end, if not NULL. Return -ERANGE on overflow, and -EINVAL on 207 207 * other error. 208 208 */ 209 - static int do_strtosz(const char *nptr, char **end, 209 + static int do_strtosz(const char *nptr, const char **end, 210 210 const char default_suffix, int64_t unit, 211 211 uint64_t *result) 212 212 { 213 213 int retval; 214 - char *endptr; 214 + const char *endptr; 215 215 unsigned char c; 216 216 int mul_required = 0; 217 217 double val, mul, integral, fraction; 218 218 219 - errno = 0; 220 - val = strtod(nptr, &endptr); 221 - if (isnan(val) || endptr == nptr || errno != 0) { 222 - retval = -EINVAL; 219 + retval = qemu_strtod_finite(nptr, &endptr, &val); 220 + if (retval) { 223 221 goto out; 224 222 } 225 223 fraction = modf(val, &integral); ··· 259 257 return retval; 260 258 } 261 259 262 - int qemu_strtosz(const char *nptr, char **end, uint64_t *result) 260 + int qemu_strtosz(const char *nptr, const char **end, uint64_t *result) 263 261 { 264 262 return do_strtosz(nptr, end, 'B', 1024, result); 265 263 } 266 264 267 - int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result) 265 + int qemu_strtosz_MiB(const char *nptr, const char **end, uint64_t *result) 268 266 { 269 267 return do_strtosz(nptr, end, 'M', 1024, result); 270 268 } 271 269 272 - int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result) 270 + int qemu_strtosz_metric(const char *nptr, const char **end, uint64_t *result) 273 271 { 274 272 return do_strtosz(nptr, end, 'B', 1000, result); 275 273 }