mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-10-04 15:10:20 +00:00
spa: json: fix string function usage in spa_json_parse_float/int
spa_json_parse_float/int receive non nul-terminated string, so calling string functions assuming nul-termination is invalid. Fix by copying data to a buffer before doing parsing.
This commit is contained in:
parent
0a70395502
commit
41d7762f8b
|
@ -219,11 +219,25 @@ static inline bool spa_json_is_null(const char *val, int len)
|
|||
/* float */
|
||||
static inline int spa_json_parse_float(const char *val, int len, float *result)
|
||||
{
|
||||
char buf[96];
|
||||
char *end;
|
||||
if (strspn(val, "+-0123456789.Ee") < (size_t)len)
|
||||
int pos;
|
||||
|
||||
if (len >= (int)sizeof(buf))
|
||||
return 0;
|
||||
*result = spa_strtof(val, &end);
|
||||
return len > 0 && end == val + len;
|
||||
|
||||
for (pos = 0; pos < len; ++pos) {
|
||||
switch (val[pos]) {
|
||||
case '+': case '-': case '0' ... '9': case '.': case 'e': case 'E': break;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(buf, val, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
*result = spa_strtof(buf, &end);
|
||||
return len > 0 && end == buf + len;
|
||||
}
|
||||
|
||||
static inline bool spa_json_is_float(const char *val, int len)
|
||||
|
@ -256,9 +270,17 @@ static inline char *spa_json_format_float(char *str, int size, float val)
|
|||
/* int */
|
||||
static inline int spa_json_parse_int(const char *val, int len, int *result)
|
||||
{
|
||||
char buf[64];
|
||||
char *end;
|
||||
*result = strtol(val, &end, 0);
|
||||
return len > 0 && end == val + len;
|
||||
|
||||
if (len >= (int)sizeof(buf))
|
||||
return 0;
|
||||
|
||||
memcpy(buf, val, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
*result = strtol(buf, &end, 0);
|
||||
return len > 0 && end == buf + len;
|
||||
}
|
||||
static inline bool spa_json_is_int(const char *val, int len)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ PWTEST(json_abi)
|
|||
#define TYPE_TRUE 5
|
||||
#define TYPE_FALSE 6
|
||||
#define TYPE_FLOAT 7
|
||||
#define TYPE_INT 8
|
||||
|
||||
static void check_type(int type, const char *value, int len)
|
||||
{
|
||||
|
@ -38,9 +39,25 @@ static void check_type(int type, const char *value, int len)
|
|||
pwtest_bool_eq(spa_json_is_bool(value, len),
|
||||
(type == TYPE_BOOL || type == TYPE_TRUE || type == TYPE_FALSE));
|
||||
pwtest_bool_eq(spa_json_is_null(value, len), (type == TYPE_NULL));
|
||||
pwtest_bool_eq(spa_json_is_true(value, len), (type == TYPE_TRUE || type == TYPE_BOOL));
|
||||
pwtest_bool_eq(spa_json_is_false(value, len), (type == TYPE_FALSE || type == TYPE_BOOL));
|
||||
pwtest_bool_eq(spa_json_is_float(value, len), (type == TYPE_FLOAT));
|
||||
if (type == TYPE_BOOL) {
|
||||
pwtest_bool_true(spa_json_is_true(value, len) || spa_json_is_false(value, len));
|
||||
} else {
|
||||
pwtest_bool_eq(spa_json_is_true(value, len), type == TYPE_TRUE);
|
||||
pwtest_bool_eq(spa_json_is_false(value, len), type == TYPE_FALSE);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TYPE_FLOAT:
|
||||
pwtest_bool_true(spa_json_is_float(value, len));
|
||||
break;
|
||||
case TYPE_INT:
|
||||
pwtest_bool_true(spa_json_is_int(value, len));
|
||||
break;
|
||||
default:
|
||||
pwtest_bool_false(spa_json_is_float(value, len));
|
||||
pwtest_bool_false(spa_json_is_int(value, len));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void expect_type(struct spa_json *it, int type)
|
||||
|
@ -51,6 +68,29 @@ static void expect_type(struct spa_json *it, int type)
|
|||
check_type(type, value, len);
|
||||
}
|
||||
|
||||
static void expect_end(struct spa_json *it)
|
||||
{
|
||||
const char *value;
|
||||
struct spa_json it2;
|
||||
|
||||
pwtest_int_eq(spa_json_next(it, &value), 0);
|
||||
|
||||
/* end is idempotent */
|
||||
memcpy(&it2, it, sizeof(*it));
|
||||
pwtest_int_eq(spa_json_next(it, &value), 0);
|
||||
pwtest_int_eq(memcmp(&it2, it, sizeof(*it)), 0);
|
||||
}
|
||||
|
||||
static void expect_array(struct spa_json *it, struct spa_json *sub)
|
||||
{
|
||||
pwtest_int_eq(spa_json_enter_array(it, sub), 1);
|
||||
}
|
||||
|
||||
static void expect_object(struct spa_json *it, struct spa_json *sub)
|
||||
{
|
||||
pwtest_int_eq(spa_json_enter_object(it, sub), 1);
|
||||
}
|
||||
|
||||
static void expect_string(struct spa_json *it, const char *str)
|
||||
{
|
||||
const char *value;
|
||||
|
@ -62,6 +102,18 @@ static void expect_string(struct spa_json *it, const char *str)
|
|||
spa_json_parse_stringn(value, len, s, len+1);
|
||||
pwtest_str_eq(s, str);
|
||||
}
|
||||
|
||||
static void expect_string_or_bare(struct spa_json *it, const char *str)
|
||||
{
|
||||
const char *value;
|
||||
int len;
|
||||
char *s;
|
||||
pwtest_int_gt((len = spa_json_next(it, &value)), 0);
|
||||
s = alloca(len+1);
|
||||
pwtest_int_eq(spa_json_parse_stringn(value, len, s, len+1), 1);
|
||||
pwtest_str_eq(s, str);
|
||||
}
|
||||
|
||||
static void expect_float(struct spa_json *it, float val)
|
||||
{
|
||||
const char *value;
|
||||
|
@ -73,6 +125,37 @@ static void expect_float(struct spa_json *it, float val)
|
|||
pwtest_double_eq(f, val);
|
||||
}
|
||||
|
||||
static void expect_int(struct spa_json *it, int val)
|
||||
{
|
||||
const char *value;
|
||||
int len;
|
||||
int f = 0;
|
||||
pwtest_int_gt((len = spa_json_next(it, &value)), 0);
|
||||
check_type(TYPE_INT, value, len);
|
||||
pwtest_int_gt(spa_json_parse_int(value, len, &f), 0);
|
||||
pwtest_int_eq(f, val);
|
||||
}
|
||||
|
||||
static void expect_bool(struct spa_json *it, bool val)
|
||||
{
|
||||
const char *value;
|
||||
int len;
|
||||
bool f = false;
|
||||
pwtest_int_gt((len = spa_json_next(it, &value)), 0);
|
||||
check_type(TYPE_BOOL, value, len);
|
||||
check_type(val ? TYPE_TRUE : TYPE_FALSE, value, len);
|
||||
pwtest_int_gt(spa_json_parse_bool(value, len, &f), 0);
|
||||
pwtest_int_eq(f, val);
|
||||
}
|
||||
|
||||
static void expect_null(struct spa_json *it)
|
||||
{
|
||||
const char *value;
|
||||
int len;
|
||||
pwtest_int_gt((len = spa_json_next(it, &value)), 0);
|
||||
check_type(TYPE_NULL, value, len);
|
||||
}
|
||||
|
||||
PWTEST(json_parse)
|
||||
{
|
||||
struct spa_json it[5];
|
||||
|
@ -135,6 +218,52 @@ PWTEST(json_parse)
|
|||
expect_string(&it[3], "1.9");
|
||||
expect_float(&it[3], 1.9f);
|
||||
|
||||
/* non-null terminated strings OK */
|
||||
json = "1.234";
|
||||
spa_json_init(&it[0], json, 4);
|
||||
expect_float(&it[0], 1.23);
|
||||
expect_end(&it[0]);
|
||||
|
||||
json = "1234";
|
||||
spa_json_init(&it[0], json, 3);
|
||||
expect_int(&it[0], 123);
|
||||
expect_end(&it[0]);
|
||||
|
||||
json = "truey";
|
||||
spa_json_init(&it[0], json, 4);
|
||||
expect_bool(&it[0], true);
|
||||
expect_end(&it[0]);
|
||||
|
||||
json = "falsey";
|
||||
spa_json_init(&it[0], json, 5);
|
||||
expect_bool(&it[0], false);
|
||||
expect_end(&it[0]);
|
||||
|
||||
json = "nully";
|
||||
spa_json_init(&it[0], json, 4);
|
||||
expect_null(&it[0]);
|
||||
expect_end(&it[0]);
|
||||
|
||||
json = "{}y{]";
|
||||
spa_json_init(&it[0], json, 2);
|
||||
expect_object(&it[0], &it[1]);
|
||||
expect_end(&it[0]);
|
||||
|
||||
json = "[]y{]";
|
||||
spa_json_init(&it[0], json, 2);
|
||||
expect_array(&it[0], &it[1]);
|
||||
expect_end(&it[0]);
|
||||
|
||||
json = "helloy";
|
||||
spa_json_init(&it[0], json, 5);
|
||||
expect_string_or_bare(&it[0], "hello");
|
||||
expect_end(&it[0]);
|
||||
|
||||
json = "\"hello\"y";
|
||||
spa_json_init(&it[0], json, 7);
|
||||
expect_string(&it[0], "hello");
|
||||
expect_end(&it[0]);
|
||||
|
||||
return PWTEST_PASS;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue