fs: align fs.ReadStream buffer pool writes to 8-byte boundary

Prevents alignment issues when creating a typed array from a buffer.

Fixes: https://github.com/nodejs/node/issues/24817

PR-URL: https://github.com/nodejs/node/pull/24838
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
ptaylor 2019-03-31 17:26:06 -07:00 committed by Anna Henningsen
parent caf9d3c1d0
commit b884ceb518
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
2 changed files with 19 additions and 5 deletions

View File

@ -51,6 +51,10 @@ function checkPosition(pos, name) {
} }
} }
function roundUpToMultipleOf8(n) {
return (n + 7) & ~7; // Align to 8 byte boundary.
}
function ReadStream(path, options) { function ReadStream(path, options) {
if (!(this instanceof ReadStream)) if (!(this instanceof ReadStream))
return new ReadStream(path, options); return new ReadStream(path, options);
@ -172,10 +176,18 @@ ReadStream.prototype._read = function(n) {
// Now that we know how much data we have actually read, re-wind the // Now that we know how much data we have actually read, re-wind the
// 'used' field if we can, and otherwise allow the remainder of our // 'used' field if we can, and otherwise allow the remainder of our
// reservation to be used as a new pool later. // reservation to be used as a new pool later.
if (start + toRead === thisPool.used && thisPool === pool) if (start + toRead === thisPool.used && thisPool === pool) {
thisPool.used += bytesRead - toRead; const newUsed = thisPool.used + bytesRead - toRead;
else if (toRead - bytesRead > kMinPoolSpace) thisPool.used = roundUpToMultipleOf8(newUsed);
poolFragments.push(thisPool.slice(start + bytesRead, start + toRead)); } else {
// Round down to the next lowest multiple of 8 to ensure the new pool
// fragment start and end positions are aligned to an 8 byte boundary.
const alignedEnd = (start + toRead) & ~7;
const alignedStart = roundUpToMultipleOf8(start + bytesRead);
if (alignedEnd - alignedStart >= kMinPoolSpace) {
poolFragments.push(thisPool.slice(alignedStart, alignedEnd));
}
}
if (bytesRead > 0) { if (bytesRead > 0) {
this.bytesRead += bytesRead; this.bytesRead += bytesRead;
@ -189,7 +201,8 @@ ReadStream.prototype._read = function(n) {
// Move the pool positions, and internal position for reading. // Move the pool positions, and internal position for reading.
if (this.pos !== undefined) if (this.pos !== undefined)
this.pos += toRead; this.pos += toRead;
pool.used += toRead;
pool.used = roundUpToMultipleOf8(pool.used + toRead);
}; };
ReadStream.prototype._destroy = function(err, cb) { ReadStream.prototype._destroy = function(err, cb) {

View File

@ -55,6 +55,7 @@ const rangeFile = fixtures.path('x.txt');
file.on('data', function(data) { file.on('data', function(data) {
assert.ok(data instanceof Buffer); assert.ok(data instanceof Buffer);
assert.ok(data.byteOffset % 8 === 0);
assert.ok(!paused); assert.ok(!paused);
file.length += data.length; file.length += data.length;