-
Notifications
You must be signed in to change notification settings - Fork 29.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
src: simplify memory management using node::Malloc()
and friends
#8482
Conversation
9e3309c
to
f04c5ed
Compare
Woooo, internal compiler error on Windows: https://ci.nodejs.org/job/node-compile-windows/4115/label=win-vs2015/console Edit for future reference: This happened with HEAD = f04c5ed4bc1ae3dcb639da469605ae1ea47ca612 One can probably eliminate that by playing with the code a bit, but maybe this is interesting for someone from @nodejs/platform-windows ? |
Also – @joshgav do you want to/should you be added to the platform-windows team? |
@@ -142,8 +142,7 @@ static void ares_poll_close_cb(uv_handle_t* watcher) { | |||
|
|||
/* Allocates and returns a new node_ares_task */ | |||
static node_ares_task* ares_task_create(Environment* env, ares_socket_t sock) { | |||
node_ares_task* task = | |||
static_cast<node_ares_task*>(node::Malloc(sizeof(*task))); | |||
node_ares_task* task = node::Malloc<node_ares_task>(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're welcome to write this as auto task = ...
while you're here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Interesting. For all its faults I've never gotten VS to ICE. |
I'm not getting an ICE locally. Maybe try updating VS on CI? |
4b39181
to
1491d99
Compare
Trying to run a new CI at https://ci.nodejs.org/job/node-test-pull-request/4012/ but it seems to be stuck reading data from Github? |
@@ -204,7 +198,7 @@ void StreamWrap::OnReadImpl(ssize_t nread, | |||
return; | |||
} | |||
|
|||
char* base = static_cast<char*>(node::Realloc(buf->base, nread)); | |||
char* base = node::UncheckedRealloc(buf->base, nread); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make this a checked realloc. It can't really fail because it shrinks but I doubt the extra check hurts.
1491d99
to
f46329c
Compare
T MultiplyWithOverflowCheck(T a, T b) { | ||
T ret = a * b; | ||
if (a != 0) | ||
CHECK_EQ(b, ret / a); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT: No, I got that wrong. The branch is always taken because a == sizeof(T)
and therefore never zero.
LGTM |
@@ -229,30 +229,74 @@ bool StringEqualNoCaseN(const char* a, const char* b, size_t length) { | |||
return true; | |||
} | |||
|
|||
template <typename T> | |||
T MultiplyWithOverflowCheck(T a, T b) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think making this a template is a good idea. It can't be used with signed types since signed overflow is UB, so the check could be optimized out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seishun How strongly do you feel about this? I don’t really care but it might be nice to have a generic utility if one is ever needed again. I can add a static_assert
to check for unsignedness, if you want.
Also, I’m surprised, but your worries are not only theoretical; clang actually would optimize the check away for signed integers… oO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add a static_assert to check for unsignedness, if you want.
That works, but I would personally prefer to have a function that works just with size_t
. That way you can see that it doesn't work with signed values from the signature. Your call, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seishun ¯_(ツ)_/¯ updated with size_t
:)
f46329c
to
d03ff03
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Adds an optional second parameter to `node::Malloc()` and an optional third parameter to `node::Realloc()` giving the size/number of items to be allocated, in the style of `calloc(3)`. Use a proper overflow check using division; the previous `CHECK_GE(n * size, n);` would not detect all cases of overflow (e.g. `size == SIZE_MAX / 2 && n == 3`). PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Pass the desired return type directly to the allocation functions, so that the resulting `static_cast` from `void*` becomes unneccessary and the return type can be use as a reasonable default value for the `size` parameter. PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Provide shortcut `node::CheckedMalloc()` and friends that replace `node::Malloc()` + `CHECK_NE(·, nullptr);` combinations in a few places. PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Call `v8::Isolate::GetCurrent()->LowMemoryNotification()` when an allocation fails to give V8 a chance to clean up and return memory before retrying (and possibly giving up). PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
@addaleax I've set this as do not land... please feel free to change if it should be backported |
depends on #7082 |
Make cctest valgrind-clean again by freeing heap-allocated memory. Overlooked in commit ea94086 ("src: provide allocation + nullptr check shortcuts.") PR-URL: nodejs#9667 Refs: nodejs#8482 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Make cctest valgrind-clean again by freeing heap-allocated memory. Overlooked in commit ea94086 ("src: provide allocation + nullptr check shortcuts.") PR-URL: #9667 Refs: #8482 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Adds an optional second parameter to `node::Malloc()` and an optional third parameter to `node::Realloc()` giving the size/number of items to be allocated, in the style of `calloc(3)`. Use a proper overflow check using division; the previous `CHECK_GE(n * size, n);` would not detect all cases of overflow (e.g. `size == SIZE_MAX / 2 && n == 3`). PR-URL: nodejs#8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Pass the desired return type directly to the allocation functions, so that the resulting `static_cast` from `void*` becomes unneccessary and the return type can be use as a reasonable default value for the `size` parameter. PR-URL: nodejs#8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Provide shortcut `node::CheckedMalloc()` and friends that replace `node::Malloc()` + `CHECK_NE(·, nullptr);` combinations in a few places. PR-URL: nodejs#8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Call `v8::Isolate::GetCurrent()->LowMemoryNotification()` when an allocation fails to give V8 a chance to clean up and return memory before retrying (and possibly giving up). PR-URL: nodejs#8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
v6.x: #16587 Removed the |
Adds an optional second parameter to `node::Malloc()` and an optional third parameter to `node::Realloc()` giving the size/number of items to be allocated, in the style of `calloc(3)`. Use a proper overflow check using division; the previous `CHECK_GE(n * size, n);` would not detect all cases of overflow (e.g. `size == SIZE_MAX / 2 && n == 3`). Backport-PR-URL: #16587 PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Pass the desired return type directly to the allocation functions, so that the resulting `static_cast` from `void*` becomes unneccessary and the return type can be use as a reasonable default value for the `size` parameter. Backport-PR-URL: #16587 PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Provide shortcut `node::CheckedMalloc()` and friends that replace `node::Malloc()` + `CHECK_NE(·, nullptr);` combinations in a few places. Backport-PR-URL: #16587 PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Call `v8::Isolate::GetCurrent()->LowMemoryNotification()` when an allocation fails to give V8 a chance to clean up and return memory before retrying (and possibly giving up). Backport-PR-URL: #16587 PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Checklist
make -j4 test
(UNIX), orvcbuild test nosign
(Windows) passesAffected core subsystem(s)
src
Description of change
size
param tonode::Malloc()
andnode::Realloc()
incalloc(3)
-style and use proper overflow detection.static_cast
s to the desired pointer types.node::Malloc()
+CHECK_NE(·, nullptr)
combinations that often occur together in the codebase.v8::Isolate::GetCurrent()->LowMemoryNotification()
when an allocation fails to give V8 a chance to clean up and return memory before retrying (and possibly giving up).Any of the changes here can be left out but I believe that they all pretty much make sense to have.
CI: https://ci.nodejs.org/job/node-test-commit/4994/CI: https://ci.nodejs.org/job/node-test-commit/4995/CI: https://ci.nodejs.org/job/node-test-commit/4996/CI: https://ci.nodejs.org/job/node-test-commit/4997/CI: https://ci.nodejs.org/job/node-test-commit/5008/CI: https://ci.nodejs.org/job/node-test-commit/5013/CI: https://ci.nodejs.org/job/node-test-commit/5025/