diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 3c4f419aa29470..259e6eeda3e476 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -123,10 +123,13 @@ MaybeLocal ToBufferEndian(Environment* env, MaybeStackBuffer* buf) { void CopySourceBuffer(MaybeStackBuffer* dest, const char* data, - const size_t length, const size_t length_in_chars) { dest->AllocateSufficientStorage(length_in_chars); char* dst = reinterpret_cast(**dest); + // The destination holds length_in_chars UChar units. Copy that many whole + // units and ignore a trailing odd byte; copying the raw byte length would + // write one byte past the buffer when the source length is not even. + const size_t length = length_in_chars * sizeof(UChar); memcpy(dst, data, length); if constexpr (IsBigEndian()) { CHECK(nbytes::SwapBytes16(dst, length)); @@ -199,7 +202,7 @@ MaybeLocal TranscodeFromUcs2(Environment* env, to.set_subst_chars(sub.c_str()); const size_t length_in_chars = source_length / sizeof(UChar); - CopySourceBuffer(&sourcebuf, source, source_length, length_in_chars); + CopySourceBuffer(&sourcebuf, source, length_in_chars); MaybeStackBuffer destbuf(length_in_chars); const uint32_t len = ucnv_fromUChars(to.conv(), *destbuf, length_in_chars, *sourcebuf, length_in_chars, status); diff --git a/test/parallel/test-icu-transcode.js b/test/parallel/test-icu-transcode.js index 875d954b6cab81..6bcab0054c611f 100644 --- a/test/parallel/test-icu-transcode.js +++ b/test/parallel/test-icu-transcode.js @@ -88,3 +88,18 @@ assert.deepStrictEqual( { buffer.transcode(new buffer.Buffer.allocUnsafeSlow(1), 'utf16le', 'ucs2'); } + +// An odd-length ucs2 source must only convert whole 2-byte code units and +// leave the trailing byte untouched, without reading or writing past the +// conversion buffer. Lengths are chosen to exercise both the on-stack and the +// heap-allocated code paths. +for (const len of [2049, 4099]) { + const src = Buffer.alloc(len, 0x61); + const wholeUnits = src.subarray(0, len - 1); + for (const to of ['latin1', 'ascii']) { + assert.deepStrictEqual( + buffer.transcode(src, 'utf16le', to), + buffer.transcode(wholeUnits, 'utf16le', to), + `ucs2->${to} odd length ${len}`); + } +}