summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias Wadman <mattias.wadman@gmail.com>2023-07-02 16:48:07 +0200
committerNico Williams <nico@cryptonector.com>2023-07-25 13:38:41 -0500
commita949745059ee61366a5d880c3b18d5d4db6524eb (patch)
tree4fb0a93cf93e99d098eae5f8eff37ef6c92b049d /src
parenta29ac81de117a6bad625bc4ff75bbb395a58f7d6 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/builtin.c23
-rw-r--r--src/jv.c3
-rw-r--r--src/jv.h1
-rw-r--r--src/jv_type_private.h1
4 files changed, 25 insertions, 3 deletions
diff --git a/src/builtin.c b/src/builtin.c
index 3e99c376..8e1de2b5 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1201,7 +1201,28 @@ static jv f_string_implode(jq_state *jq, jv a) {
if (jv_get_kind(a) != JV_KIND_ARRAY) {
return ret_error(a, jv_string("implode input must be an array"));
}
- return jv_string_implode(a);
+
+ int len = jv_array_length(jv_copy(a));
+ jv s = jv_string_empty(len);
+
+ for (int i = 0; i < len; i++) {
+ jv n = jv_array_get(jv_copy(a), i);
+ if (jv_get_kind(n) != JV_KIND_NUMBER || jvp_number_is_nan(n)) {
+ jv_free(a);
+ jv_free(s);
+ return type_error(n, "can't be imploded, unicode codepoint needs to be numeric");
+ }
+
+ int nv = jv_number_value(n);
+ jv_free(n);
+ // outside codepoint range or in utf16 surrogate pair range
+ if (nv < 0 || nv > 0x10FFFF || (nv >= 0xD800 && nv <= 0xDFFF))
+ nv = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER
+ s = jv_string_append_codepoint(s, nv);
+ }
+
+ jv_free(a);
+ return s;
}
static jv f_setpath(jq_state *jq, jv a, jv b, jv c) { return jv_setpath(a, b, c); }
diff --git a/src/jv.c b/src/jv.c
index 159b3f27..b4ee8a2e 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -1368,7 +1368,8 @@ jv jv_string_implode(jv j) {
assert(JVP_HAS_KIND(n, JV_KIND_NUMBER));
int nv = jv_number_value(n);
jv_free(n);
- if (nv > 0x10FFFF)
+ // outside codepoint range or in utf16 surrogate pair range
+ if (nv < 0 || nv > 0x10FFFF || (nv >= 0xD800 && nv <= 0xDFFF))
nv = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER
s = jv_string_append_codepoint(s, nv);
}
diff --git a/src/jv.h b/src/jv.h
index 8c96f822..446ffb06 100644
--- a/src/jv.h
+++ b/src/jv.h
@@ -63,6 +63,7 @@ jv jv_number(double);
jv jv_number_with_literal(const char*);
double jv_number_value(jv);
int jv_is_integer(jv);
+int jvp_number_is_nan(jv);
int jv_number_has_literal(jv n);
const char* jv_number_get_literal(jv);
diff --git a/src/jv_type_private.h b/src/jv_type_private.h
index 5996282b..a25254dc 100644
--- a/src/jv_type_private.h
+++ b/src/jv_type_private.h
@@ -2,6 +2,5 @@
#define JV_TYPE_PRIVATE
int jvp_number_cmp(jv, jv);
-int jvp_number_is_nan(jv);
#endif //JV_TYPE_PRIVATE