使用Buffer.from处理字符串时越界读取是已知Bug吗?
拼接缓冲区时读取到额外变量内容的问题分析
问题现象
拼接缓冲区时,输出文件会包含作用域内其他变量的内容。使用Buffer.from转换字符串时出现该问题,替换为Buffer.alloc则恢复正常:
- 预期输出文件内容:
A a string - 实际输出文件内容:
A <约200字节程序上下文内容> a string<约200字节程序上下文内容>
最小复现代码
import fs = require("fs"); function concatTypedArrays(a: Uint8Array, b: Uint8Array): Uint8Array { const c = new Uint8Array(a.length + b.length); c.set(a, 0); c.set(b, a.length); return c; } function concatBuffers( a: Uint8Array | Uint16Array | Uint32Array, b: Uint8Array | Uint16Array | Uint32Array ): Uint8Array { return concatTypedArrays( new Uint8Array(a.buffer || a), new Uint8Array(b.buffer || b) ); } const test_var = "this is a long string: 6caD764D996ceB0B6217a01C3ec29DDEc760286C97c28FCBFFdF0dc41CD2AE5A0BdcF36a7Cd29cfc99E118Ef0Be71b4Ba4c1dfdE5CeEAaafee3b93ea4eb20ED5ab99bd0aABd2BFd9bdAc1FdA962813D7CD558c9a0AAD4dD81988eaF6c1481bA8AAa731A87AF7DC0B90cB303CBB16122f8778a1c62F38f19Ff599c147c133fC9a9ba0e272de1bA9eD8b6DcC3bD84Ea8d8d0033CdE1d56aa8bcfb4d7dBFd3cF7e354642c026f6EbFb0f1D28Bb6778Ba4CCaaB15eD66fF6Bd428a3cf6C8dD1dBAb3bAbbA3FF7B1ce784473daD21eF45f7a08Eff4FF1Beae9ce4F69DdB1351Bb1d348A7b4aE2F21c9dF3DeAaA2bECF646e34Dbc7F18C3c28fcccAafbA5ACA9C3d8D240adB5C18Df99DcefbEdE1b27C7bd867364abB983eEa7cDC25B401df91ba8A8E776AD0f3a8Faa06bc1ECaF5B0dA0f633f9bf85B24A33c6cAFfF0eEc4BD68B99eBdc8Af258F90ebB049Eb8e9daD3AcbdA47a5Cd2BFFD4d3cbd26BA"; console.log(`test_var: ${test_var}`); let blob = new Uint8Array(0); const test_str = "a string"; blob = concatBuffers(blob, new Uint8Array([0x41, 0x20])); blob = concatBuffers(blob, Buffer.from(test_str)); // blob = concatBuffers(blob, Buffer.alloc(test_str.length, test_str)); fs.writeFileSync("./test_f.bin", blob);
问题根源
这不是Node.js的已知Bug,而是你的concatBuffers函数实现存在问题:
Node.js的Buffer是Uint8Array的子类,为了性能优化会使用内存池机制——Buffer.from创建的实例通常只是共享内存池中某一段区域的视图,它的底层buffer是一个更大的ArrayBuffer,而Buffer自身通过byteOffset和byteLength来限定有效数据范围。
你的concatBuffers函数直接通过new Uint8Array(a.buffer)读取整个底层ArrayBuffer,没有考虑byteOffset和byteLength,导致把内存池中其他变量的内容也一并读取进来,最终写入文件时包含了额外的上下文数据。
而Buffer.alloc会创建独立的、不共享内存池的Buffer实例,它的底层buffer刚好等于自身的有效数据范围,所以不会出现额外内容。
修复方案
修改concatBuffers函数,正确处理TypedArray的有效数据范围:
function concatBuffers( a: Uint8Array | Uint16Array | Uint32Array, b: Uint8Array | Uint16Array | Uint32Array ): Uint8Array { // 提取TypedArray的有效视图,而非整个底层buffer const aUint8 = 'byteOffset' in a ? new Uint8Array(a.buffer, a.byteOffset, a.byteLength) : new Uint8Array(a); const bUint8 = 'byteOffset' in b ? new Uint8Array(b.buffer, b.byteOffset, b.byteLength) : new Uint8Array(b); return concatTypedArrays(aUint8, bUint8); }
所有TypedArray(包括Buffer)都具备byteOffset和byteLength属性,用来标识它们在底层ArrayBuffer中的起始位置和有效长度。通过这两个属性创建新的Uint8Array,就能确保只读取目标数据的有效范围,避免混入额外内容。
内容的提问来源于stack exchange,提问作者Luctins
相关产品推荐
相关产品推荐

