From 7e19cb1c558d7e0adf8fe6e4f262832a90de3297 Mon Sep 17 00:00:00 2001 From: PGZXB Date: Fri, 25 Sep 2026 14:12:22 +0800 Subject: [PATCH] Fix heap-buffer-overflow during GC of an externally-backed SharedArrayBuffer Externally-backed ArrayBuffer/SharedArrayBuffer objects wrap a caller-supplied buffer. When no array-buffer free callback is registered, garbage collection returns such a buffer to the JerryScript heap free list through jmem_heap_free_block_internal(). Its free-list linking writes the block header into the buffer, which runs past the end of buffers smaller than a free block. Mark externally-supplied buffers with a dedicated flag and skip the internal heap free for them when no free callback is registered. Registered free callbacks are still invoked, and the buffer is still treated as allocated so lazy allocation does not replace the caller's buffer. Fixes #5272 JerryScript-DCO-1.0-Signed-off-by: PGZXB --- jerry-core/api/jerryscript.c | 6 ++++-- jerry-core/ecma/base/ecma-globals.h | 1 + jerry-core/ecma/operations/ecma-arraybuffer-object.c | 7 ++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/jerry-core/api/jerryscript.c b/jerry-core/api/jerryscript.c index d8174b92c0..495533f59c 100644 --- a/jerry-core/api/jerryscript.c +++ b/jerry-core/api/jerryscript.c @@ -5988,7 +5988,8 @@ jerry_arraybuffer_external (uint8_t *buffer_p, /**< the backing store used by th if (buffer_p != NULL) { - arraybuffer_pointer_p->extended_object.u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED; + arraybuffer_pointer_p->extended_object.u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED + | ECMA_ARRAYBUFFER_EXTERNAL; arraybuffer_pointer_p->buffer_p = buffer_p; } } @@ -6076,7 +6077,8 @@ jerry_shared_arraybuffer_external (uint8_t *buffer_p, /**< the backing store use if (buffer_p != NULL) { - shared_arraybuffer_pointer_p->extended_object.u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED; + shared_arraybuffer_pointer_p->extended_object.u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED + | ECMA_ARRAYBUFFER_EXTERNAL; shared_arraybuffer_pointer_p->buffer_p = buffer_p; } } diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 75c70e196b..bbf9a9a862 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -1848,6 +1848,7 @@ typedef enum ECMA_ARRAYBUFFER_HAS_POINTER = (1u << 0), /* ArrayBuffer has a buffer pointer. */ ECMA_ARRAYBUFFER_ALLOCATED = (1u << 1), /* ArrayBuffer memory is allocated */ ECMA_ARRAYBUFFER_DETACHED = (1u << 2), /* ArrayBuffer has been detached */ + ECMA_ARRAYBUFFER_EXTERNAL = (1u << 3), /* ArrayBuffer uses a buffer supplied by the user */ } ecma_arraybuffer_flag_t; /** diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.c b/jerry-core/ecma/operations/ecma-arraybuffer-object.c index 1491e31ec5..b43cea3f7d 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.c +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.c @@ -219,7 +219,12 @@ ecma_arraybuffer_release_buffer (ecma_object_t *arraybuffer_p) /**< ArrayBuffer if (free_callback == NULL) { - jmem_heap_free_block (arraybuffer_pointer_p->buffer_p, arraybuffer_length); + /* Externally supplied buffers are owned by the caller, so they must not be + * returned to the internal heap. */ + if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_EXTERNAL)) + { + jmem_heap_free_block (arraybuffer_pointer_p->buffer_p, arraybuffer_length); + } return; }