Uh oh!
There was an error while loading. Please reload this page.
buffer: workaround for v8 buffer.toString failure. fixes #4266 - #4394
buffer: workaround for v8 buffer.toString failure. fixes #4266#4394skilledDeveloper wants to merge 11 commits into
Conversation
Original commit message: api: introduce SealHandleScope When debugging Handle leaks in io.js we found it very convenient to be able to Seal some specific (root in our case) scope to prevent Handle allocations in it, and easily find leakage. R=yangguo BUG= Review URL: https://codereview.chromium.org/1079713002 Cr-Commit-Position: refs/heads/master@{nodejs#27766} Should help us identify and fix Handle leaks in core and user-space code. PR-URL: nodejs#3945 Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: James Snell <jasnell@gmail.com>
Helps to find Handle leaks in Debug mode. Ref: a5244d3 "deps: backport 1f8555 from v8's upstream" PR-URL: nodejs#3945 Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: James Snell <jasnell@gmail.com>
The call to node::Environment::GetCurrent(Isolate*) makes the call to v8::Isolate::GetCurrentContext(). Doing so creates a new handle that bubbled to the v8::SealHandleScope(). PR-URL: nodejs#3945 Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: James Snell <jasnell@gmail.com>
test-domain-exit-dispose-again had been written for node v0.10.x, and was using the fact that callbacks scheduled with `process.nextTick` wouldn't run if the domain attached to it was disposed. This is not longer the case, and as a result the test would not catch any regression: it would always pass. This change rewrites that test to check that the current domain is cleared properly when processing the rest of the timers list if a timer's callback throws an error. This makes the test fail without the original fix, and pass with the original fix, as expected. PR: nodejs#3991 PR-URL: nodejs#3991 Reviewed-By: Trevor Norris <trev.norris@gmail.com>
* Include reference to CVE-2015-8027 * Fix "socket may no longer have a socket" reference * Expand on non-existent parser causing the error * Clarify that CVE-2015-3194 affects TLS servers using _client certificate authentication_ PR-URL: nodejs#4154 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Backport the tools/install.py changes from 628a3ab that were missed when 6fb0b92 backported the corresponding changes to the Makefile to build the headers only archive. PR-URL: nodejs#4149 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Johan Bergström <bugs@bergstroem.nu> Reviewed-By: Rod Vagg <rod@vagg.org>
PR nodejs#3890 [1] introduced the variable ALLOW_INSECURE_SERVER_DHPARAM defined in src/node_crypto.cc. However, if nodejs is built without OpenSSL support, the build fails: error: ‘ALLOW_INSECURE_SERVER_DHPARAM’ was not declared in this scope ALLOW_INSECURE_SERVER_DHPARAM = true; Fix this by using the preprocessor macro HAVE_OPENSSL to opt-out the use of ALLOW_INSECURE_SERVER_DHPARAM in non-OpenSSL builds. [1] nodejs#3890 PR-URL: nodejs#4201 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Rod Vagg <rod@vagg.org>
d1ba82a "fixed" test-domain-exit-dispose-again by changing its logic to test that process.domain was cleared properly in case an error was thrown from a timer's callback. However, it became clear when reviewing a recent change that refactors lib/timers.js that it was not quite the intention of the original test. Thus, this change adds the original implementation of test-domain-exit-dispose-again back, with comments that make its implementation easier to understand. It also preserves the changes made by d1ba82a, but it moves them to a new test file named test-timers-reset-process-domain-on-throw.js. PR: nodejs#4278 PR-URL: nodejs#4278 Reviewed-By: James M Snell <jasnell@gmail.com>
Fix node exiting due to an exception being thrown rather than emitting an 'uncaughtException' event on the process object when: 1. no error handler is set on the domain within which an error is thrown 2. an 'uncaughtException' event listener is set on the process Also fix an issue where the process would not abort in the proper function call if an error is thrown within a domain with no error handler and --abort-on-uncaught-exception is used. Fixesnodejs#3607 and nodejs#3653. PR: nodejs#3885 PR-URL: nodejs#3885 Reviewed-By: James M Snell <jasnell@gmail.com>
ofrobots
commented
Dec 29, 2015
@skilledDeveloper Can you update the commit log messages to match the contribution guidelines. Specifically, use subsystem prefix ( |
There was a problem hiding this comment.
This comment is too vague; I'd phrase it as // V8 aborts if we try to allocate a string that is too large. (punctuation intentional.)
Shouldn't NewFromCopy() have this logic as well?
rvagg
commented
Jan 4, 2016
Thanks for this @skilledDeveloper, I think this is your first contribution to core, thanks for taking the time. Please let us know if you need any help sorting out the issues raised by @ofrobots and @bnoordhuis to get this ready for landing. |
There was a problem hiding this comment.
Please use String::kMaxLength instead. More forwards compatible.
There was a problem hiding this comment.
oh wait. missed that this targets v0.12 branch.
There was a problem hiding this comment.
That's right. There is no such thing in v0.12 and kStringMaxLength is not exposed anywhere.
skilledDeveloper
commented
Jan 8, 2016
@rvagg Not a problem at all! p.s. Jsut noticed that one of the commits messages is still more than 50 chars! |
skilledDeveloper
commented
Jan 10, 2016
This PR will fix the issue #4266. |
There was a problem hiding this comment.
Should use an appropriate assert.throws or assert.doesNotThrow here instead of throwing the raw error
There was a problem hiding this comment.
This is how it's done in all other test-stringbytes-external-*.js tests (on master). We're doing a check if the machine has enough memory available, and quitting the test without error if there's not. No assert should be used.
trevnorris
commented
Jan 11, 2016
LGTM. This was my last review to prevent myself from making the same irrelevant comments again. |
rvagg
commented
Jan 12, 2016
Need to squash the commits closer to ~1. Without having the time to dive into the details of this myself, @trevnorris or @ofrobots do either of you have suggestions for commit compaction here? |
skilledDeveloper
commented
Mar 3, 2016
Here's the summary of this PR so far:
|
trevnorris
commented
Mar 3, 2016
@skilledDeveloper Below is a patch that fixes things up. Except for the fact that for some reason throwing from commit 62c5a08157825a5882aec35c5ab58e900464c303
Author: Trevor Norris <trev.norris@gmail.com>
Date: Thu Mar 3 14:29:50 2016 -0700
FIX IT UP
diff --git a/lib/buffer.js b/lib/buffer.js
index 1a9f7ca..31f721f 100644
--- a/lib/buffer.js+++ b/lib/buffer.js@@ -247,8 +247,6 @@ Buffer.byteLength = function(str, enc) {
// toString(encoding, start=0, end=buffer.length)
Buffer.prototype.toString = function(encoding, start, end) {
- var loweredCase = false;-
start = start >>> 0;
end = util.isUndefined(end) || end === Infinity ? this.length : end >>> 0;
@@ -257,29 +255,41 @@ Buffer.prototype.toString = function(encoding, start, end) {
if (end > this.length) end = this.length;
if (end <= start) return '';
+ var ret = getSlice(this, start, end, encoding);+ if (ret === undefined)+ // XXX Throwing from toString causes:+ // FATAL ERROR: invalid array length Allocation failed+ throw new Error('"toString()" failed');+ return ret;+};+++function getSlice(self, start, end, encoding) {+ var loweredCase = false;+
while (true) {
switch (encoding) {
case 'hex':
- return this.hexSlice(start, end);+ return self.hexSlice(start, end);
case 'utf8':
case 'utf-8':
- return this.utf8Slice(start, end);+ return self.utf8Slice(start, end);
case 'ascii':
- return this.asciiSlice(start, end);+ return self.asciiSlice(start, end);
case 'binary':
- return this.binarySlice(start, end);+ return self.binarySlice(start, end);
case 'base64':
- return this.base64Slice(start, end);+ return self.base64Slice(start, end);
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
- return this.ucs2Slice(start, end);+ return self.ucs2Slice(start, end);
default:
if (loweredCase)
@@ -288,7 +298,7 @@ Buffer.prototype.toString = function(encoding, start, end) {
loweredCase = true;
}
}
-};+}
Buffer.prototype.equals = function equals(b) {
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index cd66a8a..8fa1b70 100644
--- a/src/node_buffer.cc+++ b/src/node_buffer.cc@@ -262,8 +262,11 @@ void StringSlice(const FunctionCallbackInfo<Value>& args) {
ARGS_THIS(args.This())
SLICE_START_END(args[0], args[1], obj_length)
- args.GetReturnValue().Set(- StringBytes::Encode(env->isolate(), obj_data + start, length, encoding));+ Local<Value> ret =+ StringBytes::Encode(env->isolate(), obj_data + start, length, encoding);++ if (!ret.IsEmpty())+ args.GetReturnValue().Set(ret);
}
diff --git a/src/string_bytes.cc b/src/string_bytes.cc
index 5805c7c..84c4b4c 100644
--- a/src/string_bytes.cc+++ b/src/string_bytes.cc@@ -733,10 +733,14 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
break;
case UTF8:
- val = String::NewFromUtf8(isolate,- buf,- String::kNormalString,- buflen);+ if (buflen > ExternOneByteString::kMaxLength) {+ val = Local<String>();+ } else {+ val = String::NewFromUtf8(isolate,+ buf,+ String::kNormalString,+ buflen);+ }
break;
case BINARY: |
skilledDeveloper
commented
Mar 3, 2016
@trevnorris That's exactly the fatal error I've been talking about. I don't believe it's caused by throwing though. It seems to be caused by variable assignment: |
trevnorris
commented
Mar 8, 2016
@skilledDeveloper I'm at a lose. This has got to be some sort of v8 bug. How about we just throw from C++ if the returned handle is empty? |
skilledDeveloper
commented
Mar 15, 2016
@trevnorris@bnoordhuis I even tried throwing error first thing in the JS but I got the same error. if(this.length>268435440){console.log("len:",this.length);thrownewError('toString failed');}Here's the result. |
trevnorris
commented
Mar 16, 2016
@skilledDeveloper The following patch may fix that problem. Try this out: diff --git a/src/node.cc b/src/node.cc
index 624865b..c12c993 100644
--- a/src/node.cc+++ b/src/node.cc@@ -177,21 +177,19 @@ ArrayBufferAllocator ArrayBufferAllocator::the_singleton;
void* ArrayBufferAllocator::Allocate(size_t length) {
if (length > kMaxLength)
return NULL;
- char* data = new char[length];- memset(data, 0, length);- return data;+ return calloc(length, 1);
}
void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
if (length > kMaxLength)
return NULL;
- return new char[length];+ return malloc(length);
}
void ArrayBufferAllocator::Free(void* data, size_t length) {
- delete[] static_cast<char*>(data);+ free(data);
}
|
skilledDeveloper
commented
Mar 16, 2016
@trevnorris Did not help. Thanks though. |
skilledDeveloper
commented
Apr 19, 2016
@trevnorris@bnoordhuis@jasnell@ofrobots@thealphanerd@rvagg@targos@ChALkeR
There is not much progress on this PR and we are apparently blocked by a V8 (or some memory management) bug. Shall we close this unsolved? |
jasnell
commented
Apr 19, 2016
Let's leave it open and revisit. |
Trott
commented
Aug 7, 2016
More than three months ago, @jasnell wrote:
Are we at a point where we can make a decision? Seems like the choices are (in order of degree of difficulty):
|
jasnell
commented
Aug 7, 2016
+1 on moving forward with something here. Options 2 or 3 sound best but On Saturday, August 6, 2016, Rich Trott notifications@github.com wrote:
|
* Workaround for Buffer.toString failure caused by exceeding the maximum supported length in V8. * See issue nodejs/node#4266 and PR nodejs/node#4394Fixes#22
rvagg
commented
Dec 20, 2016
not gonna make it now, EOL around the corner for v0.12, thanks for the effort on this anyway! |
jasnell
commented
Dec 22, 2016
@rvagg ... should we go ahead and close? |
MylesBorins
commented
Dec 29, 2016
@jasnell I'm going to close this assuming you did not mean to repoen |
* Workaround for Buffer.toString failure caused by exceeding the maximum supported length in V8. * See issue nodejs/node#4266 and PR nodejs/node#4394Fixes#22
if any ways to possible to get above 265 MB via nodejs. |
targos
commented
Nov 26, 2018
The limit is ~1024 MB from Node 8 if you are on a 64-bit system |
nashid
commented
May 25, 2020
What would be the workaround to mitigate this issue? |
nashid
commented
Jun 1, 2020
even when I give more memory to node i.e. What can be a potential work around? |
addaleax
commented
Jun 1, 2020
@nashid Can you open a new issue at https://github.com/nodejs/help/issues/? Whatever you’re seeing is unrelated to this PR, and commenting on a 4-year-old PR isn’t going to give you any helpful information either. |
A workaround to return
undefinedwhenBuffer.toStringfails because of exceeding the maximum supported length in V8.@bnoordhuis Please review.