Buffer.prototype.toString = function() {
- const length = this.length | 0;
- if (arguments.length === 0)
- return this.utf8Slice(0, length);
- return slowToString.apply(this, arguments);
+ if (arguments.length === 0) {
+ var result = this.utf8Slice(0, this.length);
+ } else {
+ var result = slowToString.apply(this, arguments);
+ }
+ if (result === undefined)
+ throw new Error('toString failed');
+ return result;
};
using v8::Object;
using v8::String;
using v8::Value;
+using v8::MaybeLocal;
template <typename ResourceType, typename TypeName>
class ExternString: public ResourceType {
public:
~ExternString() override {
- delete[] data_;
+ free(const_cast<TypeName*>(data_));
isolate()->AdjustAmountOfExternalAllocatedMemory(-byte_length());
}
if (length == 0)
return scope.Escape(String::Empty(isolate));
- TypeName* new_data = new TypeName[length];
+ TypeName* new_data =
+ static_cast<TypeName*>(malloc(length * sizeof(*new_data)));
+ if (new_data == nullptr) {
+ return Local<String>();
+ }
memcpy(new_data, data, length * sizeof(*new_data));
return scope.Escape(ExternString<ResourceType, TypeName>::New(isolate,
ExternString* h_str = new ExternString<ResourceType, TypeName>(isolate,
data,
length);
- Local<String> str = String::NewExternal(isolate, h_str);
+ MaybeLocal<String> str = String::NewExternal(isolate, h_str);
isolate->AdjustAmountOfExternalAllocatedMemory(h_str->byte_length());
- return scope.Escape(str);
+ if (str.IsEmpty()) {
+ delete h_str;
+ return Local<String>();
+ }
+
+ return scope.Escape(str.ToLocalChecked());
}
inline Isolate* isolate() const { return isolate_; }
case ASCII:
if (contains_non_ascii(buf, buflen)) {
- char* out = new char[buflen];
+ char* out = static_cast<char*>(malloc(buflen));
+ if (out == nullptr) {
+ return Local<String>();
+ }
force_ascii(buf, out, buflen);
if (buflen < EXTERN_APEX) {
val = OneByteString(isolate, out, buflen);
- delete[] out;
+ free(out);
} else {
val = ExternOneByteString::New(isolate, out, buflen);
}
case BASE64: {
size_t dlen = base64_encoded_size(buflen);
- char* dst = new char[dlen];
+ char* dst = static_cast<char*>(malloc(dlen));
+ if (dst == nullptr) {
+ return Local<String>();
+ }
size_t written = base64_encode(buf, buflen, dst, dlen);
CHECK_EQ(written, dlen);
if (dlen < EXTERN_APEX) {
val = OneByteString(isolate, dst, dlen);
- delete[] dst;
+ free(dst);
} else {
val = ExternOneByteString::New(isolate, dst, dlen);
}
case HEX: {
size_t dlen = buflen * 2;
- char* dst = new char[dlen];
+ char* dst = static_cast<char*>(malloc(dlen));
+ if (dst == nullptr) {
+ return Local<String>();
+ }
size_t written = hex_encode(buf, buflen, dst, dlen);
CHECK_EQ(written, dlen);
if (dlen < EXTERN_APEX) {
val = OneByteString(isolate, dst, dlen);
- delete[] dst;
+ free(dst);
} else {
val = ExternOneByteString::New(isolate, dst, dlen);
}
assert.equal(a, b);
assert.equal(b, c);
})();
+
+// v8 fails silently if string length > v8::String::kMaxLength
+(function() {
+ // v8::String::kMaxLength defined in v8.h
+ const kStringMaxLength = process.binding('buffer').kStringMaxLength;
+
+ assert.throws(function() {
+ new Buffer(kStringMaxLength + 1).toString();
+ }, /toString failed|Buffer allocation failed/);
+
+ try {
+ new Buffer(kStringMaxLength * 4);
+ } catch(e) {
+ assert.equal(e.message, 'Buffer allocation failed - process out of memory');
+ console.log(
+ '1..0 # Skipped: intensive toString tests due to memory confinements');
+ return;
+ }
+
+ assert.throws(function() {
+ new Buffer(kStringMaxLength + 1).toString('ascii');
+ }, /toString failed/);
+
+ assert.throws(function() {
+ new Buffer(kStringMaxLength + 1).toString('utf8');
+ }, /toString failed/);
+
+ assert.throws(function() {
+ new Buffer(kStringMaxLength * 2 + 2).toString('utf16le');
+ }, /toString failed/);
+
+ assert.throws(function() {
+ new Buffer(kStringMaxLength + 1).toString('binary');
+ }, /toString failed/);
+
+ assert.throws(function() {
+ new Buffer(kStringMaxLength + 1).toString('base64');
+ }, /toString failed/);
+
+ assert.throws(function() {
+ new Buffer(kStringMaxLength + 1).toString('hex');
+ }, /toString failed/);
+
+ var maxString = new Buffer(kStringMaxLength).toString();
+ assert.equal(maxString.length, kStringMaxLength);
+ // Free the memory early instead of at the end of the next assignment
+ maxString = undefined;
+
+ maxString = new Buffer(kStringMaxLength).toString('binary');
+ assert.equal(maxString.length, kStringMaxLength);
+ maxString = undefined;
+
+ maxString =
+ new Buffer(kStringMaxLength + 1).toString('binary', 1);
+ assert.equal(maxString.length, kStringMaxLength);
+ maxString = undefined;
+
+ maxString =
+ new Buffer(kStringMaxLength + 1).toString('binary', 0, kStringMaxLength);
+ assert.equal(maxString.length, kStringMaxLength);
+ maxString = undefined;
+
+ maxString = new Buffer(kStringMaxLength + 2).toString('utf16le');
+ assert.equal(maxString.length, (kStringMaxLength + 2) / 2);
+ maxString = undefined;
+})();