Skip to content

Commit b214e2b

Browse files
committed
implode: Better invalid input validation and handling
Error on non-number and nan codepoint, would asserd before Replace negative codepoint and surrogate range with unicode replacement character, would assert before Fixes #1160
1 parent cf3c11b commit b214e2b

File tree

5 files changed

+25
-2
lines changed

5 files changed

+25
-2
lines changed

src/builtin.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,9 +1201,20 @@ static jv f_string_indexes(jq_state *jq, jv a, jv b) {
12011201
}
12021202

12031203
static jv f_string_implode(jq_state *jq, jv a) {
1204+
int i;
1205+
int len;
12041206
if (jv_get_kind(a) != JV_KIND_ARRAY) {
12051207
return ret_error(a, jv_string("implode input must be an array"));
12061208
}
1209+
len = jv_array_length(jv_copy(a));
1210+
for (i = 0; i < len; i++) {
1211+
jv n = jv_array_get(jv_copy(a), i);
1212+
if (jv_get_kind(n) != JV_KIND_NUMBER || jvp_number_is_nan(n)) {
1213+
jv_free(a);
1214+
return type_error(n, "codepoint must be a number");
1215+
}
1216+
}
1217+
12071218
return jv_string_implode(a);
12081219
}
12091220

src/jv.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1362,7 +1362,8 @@ jv jv_string_implode(jv j) {
13621362
assert(JVP_HAS_KIND(n, JV_KIND_NUMBER));
13631363
int nv = jv_number_value(n);
13641364
jv_free(n);
1365-
if (nv > 0x10FFFF)
1365+
// outside codepoint range or in utf16 surrogate pair range
1366+
if (nv < 0 || nv > 0x10FFFF || (nv >= 0xD800 && nv <= 0xDFFF))
13661367
nv = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER
13671368
s = jv_string_append_codepoint(s, nv);
13681369
}

src/jv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ jv jv_number(double);
6363
jv jv_number_with_literal(const char*);
6464
double jv_number_value(jv);
6565
int jv_is_integer(jv);
66+
int jvp_number_is_nan(jv);
6667

6768
int jv_number_has_literal(jv n);
6869
const char* jv_number_get_literal(jv);

src/jv_type_private.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
#define JV_TYPE_PRIVATE
33

44
int jvp_number_cmp(jv, jv);
5-
int jvp_number_is_nan(jv);
65

76
#endif //JV_TYPE_PRIVATE

tests/jq.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,3 +1897,14 @@ any(keys[]|tostring?;true)
18971897
{"a":"1","b":"2","c":"3"}
18981898
true
18991899

1900+
1901+
# explode/implode
1902+
# test replacement character (65533) for outside codepoint range and 0xd800 (55296) - 0xdfff (57343) utf16 surrogate pair range
1903+
# 1.1 and 1.9 to test round down of non-ints
1904+
implode|explode
1905+
[-1,0,1,2,3,1114111,1114112,55295,55296,57343,57344,1.1,1.9]
1906+
[65533,0,1,2,3,1114111,65533,55295,65533,65533,57344,1,1]
1907+
1908+
map(try implode catch .)
1909+
[123,["a"],[nan]]
1910+
["implode input must be an array","string (\"a\") codepoint must be a number","number (null) codepoint must be a number"]

0 commit comments

Comments
 (0)