Skip to content

Commit 8e542ea

Browse files
addaleaxtargos
authored andcommitted
zlib: fix memory leak for invalid input
Don’t toggle the weak/strong reference flag from the error handler, that’s too confusing. Instead, always do it in the code that handles the write call. Fixes: #22705 PR-URL: #22713 Reviewed-By: James M Snell <[email protected]>
1 parent 707a37f commit 8e542ea

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

src/node_zlib.cc

+2-4
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ class ZCtx : public AsyncWrap, public ThreadPoolWork {
215215
ctx->write_result_[0] = ctx->strm_.avail_out;
216216
ctx->write_result_[1] = ctx->strm_.avail_in;
217217
ctx->write_in_progress_ = false;
218-
ctx->Unref();
219218
}
219+
ctx->Unref();
220220
return;
221221
}
222222

@@ -364,6 +364,7 @@ class ZCtx : public AsyncWrap, public ThreadPoolWork {
364364
// v8 land!
365365
void AfterThreadPoolWork(int status) override {
366366
AllocScope alloc_scope(this);
367+
OnScopeLeave on_scope_leave([&]() { Unref(); });
367368

368369
write_in_progress_ = false;
369370

@@ -388,7 +389,6 @@ class ZCtx : public AsyncWrap, public ThreadPoolWork {
388389
write_js_callback_);
389390
MakeCallback(cb, 0, nullptr);
390391

391-
Unref();
392392
if (pending_close_)
393393
Close();
394394
}
@@ -410,8 +410,6 @@ class ZCtx : public AsyncWrap, public ThreadPoolWork {
410410
MakeCallback(env()->onerror_string(), arraysize(args), args);
411411

412412
// no hope of rescue.
413-
if (write_in_progress_)
414-
Unref();
415413
write_in_progress_ = false;
416414
if (pending_close_)
417415
Close();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Flags: --expose-gc
2+
'use strict';
3+
const common = require('../common');
4+
const onGC = require('../common/ongc');
5+
const assert = require('assert');
6+
const zlib = require('zlib');
7+
8+
// Checks that, if a zlib context fails with an error, it can still be GC'ed:
9+
// Refs: https://github.com/nodejs/node/issues/22705
10+
11+
const ongc = common.mustCall();
12+
13+
{
14+
const input = Buffer.from('foobar');
15+
const strm = zlib.createInflate();
16+
strm.end(input);
17+
strm.once('error', common.mustCall((err) => {
18+
assert(err);
19+
setImmediate(() => {
20+
global.gc();
21+
// Keep the event loop alive for seeing the async_hooks destroy hook
22+
// we use for GC tracking...
23+
// TODO(addaleax): This should maybe not be necessary?
24+
setImmediate(() => {});
25+
});
26+
}));
27+
onGC(strm, { ongc });
28+
}

0 commit comments

Comments
 (0)