This is an automated email from the ASF dual-hosted git repository.
vatamane pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb.git
The following commit(s) were added to refs/heads/main by this push:
new fb7d5f908 Update QuickJS
fb7d5f908 is described below
commit fb7d5f9085c3288480769f044e666c1e975d35fb
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Fri Mar 14 13:38:46 2025 -0400
Update QuickJS
Specifically, include my date parsing fix and some other updates (stack
overflow check in stringify, unicode fixes):
https://github.com/bellard/quickjs/compare/6e2e68fd0896957f92eb6c242a2e048c1ef3cae0...master
---
.../patches/01-spidermonkey-185-mode.patch | 6 +-
src/couch_quickjs/quickjs/libregexp.c | 36 +-
src/couch_quickjs/quickjs/libregexp.h | 5 +
src/couch_quickjs/quickjs/libunicode.c | 402 ++++++++++-----------
src/couch_quickjs/quickjs/quickjs-libc.c | 8 +-
src/couch_quickjs/quickjs/quickjs.c | 103 ++++--
6 files changed, 311 insertions(+), 249 deletions(-)
diff --git a/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
b/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
index 6a5f8f2d7..346978fde 100644
--- a/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
+++ b/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
@@ -1,6 +1,6 @@
---- quickjs-master/quickjs.c 2024-07-17 07:58:08
-+++ quickjs/quickjs.c 2024-07-18 11:37:31
-@@ -29451,10 +29451,24 @@
+--- quickjs-master/quickjs.c 2025-03-13 13:13:25
++++ quickjs/quickjs.c 2025-03-14 13:36:01
+@@ -29456,10 +29456,24 @@
if (s->token.val == TOK_FUNCTION ||
(token_is_pseudo_keyword(s, JS_ATOM_async) &&
peek_token(s, TRUE) == TOK_FUNCTION)) {
diff --git a/src/couch_quickjs/quickjs/libregexp.c
b/src/couch_quickjs/quickjs/libregexp.c
index a2d56a7d0..9295fe72f 100644
--- a/src/couch_quickjs/quickjs/libregexp.c
+++ b/src/couch_quickjs/quickjs/libregexp.c
@@ -54,6 +54,9 @@ typedef enum {
#define CAPTURE_COUNT_MAX 255
#define STACK_SIZE_MAX 255
+/* must be large enough to have a negligible runtime cost and small
+ enough to call the interrupt callback often. */
+#define INTERRUPT_COUNTER_INIT 10000
/* unicode code points */
#define CP_LS 0x2028
@@ -1931,6 +1934,7 @@ typedef struct {
BOOL multi_line;
BOOL ignore_case;
BOOL is_unicode;
+ int interrupt_counter;
void *opaque; /* used for stack overflow check */
size_t state_size;
@@ -1977,7 +1981,17 @@ static int push_state(REExecContext *s,
return 0;
}
-/* return 1 if match, 0 if not match or -1 if error. */
+static int lre_poll_timeout(REExecContext *s)
+{
+ if (unlikely(--s->interrupt_counter <= 0)) {
+ s->interrupt_counter = INTERRUPT_COUNTER_INIT;
+ if (lre_check_timeout(s->opaque))
+ return LRE_RET_TIMEOUT;
+ }
+ return 0;
+}
+
+/* return 1 if match, 0 if not match or < 0 if error. */
static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
StackInt *stack, int stack_len,
const uint8_t *pc, const uint8_t *cptr,
@@ -2008,6 +2022,8 @@ static intptr_t lre_exec_backtrack(REExecContext *s,
uint8_t **capture,
ret = 0;
recurse:
for(;;) {
+ if (lre_poll_timeout(s))
+ return LRE_RET_TIMEOUT;
if (s->state_stack_len == 0)
return ret;
rs = (REExecState *)(s->state_stack +
@@ -2097,7 +2113,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s,
uint8_t **capture,
ret = push_state(s, capture, stack, stack_len,
pc1, cptr, RE_EXEC_STATE_SPLIT, 0);
if (ret < 0)
- return -1;
+ return LRE_RET_MEMORY_ERROR;
break;
}
case REOP_lookahead:
@@ -2109,12 +2125,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s,
uint8_t **capture,
RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead,
0);
if (ret < 0)
- return -1;
+ return LRE_RET_MEMORY_ERROR;
break;
case REOP_goto:
val = get_u32(pc);
pc += 4 + (int)val;
+ if (lre_poll_timeout(s))
+ return LRE_RET_TIMEOUT;
break;
case REOP_line_start:
if (cptr == s->cbuf)
@@ -2179,6 +2197,8 @@ static intptr_t lre_exec_backtrack(REExecContext *s,
uint8_t **capture,
pc += 4;
if (--stack[stack_len - 1] != 0) {
pc += (int)val;
+ if (lre_poll_timeout(s))
+ return LRE_RET_TIMEOUT;
}
break;
case REOP_push_char_pos:
@@ -2353,9 +2373,12 @@ static intptr_t lre_exec_backtrack(REExecContext *s,
uint8_t **capture,
q = 0;
for(;;) {
+ if (lre_poll_timeout(s))
+ return LRE_RET_TIMEOUT;
res = lre_exec_backtrack(s, capture, stack, stack_len,
pc1, cptr, TRUE);
- if (res == -1)
+ if (res == LRE_RET_MEMORY_ERROR ||
+ res == LRE_RET_TIMEOUT)
return res;
if (!res)
break;
@@ -2373,7 +2396,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s,
uint8_t **capture,
RE_EXEC_STATE_GREEDY_QUANT,
q - quant_min);
if (ret < 0)
- return -1;
+ return LRE_RET_MEMORY_ERROR;
}
}
break;
@@ -2383,7 +2406,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s,
uint8_t **capture,
}
}
-/* Return 1 if match, 0 if not match or -1 if error. cindex is the
+/* Return 1 if match, 0 if not match or < 0 if error (see LRE_RET_x). cindex
is the
starting position of the match and must be such as 0 <= cindex <=
clen. */
int lre_exec(uint8_t **capture,
@@ -2405,6 +2428,7 @@ int lre_exec(uint8_t **capture,
s->cbuf_type = cbuf_type;
if (s->cbuf_type == 1 && s->is_unicode)
s->cbuf_type = 2;
+ s->interrupt_counter = INTERRUPT_COUNTER_INIT;
s->opaque = opaque;
s->state_size = sizeof(REExecState) +
diff --git a/src/couch_quickjs/quickjs/libregexp.h
b/src/couch_quickjs/quickjs/libregexp.h
index 7af7ece0f..7475bbea9 100644
--- a/src/couch_quickjs/quickjs/libregexp.h
+++ b/src/couch_quickjs/quickjs/libregexp.h
@@ -36,6 +36,9 @@
#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the
regexp */
+#define LRE_RET_MEMORY_ERROR (-1)
+#define LRE_RET_TIMEOUT (-2)
+
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
const char *buf, size_t buf_len, int re_flags,
void *opaque);
@@ -50,6 +53,8 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16);
/* must be provided by the user, return non zero if overflow */
int lre_check_stack_overflow(void *opaque, size_t alloca_size);
+/* must be provided by the user, return non zero if time out */
+int lre_check_timeout(void *opaque);
void *lre_realloc(void *opaque, void *ptr, size_t size);
#endif /* LIBREGEXP_H */
diff --git a/src/couch_quickjs/quickjs/libunicode.c
b/src/couch_quickjs/quickjs/libunicode.c
index c80d2f3d1..d1bf1e91c 100644
--- a/src/couch_quickjs/quickjs/libunicode.c
+++ b/src/couch_quickjs/quickjs/libunicode.c
@@ -537,6 +537,207 @@ int cr_invert(CharRange *cr)
return 0;
}
+#define CASE_U (1 << 0)
+#define CASE_L (1 << 1)
+#define CASE_F (1 << 2)
+
+/* use the case conversion table to generate range of characters.
+ CASE_U: set char if modified by uppercasing,
+ CASE_L: set char if modified by lowercasing,
+ CASE_F: set char if modified by case folding,
+ */
+static int unicode_case1(CharRange *cr, int case_mask)
+{
+#define MR(x) (1 << RUN_TYPE_ ## x)
+ const uint32_t tab_run_mask[3] = {
+ MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
+ MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
+
+ MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) |
MR(LF_EXT2),
+
+ MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) |
MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) |
MR(UF_EXT3),
+ };
+#undef MR
+ uint32_t mask, v, code, type, len, i, idx;
+
+ if (case_mask == 0)
+ return 0;
+ mask = 0;
+ for(i = 0; i < 3; i++) {
+ if ((case_mask >> i) & 1)
+ mask |= tab_run_mask[i];
+ }
+ for(idx = 0; idx < countof(case_conv_table1); idx++) {
+ v = case_conv_table1[idx];
+ type = (v >> (32 - 17 - 7 - 4)) & 0xf;
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ if ((mask >> type) & 1) {
+ // printf("%d: type=%d %04x %04x\n", idx, type, code,
code + len - 1);
+ switch(type) {
+ case RUN_TYPE_UL:
+ if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
+ goto def_case;
+ code += ((case_mask & CASE_U) != 0);
+ for(i = 0; i < len; i += 2) {
+ if (cr_add_interval(cr, code + i, code + i + 1))
+ return -1;
+ }
+ break;
+ case RUN_TYPE_LSU:
+ if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
+ goto def_case;
+ if (!(case_mask & CASE_U)) {
+ if (cr_add_interval(cr, code, code + 1))
+ return -1;
+ }
+ if (cr_add_interval(cr, code + 1, code + 2))
+ return -1;
+ if (case_mask & CASE_U) {
+ if (cr_add_interval(cr, code + 2, code + 3))
+ return -1;
+ }
+ break;
+ default:
+ def_case:
+ if (cr_add_interval(cr, code, code + len))
+ return -1;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int point_cmp(const void *p1, const void *p2, void *arg)
+{
+ uint32_t v1 = *(uint32_t *)p1;
+ uint32_t v2 = *(uint32_t *)p2;
+ return (v1 > v2) - (v1 < v2);
+}
+
+static void cr_sort_and_remove_overlap(CharRange *cr)
+{
+ uint32_t start, end, start1, end1, i, j;
+
+ /* the resulting ranges are not necessarily sorted and may overlap */
+ rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp,
NULL);
+ j = 0;
+ for(i = 0; i < cr->len; ) {
+ start = cr->points[i];
+ end = cr->points[i + 1];
+ i += 2;
+ while (i < cr->len) {
+ start1 = cr->points[i];
+ end1 = cr->points[i + 1];
+ if (start1 > end) {
+ /* |------|
+ * |-------| */
+ break;
+ } else if (end1 <= end) {
+ /* |------|
+ * |--| */
+ i += 2;
+ } else {
+ /* |------|
+ * |-------| */
+ end = end1;
+ i += 2;
+ }
+ }
+ cr->points[j] = start;
+ cr->points[j + 1] = end;
+ j += 2;
+ }
+ cr->len = j;
+}
+
+/* canonicalize a character set using the JS regex case folding rules
+ (see lre_canonicalize()) */
+int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
+{
+ CharRange cr_inter, cr_mask, cr_result, cr_sub;
+ uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
+
+ cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
+
+ if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
+ goto fail;
+ if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len,
CR_OP_INTER))
+ goto fail;
+
+ if (cr_invert(&cr_mask))
+ goto fail;
+ if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len,
CR_OP_INTER))
+ goto fail;
+
+ /* cr_inter = cr & cr_mask */
+ /* cr_sub = cr & ~cr_mask */
+
+ /* use the case conversion table to compute the result */
+ d_start = -1;
+ d_end = -1;
+ idx = 0;
+ v = case_conv_table1[idx];
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ for(i = 0; i < cr_inter.len; i += 2) {
+ start = cr_inter.points[i];
+ end = cr_inter.points[i + 1];
+
+ for(c = start; c < end; c++) {
+ for(;;) {
+ if (c >= code && c < code + len)
+ break;
+ idx++;
+ assert(idx < countof(case_conv_table1));
+ v = case_conv_table1[idx];
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ }
+ d = lre_case_folding_entry(c, idx, v, is_unicode);
+ /* try to merge with the current interval */
+ if (d_start == -1) {
+ d_start = d;
+ d_end = d + 1;
+ } else if (d_end == d) {
+ d_end++;
+ } else {
+ cr_add_interval(&cr_result, d_start, d_end);
+ d_start = d;
+ d_end = d + 1;
+ }
+ }
+ }
+ if (d_start != -1) {
+ if (cr_add_interval(&cr_result, d_start, d_end))
+ goto fail;
+ }
+
+ /* the resulting ranges are not necessarily sorted and may overlap */
+ cr_sort_and_remove_overlap(&cr_result);
+
+ /* or with the character not affected by the case folding */
+ cr->len = 0;
+ if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len,
CR_OP_UNION))
+ goto fail;
+
+ cr_free(&cr_inter);
+ cr_free(&cr_mask);
+ cr_free(&cr_result);
+ cr_free(&cr_sub);
+ return 0;
+ fail:
+ cr_free(&cr_inter);
+ cr_free(&cr_mask);
+ cr_free(&cr_result);
+ cr_free(&cr_sub);
+ return -1;
+}
+
#ifdef CONFIG_ALL_UNICODE
BOOL lre_is_id_start(uint32_t c)
@@ -1296,207 +1497,6 @@ static int unicode_prop1(CharRange *cr, int prop_idx)
return 0;
}
-#define CASE_U (1 << 0)
-#define CASE_L (1 << 1)
-#define CASE_F (1 << 2)
-
-/* use the case conversion table to generate range of characters.
- CASE_U: set char if modified by uppercasing,
- CASE_L: set char if modified by lowercasing,
- CASE_F: set char if modified by case folding,
- */
-static int unicode_case1(CharRange *cr, int case_mask)
-{
-#define MR(x) (1 << RUN_TYPE_ ## x)
- const uint32_t tab_run_mask[3] = {
- MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
- MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
-
- MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) |
MR(LF_EXT2),
-
- MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) |
MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) |
MR(UF_EXT3),
- };
-#undef MR
- uint32_t mask, v, code, type, len, i, idx;
-
- if (case_mask == 0)
- return 0;
- mask = 0;
- for(i = 0; i < 3; i++) {
- if ((case_mask >> i) & 1)
- mask |= tab_run_mask[i];
- }
- for(idx = 0; idx < countof(case_conv_table1); idx++) {
- v = case_conv_table1[idx];
- type = (v >> (32 - 17 - 7 - 4)) & 0xf;
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- if ((mask >> type) & 1) {
- // printf("%d: type=%d %04x %04x\n", idx, type, code,
code + len - 1);
- switch(type) {
- case RUN_TYPE_UL:
- if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
- goto def_case;
- code += ((case_mask & CASE_U) != 0);
- for(i = 0; i < len; i += 2) {
- if (cr_add_interval(cr, code + i, code + i + 1))
- return -1;
- }
- break;
- case RUN_TYPE_LSU:
- if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
- goto def_case;
- if (!(case_mask & CASE_U)) {
- if (cr_add_interval(cr, code, code + 1))
- return -1;
- }
- if (cr_add_interval(cr, code + 1, code + 2))
- return -1;
- if (case_mask & CASE_U) {
- if (cr_add_interval(cr, code + 2, code + 3))
- return -1;
- }
- break;
- default:
- def_case:
- if (cr_add_interval(cr, code, code + len))
- return -1;
- break;
- }
- }
- }
- return 0;
-}
-
-static int point_cmp(const void *p1, const void *p2, void *arg)
-{
- uint32_t v1 = *(uint32_t *)p1;
- uint32_t v2 = *(uint32_t *)p2;
- return (v1 > v2) - (v1 < v2);
-}
-
-static void cr_sort_and_remove_overlap(CharRange *cr)
-{
- uint32_t start, end, start1, end1, i, j;
-
- /* the resulting ranges are not necessarily sorted and may overlap */
- rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp,
NULL);
- j = 0;
- for(i = 0; i < cr->len; ) {
- start = cr->points[i];
- end = cr->points[i + 1];
- i += 2;
- while (i < cr->len) {
- start1 = cr->points[i];
- end1 = cr->points[i + 1];
- if (start1 > end) {
- /* |------|
- * |-------| */
- break;
- } else if (end1 <= end) {
- /* |------|
- * |--| */
- i += 2;
- } else {
- /* |------|
- * |-------| */
- end = end1;
- i += 2;
- }
- }
- cr->points[j] = start;
- cr->points[j + 1] = end;
- j += 2;
- }
- cr->len = j;
-}
-
-/* canonicalize a character set using the JS regex case folding rules
- (see lre_canonicalize()) */
-int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
-{
- CharRange cr_inter, cr_mask, cr_result, cr_sub;
- uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
-
- cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
- cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
- cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
- cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
-
- if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
- goto fail;
- if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len,
CR_OP_INTER))
- goto fail;
-
- if (cr_invert(&cr_mask))
- goto fail;
- if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len,
CR_OP_INTER))
- goto fail;
-
- /* cr_inter = cr & cr_mask */
- /* cr_sub = cr & ~cr_mask */
-
- /* use the case conversion table to compute the result */
- d_start = -1;
- d_end = -1;
- idx = 0;
- v = case_conv_table1[idx];
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- for(i = 0; i < cr_inter.len; i += 2) {
- start = cr_inter.points[i];
- end = cr_inter.points[i + 1];
-
- for(c = start; c < end; c++) {
- for(;;) {
- if (c >= code && c < code + len)
- break;
- idx++;
- assert(idx < countof(case_conv_table1));
- v = case_conv_table1[idx];
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- }
- d = lre_case_folding_entry(c, idx, v, is_unicode);
- /* try to merge with the current interval */
- if (d_start == -1) {
- d_start = d;
- d_end = d + 1;
- } else if (d_end == d) {
- d_end++;
- } else {
- cr_add_interval(&cr_result, d_start, d_end);
- d_start = d;
- d_end = d + 1;
- }
- }
- }
- if (d_start != -1) {
- if (cr_add_interval(&cr_result, d_start, d_end))
- goto fail;
- }
-
- /* the resulting ranges are not necessarily sorted and may overlap */
- cr_sort_and_remove_overlap(&cr_result);
-
- /* or with the character not affected by the case folding */
- cr->len = 0;
- if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len,
CR_OP_UNION))
- goto fail;
-
- cr_free(&cr_inter);
- cr_free(&cr_mask);
- cr_free(&cr_result);
- cr_free(&cr_sub);
- return 0;
- fail:
- cr_free(&cr_inter);
- cr_free(&cr_mask);
- cr_free(&cr_result);
- cr_free(&cr_sub);
- return -1;
-}
-
typedef enum {
POP_GC,
POP_PROP,
diff --git a/src/couch_quickjs/quickjs/quickjs-libc.c
b/src/couch_quickjs/quickjs/quickjs-libc.c
index 81371507f..141f79f3c 100644
--- a/src/couch_quickjs/quickjs/quickjs-libc.c
+++ b/src/couch_quickjs/quickjs/quickjs-libc.c
@@ -78,6 +78,10 @@ typedef sig_t sighandler_t;
#include "list.h"
#include "quickjs-libc.h"
+#if !defined(PATH_MAX)
+#define PATH_MAX 4096
+#endif
+
/* TODO:
- add socket calls
*/
@@ -1090,7 +1094,7 @@ static JSValue js_std_file_tell(JSContext *ctx,
JSValueConst this_val,
int64_t pos;
if (!f)
return JS_EXCEPTION;
-#if defined(__linux__)
+#if defined(__linux__) || defined(__GLIBC__)
pos = ftello(f);
#else
pos = ftell(f);
@@ -1113,7 +1117,7 @@ static JSValue js_std_file_seek(JSContext *ctx,
JSValueConst this_val,
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &whence, argv[1]))
return JS_EXCEPTION;
-#if defined(__linux__)
+#if defined(__linux__) || defined(__GLIBC__)
ret = fseeko(f, pos, whence);
#else
ret = fseek(f, pos, whence);
diff --git a/src/couch_quickjs/quickjs/quickjs.c
b/src/couch_quickjs/quickjs/quickjs.c
index 54f66ddde..cd35e64de 100644
--- a/src/couch_quickjs/quickjs/quickjs.c
+++ b/src/couch_quickjs/quickjs/quickjs.c
@@ -34,7 +34,7 @@
#include <math.h>
#if defined(__APPLE__)
#include <malloc/malloc.h>
-#elif defined(__linux__)
+#elif defined(__linux__) || defined(__GLIBC__)
#include <malloc.h>
#elif defined(__FreeBSD__)
#include <malloc_np.h>
@@ -363,10 +363,7 @@ typedef struct JSVarRef {
struct {
int __gc_ref_count; /* corresponds to header.ref_count */
uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
- uint8_t is_detached : 1;
- uint8_t is_arg : 1;
- uint16_t var_idx; /* index of the corresponding function variable
on
- the stack */
+ uint8_t is_detached;
};
};
JSValue *pvalue; /* pointer to the value, either on the stack or
@@ -1708,7 +1705,7 @@ static size_t js_def_malloc_usable_size(const void *ptr)
return _msize((void *)ptr);
#elif defined(EMSCRIPTEN)
return 0;
-#elif defined(__linux__)
+#elif defined(__linux__) || defined(__GLIBC__)
return malloc_usable_size((void *)ptr);
#else
/* change this to `return 0;` if compilation fails */
@@ -6836,15 +6833,19 @@ static JSValue JS_ThrowTypeErrorInvalidClass(JSContext
*ctx, int class_id)
return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
}
+static void JS_ThrowInterrupted(JSContext *ctx)
+{
+ JS_ThrowInternalError(ctx, "interrupted");
+ JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
+}
+
static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
if (rt->interrupt_handler) {
if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
- /* XXX: should set a specific flag to avoid catching */
- JS_ThrowInternalError(ctx, "interrupted");
- JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
+ JS_ThrowInterrupted(ctx);
return -1;
}
}
@@ -8601,6 +8602,8 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst
obj,
goto retry2;
} else if (!(prs->flags & JS_PROP_WRITABLE)) {
goto read_only_prop;
+ } else {
+ break;
}
}
}
@@ -14855,16 +14858,16 @@ static JSValue js_build_arguments(JSContext *ctx, int
argc, JSValueConst *argv)
/* add the length field (cannot fail) */
pr = add_property(ctx, p, JS_ATOM_length,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ if (unlikely(!pr))
+ goto fail;
pr->u.value = JS_NewInt32(ctx, argc);
/* initialize the fast array part */
tab = NULL;
if (argc > 0) {
tab = js_malloc(ctx, sizeof(tab[0]) * argc);
- if (!tab) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
+ if (!tab)
+ goto fail;
for(i = 0; i < argc; i++) {
tab[i] = JS_DupValue(ctx, argv[i]);
}
@@ -14880,6 +14883,9 @@ static JSValue js_build_arguments(JSContext *ctx, int
argc, JSValueConst *argv)
ctx->throw_type_error, ctx->throw_type_error,
JS_PROP_HAS_GET | JS_PROP_HAS_SET);
return val;
+ fail:
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
}
#define GLOBAL_VAR_OFFSET 0x40000000
@@ -14904,6 +14910,8 @@ static JSValue js_build_mapped_arguments(JSContext
*ctx, int argc,
/* add the length field (cannot fail) */
pr = add_property(ctx, p, JS_ATOM_length,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ if (unlikely(!pr))
+ goto fail;
pr->u.value = JS_NewInt32(ctx, argc);
for(i = 0; i < arg_count; i++) {
@@ -15662,10 +15670,16 @@ static JSVarRef *get_var_ref(JSContext *ctx,
JSStackFrame *sf,
{
JSVarRef *var_ref;
struct list_head *el;
+ JSValue *pvalue;
+
+ if (is_arg)
+ pvalue = &sf->arg_buf[var_idx];
+ else
+ pvalue = &sf->var_buf[var_idx];
list_for_each(el, &sf->var_ref_list) {
var_ref = list_entry(el, JSVarRef, var_ref_link);
- if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
+ if (var_ref->pvalue == pvalue) {
var_ref->header.ref_count++;
return var_ref;
}
@@ -15677,8 +15691,6 @@ static JSVarRef *get_var_ref(JSContext *ctx,
JSStackFrame *sf,
var_ref->header.ref_count = 1;
add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
var_ref->is_detached = FALSE;
- var_ref->is_arg = is_arg;
- var_ref->var_idx = var_idx;
list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list);
if (sf->js_mode & JS_MODE_ASYNC) {
/* The stack frame is detached and may be destroyed at any
@@ -15694,10 +15706,7 @@ static JSVarRef *get_var_ref(JSContext *ctx,
JSStackFrame *sf,
} else {
var_ref->async_func = NULL;
}
- if (is_arg)
- var_ref->pvalue = &sf->arg_buf[var_idx];
- else
- var_ref->pvalue = &sf->var_buf[var_idx];
+ var_ref->pvalue = pvalue;
return var_ref;
}
@@ -15925,37 +15934,33 @@ static void close_var_refs(JSRuntime *rt,
JSStackFrame *sf)
{
struct list_head *el, *el1;
JSVarRef *var_ref;
- int var_idx;
list_for_each_safe(el, el1, &sf->var_ref_list) {
var_ref = list_entry(el, JSVarRef, var_ref_link);
/* no need to unlink var_ref->var_ref_link as the list is never used
afterwards */
if (var_ref->async_func)
async_func_free(rt, var_ref->async_func);
- var_idx = var_ref->var_idx;
- if (var_ref->is_arg)
- var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]);
- else
- var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]);
+ var_ref->value = JS_DupValueRT(rt, *var_ref->pvalue);
var_ref->pvalue = &var_ref->value;
/* the reference is no longer to a local variable */
var_ref->is_detached = TRUE;
}
}
-static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int
is_arg)
+static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int var_idx)
{
+ JSValue *pvalue;
struct list_head *el, *el1;
JSVarRef *var_ref;
- int var_idx = idx;
+ pvalue = &sf->var_buf[var_idx];
list_for_each_safe(el, el1, &sf->var_ref_list) {
var_ref = list_entry(el, JSVarRef, var_ref_link);
- if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) {
+ if (var_ref->pvalue == pvalue) {
list_del(&var_ref->var_ref_link);
if (var_ref->async_func)
async_func_free(ctx->rt, var_ref->async_func);
- var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]);
+ var_ref->value = JS_DupValue(ctx, *var_ref->pvalue);
var_ref->pvalue = &var_ref->value;
/* the reference is no longer to a local variable */
var_ref->is_detached = TRUE;
@@ -17188,7 +17193,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx,
JSValueConst func_obj,
int idx;
idx = get_u16(pc);
pc += 2;
- close_lexical_var(ctx, sf, idx, FALSE);
+ close_lexical_var(ctx, sf, idx);
}
BREAK;
@@ -43921,12 +43926,20 @@ fail:
return JS_EXCEPTION;
}
-BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
+int lre_check_stack_overflow(void *opaque, size_t alloca_size)
{
JSContext *ctx = opaque;
return js_check_stack_overflow(ctx->rt, alloca_size);
}
+int lre_check_timeout(void *opaque)
+{
+ JSContext *ctx = opaque;
+ JSRuntime *rt = ctx->rt;
+ return (rt->interrupt_handler &&
+ rt->interrupt_handler(rt, rt->interrupt_opaque));
+}
+
void *lre_realloc(void *opaque, void *ptr, size_t size)
{
JSContext *ctx = opaque;
@@ -43994,7 +44007,11 @@ static JSValue js_regexp_exec(JSContext *ctx,
JSValueConst this_val,
goto fail;
}
} else {
- JS_ThrowInternalError(ctx, "out of memory in regexp execution");
+ if (rc == LRE_RET_TIMEOUT) {
+ JS_ThrowInterrupted(ctx);
+ } else {
+ JS_ThrowInternalError(ctx, "out of memory in regexp
execution");
+ }
goto fail;
}
} else {
@@ -44190,7 +44207,11 @@ static JSValue JS_RegExpDelete(JSContext *ctx,
JSValueConst this_val, JSValueCon
goto fail;
}
} else {
- JS_ThrowInternalError(ctx, "out of memory in regexp
execution");
+ if (ret == LRE_RET_TIMEOUT) {
+ JS_ThrowInterrupted(ctx);
+ } else {
+ JS_ThrowInternalError(ctx, "out of memory in regexp
execution");
+ }
goto fail;
}
break;
@@ -45399,6 +45420,11 @@ static int js_json_to_str(JSContext *ctx,
JSONStringifyContext *jsc,
tab = JS_UNDEFINED;
prop = JS_UNDEFINED;
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ goto exception;
+ }
+
if (JS_IsObject(val)) {
p = JS_VALUE_GET_OBJ(val);
cl = p->class_id;
@@ -50020,6 +50046,9 @@ static BOOL string_get_digits(const uint8_t *sp, int
*pp, int *pval,
p_start = p;
while ((c = sp[p]) >= '0' && c <= '9') {
+ /* arbitrary limit to 9 digits */
+ if (v >= 100000000)
+ return FALSE;
v = v * 10 + c - '0';
p++;
if (p - p_start == max_digits)
@@ -50067,7 +50096,7 @@ static BOOL string_get_tzoffset(const uint8_t *sp, int
*pp, int *tzp, BOOL stric
sgn = sp[p++];
if (sgn == '+' || sgn == '-') {
int n = p;
- if (!string_get_digits(sp, &p, &hh, 1, 9))
+ if (!string_get_digits(sp, &p, &hh, 1, 0))
return FALSE;
n = p - n;
if (strict && n != 2 && n != 4)
@@ -50259,7 +50288,7 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp,
*is_local = FALSE;
} else {
p++;
- if (string_get_digits(sp, &p, &val, 1, 9)) {
+ if (string_get_digits(sp, &p, &val, 1, 0)) {
if (c == '-') {
if (val == 0)
return FALSE;
@@ -50270,7 +50299,7 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp,
}
}
} else
- if (string_get_digits(sp, &p, &val, 1, 9)) {
+ if (string_get_digits(sp, &p, &val, 1, 0)) {
if (string_skip_char(sp, &p, ':')) {
/* time part */
fields[3] = val;