From ef945219090de0c04884528f4113435499cc8ec3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 21 Feb 2013 23:58:55 +0100 Subject: [PATCH] zlib: fix assert on bad input The following test case occasionally triggered an assert because write_in_progress_ didn't get cleared on error: $ cat test.js require('zlib').gunzip('BAM', console.log); setTimeout(gc, 10); $ while true; do node --expose-gc test.js || break; done { [Error: incorrect header check] errno: -3, code: 'Z_DATA_ERROR' } Assertion failed: (!write_in_progress_ && "write in progress"), function Clear, file ../src/node_zlib.cc, line 71. Abort trap: 6 Steps to avoid that: * Initialize all primitive member fields in the constructor. * Clear the write_in_progress_ member field in ZCtx::Error(). * Ref the ZCtx object as soon as write_in_progress_ is set to true. Before this commit, it could get GC'ed in the time between setting the field and the call to ctx->Ref(). Fixes #4783. --- src/node_zlib.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 4a60c875d7..7c7f966cd6 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -59,7 +59,22 @@ void InitZlib(v8::Handle target); class ZCtx : public ObjectWrap { public: - ZCtx(node_zlib_mode mode) : ObjectWrap(), dictionary_(NULL), mode_(mode) {} + ZCtx(node_zlib_mode mode) + : ObjectWrap() + , init_done_(false) + , level_(0) + , windowBits_(0) + , memLevel_(0) + , strategy_(0) + , err_(0) + , dictionary_(NULL) + , dictionary_len_(0) + , flush_(0) + , chunk_size_(0) + , write_in_progress_(false) + , mode_(mode) + { + } ~ZCtx() { @@ -108,6 +123,7 @@ class ZCtx : public ObjectWrap { assert(!ctx->write_in_progress_ && "write already in progress"); ctx->write_in_progress_ = true; + ctx->Ref(); unsigned int flush = args[0]->Uint32Value(); Bytef *in; @@ -155,8 +171,6 @@ class ZCtx : public ObjectWrap { ZCtx::Process, ZCtx::After); - ctx->Ref(); - return ctx->handle_; } @@ -269,6 +283,7 @@ class ZCtx : public ObjectWrap { MakeCallback(ctx->handle_, onerror_sym, ARRAY_SIZE(args), args); // no hope of rescue. + ctx->write_in_progress_ = false; ctx->Unref(); }