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 util = require('util');
|
||||
var alloc = smalloc.alloc;
|
||||
var truncate = smalloc.truncate;
|
||||
var sliceOnto = smalloc.sliceOnto;
|
||||
var kMaxLength = smalloc.kMaxLength;
|
||||
var internal = {};
|
||||
@ -79,7 +80,13 @@ function Buffer(subject, encoding) {
|
||||
// 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
|
||||
// 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 {
|
||||
if (util.isBuffer(subject))
|
||||
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 {
|
||||
public:
|
||||
explicit RetainedAllocInfo(Handle<Value> wrapper);
|
||||
@ -572,6 +601,7 @@ void Initialize(Handle<Object> exports,
|
||||
|
||||
NODE_SET_METHOD(exports, "alloc", Alloc);
|
||||
NODE_SET_METHOD(exports, "dispose", AllocDispose);
|
||||
NODE_SET_METHOD(exports, "truncate", AllocTruncate);
|
||||
|
||||
NODE_SET_METHOD(exports, "hasExternalData", HasExternalData);
|
||||
|
||||
|
@ -1003,3 +1003,14 @@ assert.throws(function () {
|
||||
assert.throws(function () {
|
||||
new SlowBuffer(smalloc.kMaxLength + 1);
|
||||
}, 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