diff --git a/ext/lexbor/lexbor/core/swar.h b/ext/lexbor/lexbor/core/swar.h index 78579ad4bee7..ec0a13b8e23f 100644 --- a/ext/lexbor/lexbor/core/swar.h +++ b/ext/lexbor/lexbor/core/swar.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2024 Alexander Borisov * - * Author: Nora Dossche + * Author: Niels Dossche */ #ifndef LEXBOR_SWAR_H diff --git a/ext/lexbor/lexbor/url/url.c b/ext/lexbor/lexbor/url/url.c index 5c6d5cc7a6a2..1fd044bbf950 100644 --- a/ext/lexbor/lexbor/url/url.c +++ b/ext/lexbor/lexbor/url/url.c @@ -499,6 +499,7 @@ lxb_url_scheme_length = sizeof(lxb_url_scheme_res) / sizeof(lxb_url_scheme_data_ if (tmp == NULL) { \ return NULL; \ } \ + memcpy(tmp, (sbuf_begin), offset); \ } \ else { \ tmp = lexbor_realloc((sbuf_begin), new_len); \ @@ -509,7 +510,7 @@ lxb_url_scheme_length = sizeof(lxb_url_scheme_res) / sizeof(lxb_url_scheme_data_ } \ \ (sbuf) = tmp + offset; \ - (last) = sbuf + lst; \ + (last) = tmp + lst; \ (sbuf_begin) = tmp; \ (sbuf_end) = tmp + new_len; \ } \ diff --git a/ext/lexbor/patches/0001-Expose-line-and-column-information-for-use-in-PHP.patch b/ext/lexbor/patches/0001-Expose-line-and-column-information-for-use-in-PHP.patch index 32d9d42d2bf1..e106b413c22c 100644 --- a/ext/lexbor/patches/0001-Expose-line-and-column-information-for-use-in-PHP.patch +++ b/ext/lexbor/patches/0001-Expose-line-and-column-information-for-use-in-PHP.patch @@ -1,7 +1,7 @@ -From 0cd2add6c46400b808329442f81451b369863983 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 26 Aug 2023 15:08:59 +0200 -Subject: [PATCH 1/6] Expose line and column information for use in PHP +Subject: [PATCH 1/9] Expose line and column information for use in PHP --- source/lexbor/dom/interfaces/node.h | 2 ++ @@ -183,6 +183,3 @@ index 7a212af..b186772 100644 } lxb_html_tree_error_t; --- -2.51.2 - diff --git a/ext/lexbor/patches/0002-Track-implied-added-nodes-for-options-use-in-PHP.patch b/ext/lexbor/patches/0002-Track-implied-added-nodes-for-options-use-in-PHP.patch index 1902abf96e3a..9e83700198e1 100644 --- a/ext/lexbor/patches/0002-Track-implied-added-nodes-for-options-use-in-PHP.patch +++ b/ext/lexbor/patches/0002-Track-implied-added-nodes-for-options-use-in-PHP.patch @@ -1,7 +1,7 @@ -From a4c29ba8d1ea1065ce6bd4a34382d53140cf1924 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 14 Aug 2023 20:18:51 +0200 -Subject: [PATCH 2/6] Track implied added nodes for options use in PHP +Subject: [PATCH 2/9] Track implied added nodes for options use in PHP --- source/lexbor/html/tree.h | 3 +++ @@ -62,6 +62,3 @@ index 05fe738..1e09cda 100644 tree->mode = lxb_html_tree_insertion_mode_before_head; break; --- -2.51.2 - diff --git a/ext/lexbor/patches/0003-Patch-utilities-and-data-structure-to-be-able-to-gen.patch b/ext/lexbor/patches/0003-Patch-utilities-and-data-structure-to-be-able-to-gen.patch index 51f77483bc6e..9ed36fda109d 100644 --- a/ext/lexbor/patches/0003-Patch-utilities-and-data-structure-to-be-able-to-gen.patch +++ b/ext/lexbor/patches/0003-Patch-utilities-and-data-structure-to-be-able-to-gen.patch @@ -1,7 +1,7 @@ -From 46fc776449252e74795569759a19d13857a59069 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:57:48 +0200 -Subject: [PATCH 3/6] Patch utilities and data structure to be able to generate +Subject: [PATCH 3/9] Patch utilities and data structure to be able to generate smaller lookup tables Changed the generation script to check if everything fits in 32-bits. @@ -92,6 +92,3 @@ index 3e75812..2370c66 100755 result.append("};") --- -2.51.2 - diff --git a/ext/lexbor/patches/0004-Remove-unused-upper-case-tag-static-data.patch b/ext/lexbor/patches/0004-Remove-unused-upper-case-tag-static-data.patch index 6cb6658a164b..9e9fcaf8db7a 100644 --- a/ext/lexbor/patches/0004-Remove-unused-upper-case-tag-static-data.patch +++ b/ext/lexbor/patches/0004-Remove-unused-upper-case-tag-static-data.patch @@ -1,7 +1,7 @@ -From ae9d7254ac129cc3be34de6fd34af27baf3bb396 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 29 Nov 2023 21:26:47 +0100 -Subject: [PATCH 4/6] Remove unused upper case tag static data +Subject: [PATCH 4/9] Remove unused upper case tag static data --- source/lexbor/tag/res.h | 2 ++ @@ -48,6 +48,3 @@ index 780bc47..be5bb30 100644 /* * No inline functions for ABI. --- -2.51.2 - diff --git a/ext/lexbor/patches/0005-Shrink-size-of-static-binary-search-tree.patch b/ext/lexbor/patches/0005-Shrink-size-of-static-binary-search-tree.patch index 9ef6e305e498..ce3448169395 100644 --- a/ext/lexbor/patches/0005-Shrink-size-of-static-binary-search-tree.patch +++ b/ext/lexbor/patches/0005-Shrink-size-of-static-binary-search-tree.patch @@ -1,7 +1,7 @@ -From 19cf6183813e013dfe0eb2303c15eaf6e01b9faf Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 29 Nov 2023 21:29:31 +0100 -Subject: [PATCH 5/6] Shrink size of static binary search tree +Subject: [PATCH 5/9] Shrink size of static binary search tree This also makes it more efficient on the data cache. --- @@ -111,6 +111,3 @@ index 2370c66..c41e645 100755 self.buffer.append(line) fh.close() --- -2.51.2 - diff --git a/ext/lexbor/patches/0006-Patch-out-unused-CSS-style-code.patch b/ext/lexbor/patches/0006-Patch-out-unused-CSS-style-code.patch index a643f9716488..c8f485f34807 100644 --- a/ext/lexbor/patches/0006-Patch-out-unused-CSS-style-code.patch +++ b/ext/lexbor/patches/0006-Patch-out-unused-CSS-style-code.patch @@ -1,7 +1,7 @@ -From 54399ee441d922d89c32909e2028f899f6091cd6 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 7 Jan 2024 21:59:28 +0100 -Subject: [PATCH 6/6] Patch out unused CSS style code +Subject: [PATCH 6/9] Patch out unused CSS style code --- source/lexbor/css/rule.h | 2 ++ @@ -27,6 +27,3 @@ index 308dced..d192a01 100644 } lxb_inline void --- -2.51.2 - diff --git a/ext/lexbor/patches/0007-Add-Is_Special_Url_Support.patch b/ext/lexbor/patches/0007-Add-lxb_url_is_special-to-the-public-API-362.patch similarity index 86% rename from ext/lexbor/patches/0007-Add-Is_Special_Url_Support.patch rename to ext/lexbor/patches/0007-Add-lxb_url_is_special-to-the-public-API-362.patch index 6f5e126336d0..b56a1d1f06ab 100644 --- a/ext/lexbor/patches/0007-Add-Is_Special_Url_Support.patch +++ b/ext/lexbor/patches/0007-Add-lxb_url_is_special-to-the-public-API-362.patch @@ -1,7 +1,7 @@ -From 9181fce509ab9b37c02994545f3971687433e770 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sun, 17 May 2026 22:17:14 +0200 -Subject: [PATCH] Add lxb_url_is_special() to the public API (#362) +Subject: [PATCH 7/9] Add lxb_url_is_special() to the public API (#362) As https://wiki.php.net/rfc/uri_followup#uri_type_detection relies on this information. --- @@ -10,7 +10,7 @@ As https://wiki.php.net/rfc/uri_followup#uri_type_detection relies on this infor 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/lexbor/url/url.c b/source/lexbor/url/url.c -index 5a114346..a5b323f2 100644 +index 5a11434..a5b323f 100644 --- a/source/lexbor/url/url.c +++ b/source/lexbor/url/url.c @@ -860,7 +860,7 @@ lxb_url_is_url_codepoint(lxb_codepoint_t cp) @@ -23,7 +23,7 @@ index 5a114346..a5b323f2 100644 { return url->scheme.type != LXB_URL_SCHEMEL_TYPE__UNKNOWN; diff --git a/source/lexbor/url/url.h b/source/lexbor/url/url.h -index 4ed3f32a..6cc6f108 100644 +index 4ed3f32..6cc6f10 100644 --- a/source/lexbor/url/url.h +++ b/source/lexbor/url/url.h @@ -763,6 +763,15 @@ LXB_API lxb_status_t @@ -41,4 +41,4 @@ index 4ed3f32a..6cc6f108 100644 + /* * Inline functions. - */ \ No newline at end of file + */ diff --git a/ext/lexbor/patches/0008-Fix-empty-port-setter.patch b/ext/lexbor/patches/0008-URL-fixed-setters-for-empty-hosts.patch similarity index 91% rename from ext/lexbor/patches/0008-Fix-empty-port-setter.patch rename to ext/lexbor/patches/0008-URL-fixed-setters-for-empty-hosts.patch index 75ceaab0c63f..de66962e7cca 100644 --- a/ext/lexbor/patches/0008-Fix-empty-port-setter.patch +++ b/ext/lexbor/patches/0008-URL-fixed-setters-for-empty-hosts.patch @@ -1,7 +1,7 @@ -From cf07699ca0f5fa4e1f7fd05c2135fd38e6d196c2 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Fri, 26 Jun 2026 18:55:56 +0300 -Subject: [PATCH] URL: fixed setters for empty hosts. +Subject: [PATCH 8/9] URL: fixed setters for empty hosts. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -22,13 +22,13 @@ This relates to #387 issue on GitHub. 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/source/lexbor/url/url.c b/source/lexbor/url/url.c -index ced4462b..e1da2c38 100644 +index a5b323f..5c6d5cc 100644 --- a/source/lexbor/url/url.c +++ b/source/lexbor/url/url.c -@@ -1116,11 +1116,13 @@ lxb_url_host_copy(const lxb_url_host_t *src, lxb_url_host_t *dst, - +@@ -1115,11 +1115,13 @@ lxb_url_host_copy(const lxb_url_host_t *src, lxb_url_host_t *dst, + dst->type = src->type; - + - if (src->type <= LXB_URL_HOST_TYPE_OPAQUE) { - if (src->type == LXB_URL_HOST_TYPE__UNDEF) { - return LXB_STATUS_OK; @@ -38,15 +38,15 @@ index ced4462b..e1da2c38 100644 + { + return LXB_STATUS_OK; + } - + + if (src->type <= LXB_URL_HOST_TYPE_OPAQUE) { return lxb_url_str_copy(&src->u.domain, &dst->u.domain, dst_mraw); } -@@ -1153,6 +1155,24 @@ lxb_url_host_set_empty(lxb_url_host_t *host, lexbor_mraw_t *mraw) +@@ -1152,6 +1154,24 @@ lxb_url_host_set_empty(lxb_url_host_t *host, lexbor_mraw_t *mraw) host->type = LXB_URL_HOST_TYPE_EMPTY; } - + +lxb_inline bool +lxb_url_host_is_empty(const lxb_url_host_t *host) +{ @@ -68,7 +68,7 @@ index ced4462b..e1da2c38 100644 static bool lxb_url_host_eq(lxb_url_host_t *host, const lxb_char_t *data, size_t length) { -@@ -1252,7 +1272,7 @@ lxb_url_normalized_windows_drive_letter(const lxb_char_t *data, +@@ -1251,7 +1271,7 @@ lxb_url_normalized_windows_drive_letter(const lxb_char_t *data, static bool lxb_url_cannot_have_user_pass_port(lxb_url_t *url) { @@ -77,20 +77,20 @@ index ced4462b..e1da2c38 100644 || url->host.type == LXB_URL_HOST_TYPE__UNDEF || url->scheme.type == LXB_URL_SCHEMEL_TYPE_FILE; } -@@ -3979,6 +3999,11 @@ lxb_url_opaque_host_parse(lxb_url_parser_t *parser, const lxb_char_t *data, +@@ -3978,6 +3998,11 @@ lxb_url_opaque_host_parse(lxb_url_parser_t *parser, const lxb_char_t *data, lxb_status_t status; const lxb_char_t *p; - + + if (data == end) { + lxb_url_host_set_empty(host, mraw); + return LXB_STATUS_OK; + } + p = data; - + while (p < end) { diff --git a/test/files/lexbor/url/changes.ton b/test/files/lexbor/url/changes.ton -index 07bc9449..1a0b6e35 100644 +index 07bc944..1a0b6e3 100644 --- a/test/files/lexbor/url/changes.ton +++ b/test/files/lexbor/url/changes.ton @@ -1,5 +1,5 @@ @@ -167,7 +167,7 @@ index 07bc9449..1a0b6e35 100644 } ] diff --git a/test/files/lexbor/url/url.ton b/test/files/lexbor/url/url.ton -index 2baa4bc2..85794c5b 100644 +index 2baa4bc..85794c5 100644 --- a/test/files/lexbor/url/url.ton +++ b/test/files/lexbor/url/url.ton @@ -1,5 +1,5 @@ diff --git a/ext/lexbor/patches/0009-URL-fixed-uninitialized-memory-in-the-path-buffer-gr.patch b/ext/lexbor/patches/0009-URL-fixed-uninitialized-memory-in-the-path-buffer-gr.patch new file mode 100644 index 000000000000..0fde094eefdf --- /dev/null +++ b/ext/lexbor/patches/0009-URL-fixed-uninitialized-memory-in-the-path-buffer-gr.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alexander Borisov +Date: Fri, 5 Jun 2026 22:13:32 +0300 +Subject: [PATCH 9/9] URL: fixed uninitialized memory in the path buffer + growth. + +When a path was long enough to outgrow the on-stack buffer, the first +move to the heap didn't copy what was already written, so the start of +the path could contain garbage. Also fixed the 'last' pointer after the +move. + +Per report from Recep Asan (recep@asan.me) +--- + source/lexbor/url/url.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/source/lexbor/url/url.c b/source/lexbor/url/url.c +index 5c6d5cc..1fd044b 100644 +--- a/source/lexbor/url/url.c ++++ b/source/lexbor/url/url.c +@@ -499,6 +499,7 @@ lxb_url_scheme_length = sizeof(lxb_url_scheme_res) / sizeof(lxb_url_scheme_data_ + if (tmp == NULL) { \ + return NULL; \ + } \ ++ memcpy(tmp, (sbuf_begin), offset); \ + } \ + else { \ + tmp = lexbor_realloc((sbuf_begin), new_len); \ +@@ -509,7 +510,7 @@ lxb_url_scheme_length = sizeof(lxb_url_scheme_res) / sizeof(lxb_url_scheme_data_ + } \ + \ + (sbuf) = tmp + offset; \ +- (last) = sbuf + lst; \ ++ (last) = tmp + lst; \ + (sbuf_begin) = tmp; \ + (sbuf_end) = tmp + new_len; \ + } \ diff --git a/ext/lexbor/patches/update-lexbor.sh b/ext/lexbor/patches/update-lexbor.sh index 55e330a87644..ae288285453d 100755 --- a/ext/lexbor/patches/update-lexbor.sh +++ b/ext/lexbor/patches/update-lexbor.sh @@ -25,8 +25,9 @@ for patch in "${patches[@]}"; do done # Refresh patches +rm "$PATCHES_DIR"/*.patch NUM_PATCHES=${#patches[@]} -git format-patch "HEAD~$NUM_PATCHES" -o "$PATCHES_DIR" +git format-patch --no-signature --zero-commit "HEAD~$NUM_PATCHES" -o "$PATCHES_DIR" # Run code-generation tools (cd "$LEXBOR_TMP_DIR/utils/lexbor/encoding" && python3 single-byte.py) diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 2fe0b1896a92..d62ef95b5513 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -14234,6 +14234,26 @@ static int zend_jit_class_guard(zend_jit_ctx *jit, const zend_op *opline, ir_ref return 1; } +static int zend_jit_func_arg_by_ref_guard(zend_jit_ctx *jit, const zend_op *opline) +{ + int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); + const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); + ir_ref rx, call_info; + + if (!exit_addr) { + return 0; + } + if (jit->reuse_ip) { + rx = jit_IP(jit); + } else { + rx = ir_LOAD_A(jit_EX(call)); + } + call_info = ir_LOAD_U32(jit_CALL(rx, This.u1.type_info)); + ir_GUARD_NOT(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)), + ir_CONST_ADDR(exit_addr)); + return 1; +} + static int zend_jit_fetch_obj(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 024a5d0e194d..77bfaa03473a 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -6037,10 +6037,15 @@ static zend_vm_opcode_handler_t zend_jit_trace(zend_jit_trace_rec *trace_buffer, case ZEND_FETCH_OBJ_FUNC_ARG: if (!JIT_G(current_frame) || !JIT_G(current_frame)->call - || !JIT_G(current_frame)->call->func - || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) { + || TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) { break; } + if (!JIT_G(current_frame)->call->func + || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) { + if (!zend_jit_func_arg_by_ref_guard(&ctx, opline)) { + goto jit_failure; + } + } ZEND_FALLTHROUGH; case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_IS: diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 271d923598d9..85a81c1573bc 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -978,6 +978,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, } } break; + case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_R: { if (opline->op2_type == IS_CONST) { /* Remove the SIMPLE_GET flag to avoid inlining hooks. */ @@ -992,7 +993,6 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_IS: - case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_UNSET: case ZEND_ASSIGN_OBJ: case ZEND_ASSIGN_OBJ_OP: diff --git a/ext/opcache/tests/jit/gh21006.phpt b/ext/opcache/tests/jit/gh21006.phpt new file mode 100644 index 000000000000..a201391505ab --- /dev/null +++ b/ext/opcache/tests/jit/gh21006.phpt @@ -0,0 +1,79 @@ +--TEST-- +GH-21006: JIT SEGV with FETCH_OBJ_FUNC_ARG and property hooks +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_hot_loop=1 +opcache.jit_hot_func=1 +opcache.jit_hot_return=1 +opcache.jit_hot_side_exit=1 +--FILE-- + 'sha256'; + } + + public function sign() + { + return hash_hmac( + algo: $this->prop, + data: '', + key: '', + ); + } +} + +$obj = new C(); +for ($i = 0; $i < 100; $i++) { + $obj->sign(); +} + +#[\AllowDynamicProperties] +class D +{ + public function test() + { + return hash_hmac( + algo: $this->algo, + data: '', + key: '', + ); + } +} + +$d = new D(); +$d->algo = 'sha256'; +for ($i = 0; $i < 100; $i++) { + $d->test(); +} + +class E +{ + public $prop { + get => []; + } + + public function sign() + { + (new Trampoline)->f($this->prop); + } +} + +class Trampoline +{ + public function __call($name, $args) {} +} + +$e = new E(); +for ($i = 0; $i < 100; $i++) { + $e->sign(); +} +echo "OK\n"; +?> +--EXPECT-- +OK