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;

Reply via email to