Skip to content

Commit 35e0d60

Browse files
committed
buffer: slice on zero length buffer
SlowBuffer(0) passes NULL instead of doing malloc(0). So when someone attempted to SlowBuffer(0).slice(0, 1) an assert would fail in smalloc::SliceOnto. It's important that the check go where it is because the resulting Buffer needs to have external array data allocated. In the case a user tries to slice a zero length Buffer it will also have NULL passed as the data argument. Also fixed where the .parent attribute was set for zero length Buffers. There is no need to track the source of slice if the slice isn't actually occurring.
1 parent 0f8de5e commit 35e0d60

3 files changed

Lines changed: 18 additions & 7 deletions

File tree

lib/buffer.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,12 @@ function Buffer(subject, encoding) {
8383
if (this.length < Buffer.poolSize / 2 && this.length > 0) {
8484
if (this.length > poolSize - poolOffset)
8585
createPool();
86-
this.parent = sliceOnto(allocPool,
87-
this,
88-
poolOffset,
89-
poolOffset + this.length);
86+
var parent = sliceOnto(allocPool,
87+
this,
88+
poolOffset,
89+
poolOffset + this.length);
90+
if (this.length > 0)
91+
this.parent = parent;
9092
poolOffset += this.length;
9193
} else {
9294
alloc(this, this.length);
@@ -373,8 +375,9 @@ Buffer.prototype.slice = function(start, end) {
373375

374376
var buf = new Buffer();
375377
sliceOnto(this, buf, start, end);
376-
buf.parent = this.parent === undefined ? this : this.parent;
377378
buf.length = end - start;
379+
if (buf.length > 0)
380+
buf.parent = this.parent === undefined ? this : this.parent;
378381

379382
return buf;
380383
};

src/smalloc.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,16 @@ void SliceOnto(const FunctionCallbackInfo<Value>& args) {
124124
size_t source_len = source->GetIndexedPropertiesExternalArrayDataLength();
125125
size_t start = args[2]->Uint32Value();
126126
size_t end = args[3]->Uint32Value();
127+
size_t length = end - start;
127128

128129
assert(!dest->HasIndexedPropertiesInExternalArrayData());
129-
assert(source_data != NULL);
130+
assert(source_data != NULL || length == 0);
130131
assert(end <= source_len);
131132
assert(start <= end);
132133

133134
dest->SetIndexedPropertiesToExternalArrayData(source_data + start,
134135
kExternalUnsignedByteArray,
135-
end - start);
136+
length);
136137
args.GetReturnValue().Set(source);
137138
}
138139

test/simple/test-buffer.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,13 @@ assert.throws(function() { buf.readInt8(0); }, RangeError);
947947
assert.equal(buf.slice(-i), s.slice(-i));
948948
assert.equal(buf.slice(0, -i), s.slice(0, -i));
949949
}
950+
// try to slice a zero length Buffer
951+
// see https://github.com/joyent/node/issues/5881
952+
SlowBuffer(0).slice(0, 1);
953+
// make sure a zero length slice doesn't set the .parent attribute
954+
assert.equal(Buffer(5).slice(0,0).parent, undefined);
955+
// and make sure a proper slice does have a parent
956+
assert.ok(typeof Buffer(5).slice(0, 5).parent === 'object');
950957
})();
951958

952959
// Make sure byteLength properly checks for base64 padding

0 commit comments

Comments
 (0)