From ccf1c73a26634be9372748f2b3c408d21c7e3b51 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Mon, 7 Sep 2026 18:37:50 +0200 Subject: [PATCH] buffer: fix unaligned UTF-16LE decoding For odd-length input, the destination only has room for complete code units. Copy those units and ignore the trailing byte. This matches the aligned and big-endian paths. Assisted-by: pi Signed-off-by: Matteo Collina --- src/string_bytes.cc | 4 ++-- test/parallel/test-buffer-tostring.js | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/string_bytes.cc b/src/string_bytes.cc index 6e628b907e66..94b579b6984d 100644 --- a/src/string_bytes.cc +++ b/src/string_bytes.cc @@ -751,8 +751,8 @@ MaybeLocal StringBytes::Encode(Isolate* isolate, } if (reinterpret_cast(buf) % 2 != 0) { return EncodeTwoByteString( - isolate, str_len, [buf, buflen](uint16_t* dst) { - memcpy(dst, buf, buflen); + isolate, str_len, [buf, str_len](uint16_t* dst) { + memcpy(dst, buf, str_len * sizeof(*dst)); }); } return ExternTwoByteString::NewFromCopy( diff --git a/test/parallel/test-buffer-tostring.js b/test/parallel/test-buffer-tostring.js index a3dad0146d75..676d2f85f567 100644 --- a/test/parallel/test-buffer-tostring.js +++ b/test/parallel/test-buffer-tostring.js @@ -9,6 +9,13 @@ for (const encoding of ['utf8', 'utf-8', 'ucs2', 'ucs-2', 'ascii', 'latin1', assert.strictEqual(Buffer.from('foo', encoding).toString(encoding), 'foo'); } +// Ignore an incomplete trailing code unit when decoding unaligned UTF-16LE. +for (const size of [514, 516]) { + const buffer = Buffer.alloc(size, 0x61); + assert.strictEqual(buffer.toString('utf16le', 1), + '\u6161'.repeat((size - 1) >>> 1)); +} + // base64 ['base64', 'BASE64'].forEach((encoding) => { assert.strictEqual(Buffer.from('Zm9v', encoding).toString(encoding), 'Zm9v');