diff options
author | Ruben Bridgewater <ruben@bridgewater.de> | 2018-01-30 17:21:28 +0100 |
---|---|---|
committer | Ruben Bridgewater <ruben@bridgewater.de> | 2018-03-02 19:23:57 +0000 |
commit | 1411b30f4646878fc3ff452c3d97a240c0d8b807 (patch) | |
tree | 9f6111146f86c5288b08f23dfab0b8b39a41c432 /lib/buffer.js | |
parent | 069dd10ca2258a27f3cba2db688ce4b97b624241 (diff) | |
download | android-node-v8-1411b30f4646878fc3ff452c3d97a240c0d8b807.tar.gz android-node-v8-1411b30f4646878fc3ff452c3d97a240c0d8b807.tar.bz2 android-node-v8-1411b30f4646878fc3ff452c3d97a240c0d8b807.zip |
buffer: move c++ float functions to js
This ports the Buffer#write(Double|Float)(B|L)E functions to JS.
This fixes a security issue concerning type confusion and fixes
another possible crash in combination with `noAssert`.
In addition to that it will also significantly improve the write
performance.
Fixes: https://github.com/nodejs/node/issues/12179
Fixes: https://github.com/nodejs/node/issues/8724
PR-URL: https://github.com/nodejs/node/pull/18395
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'lib/buffer.js')
-rw-r--r-- | lib/buffer.js | 108 |
1 files changed, 74 insertions, 34 deletions
diff --git a/lib/buffer.js b/lib/buffer.js index 0aa9e2001b..f36bd76acd 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -34,10 +34,6 @@ const { swap16: _swap16, swap32: _swap32, swap64: _swap64, - writeDoubleBE: _writeDoubleBE, - writeDoubleLE: _writeDoubleLE, - writeFloatBE: _writeFloatBE, - writeFloatLE: _writeFloatLE, kMaxLength, kStringMaxLength } = process.binding('buffer'); @@ -85,6 +81,12 @@ const constants = Object.defineProperties({}, { } }); +// Temporary buffers to convert numbers. +const float32Array = new Float32Array(1); +const uInt8Float32Array = new Uint8Array(float32Array.buffer); +const float64Array = new Float64Array(1); +const uInt8Float64Array = new Uint8Array(float64Array.buffer); + Buffer.poolSize = 8 * 1024; var poolSize, poolOffset, allocPool; @@ -1297,12 +1299,16 @@ Buffer.prototype.readFloatLE = function(offset, noAssert) { return toFloat(this.readUInt32LE(offset, noAssert)); }; +function checkOOB(buffer, offset, ext) { + if (offset + ext > buffer.length) + throw new errors.RangeError('ERR_INDEX_OUT_OF_RANGE'); +} + function checkInt(buffer, value, offset, ext, max, min) { if (value > max || value < min) throw new errors.RangeError('ERR_INVALID_OPT_VALUE', 'value', value); - if (offset + ext > buffer.length) - throw new errors.RangeError('ERR_INDEX_OUT_OF_RANGE'); + checkOOB(buffer, offset, ext); } @@ -1520,49 +1526,83 @@ Buffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) { return offset + 4; }; - -Buffer.prototype.writeFloatLE = function writeFloatLE(val, offset, noAssert) { +function writeDoubleForwards(val, offset, noAssert) { val = +val; offset = offset >>> 0; if (!noAssert) - _writeFloatLE(this, val, offset); - else - _writeFloatLE(this, val, offset, true); - return offset + 4; -}; - + checkOOB(this, offset, 8); + + float64Array[0] = val; + this[offset++] = uInt8Float64Array[0]; + this[offset++] = uInt8Float64Array[1]; + this[offset++] = uInt8Float64Array[2]; + this[offset++] = uInt8Float64Array[3]; + this[offset++] = uInt8Float64Array[4]; + this[offset++] = uInt8Float64Array[5]; + this[offset++] = uInt8Float64Array[6]; + this[offset++] = uInt8Float64Array[7]; + return offset; +} -Buffer.prototype.writeFloatBE = function writeFloatBE(val, offset, noAssert) { +function writeDoubleBackwards(val, offset, noAssert) { val = +val; offset = offset >>> 0; if (!noAssert) - _writeFloatBE(this, val, offset); - else - _writeFloatBE(this, val, offset, true); - return offset + 4; -}; - + checkOOB(this, offset, 8); + + float64Array[0] = val; + this[offset++] = uInt8Float64Array[7]; + this[offset++] = uInt8Float64Array[6]; + this[offset++] = uInt8Float64Array[5]; + this[offset++] = uInt8Float64Array[4]; + this[offset++] = uInt8Float64Array[3]; + this[offset++] = uInt8Float64Array[2]; + this[offset++] = uInt8Float64Array[1]; + this[offset++] = uInt8Float64Array[0]; + return offset; +} -Buffer.prototype.writeDoubleLE = function writeDoubleLE(val, offset, noAssert) { +function writeFloatForwards(val, offset, noAssert) { val = +val; offset = offset >>> 0; if (!noAssert) - _writeDoubleLE(this, val, offset); - else - _writeDoubleLE(this, val, offset, true); - return offset + 8; -}; - + checkOOB(this, offset, 4); + + float32Array[0] = val; + this[offset++] = uInt8Float32Array[0]; + this[offset++] = uInt8Float32Array[1]; + this[offset++] = uInt8Float32Array[2]; + this[offset++] = uInt8Float32Array[3]; + return offset; +} -Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) { +function writeFloatBackwards(val, offset, noAssert) { val = +val; offset = offset >>> 0; if (!noAssert) - _writeDoubleBE(this, val, offset); - else - _writeDoubleBE(this, val, offset, true); - return offset + 8; -}; + checkOOB(this, offset, 4); + + float32Array[0] = val; + this[offset++] = uInt8Float32Array[3]; + this[offset++] = uInt8Float32Array[2]; + this[offset++] = uInt8Float32Array[1]; + this[offset++] = uInt8Float32Array[0]; + return offset; +} + +// Check endianness. +float32Array[0] = -1; +if (uInt8Float32Array[3] === 0) { // Big endian. + Buffer.prototype.writeFloatLE = writeFloatBackwards; + Buffer.prototype.writeFloatBE = writeFloatForwards; + Buffer.prototype.writeDoubleLE = writeDoubleBackwards; + Buffer.prototype.writeDoubleBE = writeDoubleForwards; +} else { // Small endian. + Buffer.prototype.writeFloatLE = writeFloatForwards; + Buffer.prototype.writeFloatBE = writeFloatBackwards; + Buffer.prototype.writeDoubleLE = writeDoubleForwards; + Buffer.prototype.writeDoubleBE = writeDoubleBackwards; +} function swap(b, n, m) { const i = b[n]; |