buffer: truncate buffer after string decode
When our estimates for a storage size are higher than the actual length of decoded data, the destination buffer should be truncated. Otherwise `Buffer::Length` will give misleading information to C++ layer. fix #7365 Signed-off-by: Fedor Indutny <fedor@indutny.com>
This commit is contained in:
parent
525fad473b
commit
4c36f3e7e6
@ -23,6 +23,7 @@ var buffer = process.binding('buffer');
|
|||||||
var smalloc = process.binding('smalloc');
|
var smalloc = process.binding('smalloc');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var alloc = smalloc.alloc;
|
var alloc = smalloc.alloc;
|
||||||
|
var truncate = smalloc.truncate;
|
||||||
var sliceOnto = smalloc.sliceOnto;
|
var sliceOnto = smalloc.sliceOnto;
|
||||||
var kMaxLength = smalloc.kMaxLength;
|
var kMaxLength = smalloc.kMaxLength;
|
||||||
var internal = {};
|
var internal = {};
|
||||||
@ -79,7 +80,13 @@ function Buffer(subject, encoding) {
|
|||||||
// In the case of base64 it's possible that the size of the buffer
|
// In the case of base64 it's possible that the size of the buffer
|
||||||
// allocated was slightly too large. In this case we need to rewrite
|
// allocated was slightly too large. In this case we need to rewrite
|
||||||
// the length to the actual length written.
|
// the length to the actual length written.
|
||||||
this.length = this.write(subject, encoding);
|
var len = this.write(subject, encoding);
|
||||||
|
|
||||||
|
// Buffer was truncated after decode, realloc internal ExternalArray
|
||||||
|
if (len !== this.length) {
|
||||||
|
this.length = len;
|
||||||
|
truncate(this, this.length);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (util.isBuffer(subject))
|
if (util.isBuffer(subject))
|
||||||
subject.copy(this, 0, 0, this.length);
|
subject.copy(this, 0, 0, this.length);
|
||||||
|
@ -504,6 +504,35 @@ bool HasExternalData(Environment* env, Local<Object> obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AllocTruncate(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
||||||
|
HandleScope scope(env->isolate());
|
||||||
|
|
||||||
|
Local<Object> obj = args[0].As<Object>();
|
||||||
|
|
||||||
|
// can't perform this check in JS
|
||||||
|
if (!obj->HasIndexedPropertiesInExternalArrayData())
|
||||||
|
return env->ThrowTypeError("object has no external array data");
|
||||||
|
|
||||||
|
char* data = static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
|
||||||
|
enum ExternalArrayType array_type =
|
||||||
|
obj->GetIndexedPropertiesExternalArrayDataType();
|
||||||
|
int length = obj->GetIndexedPropertiesExternalArrayDataLength();
|
||||||
|
|
||||||
|
unsigned int new_len = args[1]->Uint32Value();
|
||||||
|
if (new_len > kMaxLength)
|
||||||
|
return env->ThrowRangeError("truncate length is bigger than kMaxLength");
|
||||||
|
|
||||||
|
if (static_cast<int>(new_len) > length)
|
||||||
|
return env->ThrowRangeError("truncate length is bigger than current one");
|
||||||
|
|
||||||
|
obj->SetIndexedPropertiesToExternalArrayData(data,
|
||||||
|
array_type,
|
||||||
|
static_cast<int>(new_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RetainedAllocInfo: public RetainedObjectInfo {
|
class RetainedAllocInfo: public RetainedObjectInfo {
|
||||||
public:
|
public:
|
||||||
explicit RetainedAllocInfo(Handle<Value> wrapper);
|
explicit RetainedAllocInfo(Handle<Value> wrapper);
|
||||||
@ -572,6 +601,7 @@ void Initialize(Handle<Object> exports,
|
|||||||
|
|
||||||
NODE_SET_METHOD(exports, "alloc", Alloc);
|
NODE_SET_METHOD(exports, "alloc", Alloc);
|
||||||
NODE_SET_METHOD(exports, "dispose", AllocDispose);
|
NODE_SET_METHOD(exports, "dispose", AllocDispose);
|
||||||
|
NODE_SET_METHOD(exports, "truncate", AllocTruncate);
|
||||||
|
|
||||||
NODE_SET_METHOD(exports, "hasExternalData", HasExternalData);
|
NODE_SET_METHOD(exports, "hasExternalData", HasExternalData);
|
||||||
|
|
||||||
|
@ -1003,3 +1003,14 @@ assert.throws(function () {
|
|||||||
assert.throws(function () {
|
assert.throws(function () {
|
||||||
new SlowBuffer(smalloc.kMaxLength + 1);
|
new SlowBuffer(smalloc.kMaxLength + 1);
|
||||||
}, RangeError);
|
}, RangeError);
|
||||||
|
|
||||||
|
// Test truncation after decode
|
||||||
|
var crypto = require('crypto');
|
||||||
|
|
||||||
|
var b1 = new Buffer('YW55=======', 'base64');
|
||||||
|
var b2 = new Buffer('YW55', 'base64');
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
crypto.createHash('sha1').update(b1).digest('hex'),
|
||||||
|
crypto.createHash('sha1').update(b2).digest('hex')
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user