Skip to content
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

fs: fix memory leak in WriteString #19357

Closed
wants to merge 2 commits into from

Conversation

joyeecheung
Copy link
Member

In the async case, if the buffer was copied instead of being moved
then the buf will not get deleted after the request is done.
This was introduced when the FSReqWrap:: Ownership was removed in 4b9ba9b,
and ReleaseEarly was no longer called upon destruction of FSReqWrap.

Create a custom Init function so we can use the MaybeStackBuffer in
the FSReqBase to copy the string in the async case. The data will
then get destructed when the FSReqBase is destructed.

Fixes: #19356

Before this patch, running valgrind --leak-check=yes ./node --expose_externalize_string test/parallel/test-fs-write.js produces:

==25808== 21 bytes in 3 blocks are definitely lost in loss record 7 of 51
==25808==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25808==    by 0x8238CA: node::fs::WriteString(v8::FunctionCallbackInfo<v8::Value> const&) (in /home/ubuntu/projects/node/out/Release/node)
==25808==    by 0x97873B: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) (in /home/ubuntu/projects/node/out/Release/node)
==25808==    by 0x9CFEA4: v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) (in /home/ubuntu/projects/node/out/Release/node)
==25808==    by 0x9CF5D5: v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) (in /home/ubuntu/projects/node/out/Release/node)
==25808==    by 0x21191EE0427C: ???
==25808==    by 0x21191EE13616: ???
==25808==    by 0x21191EE0BF02: ???
==25808==    by 0x21191EE13616: ???
==25808==    by 0x21191EE13616: ???
==25808==    by 0x21191EE0BF02: ???
==25808==    by 0x21191EE13616: ???

After this patch, this leak is gone.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines

In the async case, if the buffer was copied instead of being moved
then the buf will not get deleted after the request is done.
This was introduced when the FSReqWrap:: Ownership was removed in 4b9ba9b,
and ReleaseEarly was no longer called upon destruction of FSReqWrap.

Create a custom Init function so we can use the MaybeStackBuffer in
the FSReqBase to copy the string in the async case. The data will
then get destructed when the FSReqBase is destructed.

Fixes: nodejs#19356
@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to the fs subsystem / file system. labels Mar 14, 2018
@joyeecheung
Copy link
Member Author

src/node_file.cc Outdated
} else { // write(fd, string, pos, enc, undefined, ctx)
CHECK_EQ(argc, 6);
fs_req_wrap req_wrap;
std::unique_ptr<char[]> delete_on_return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw, this could also very well be a MaybeStackBuffer. It’s more or less what they are there for :)

if (is_async) { // write(fd, string, pos, enc, req)
AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger,
uv_fs_write, fd, &uvbuf, 1, pos);
len = StringBytes::Write(env->isolate(), *stack_buffer, len, args[1], enc);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does StringBytes::Write guarantees null termination? From the test results I guess it does, so there is no need to call SetLengthAndZeroTerminate again after this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does StringBytes::Write guarantees null termination?

I don’t think so … and it actually specifies NO_NULL_TERMINATION for V8?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@addaleax OK, I will just call SetLengthAndZeroTerminate to be safe..

@joyeecheung
Copy link
Member Author

Updated to call SetLengthAndZeroTerminate after StringBytes::Write and use MaybeStackBuffer in the synchronous case per suggestion by @addaleax . PTAL, thanks!

https://ci.nodejs.org/job/node-test-pull-request/13687/

@joyeecheung
Copy link
Member Author

@joyeecheung
Copy link
Member Author

joyeecheung commented Mar 18, 2018

Landed in 897cec4, thanks!

edit: edited by @MylesBorins to fix commit sha

joyeecheung added a commit that referenced this pull request Mar 18, 2018
In the async case, if the buffer was copied instead of being moved
then the buf will not get deleted after the request is done.
This was introduced when the FSReqWrap:: Ownership was
removed in 4b9ba9b, and ReleaseEarly was no longer called upon
destruction of FSReqWrap.

Create a custom Init function so we can use the MaybeStackBuffer in
the FSReqBase to copy the string in the async case. The data will
then get destructed when the FSReqBase is destructed.

Fixes: #19356

PR-URL: #19357
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
@MylesBorins
Copy link
Contributor

Should this be backported to v9.x-staging? If yes please follow the guide and raise a backport PR, if not let me know or add the dont-land-on label.

@joyeecheung
Copy link
Member Author

@MylesBorins This fixed a leak introduced in #18112 so depends on whether that will be backported.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to the fs subsystem / file system.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants