diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2013-02-21 23:58:55 +0100 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2013-02-22 00:08:26 +0100 |
commit | ef945219090de0c04884528f4113435499cc8ec3 (patch) | |
tree | 5e01c679206c8f476d7d895edfeb47e300e77969 | |
parent | 9d45b945f7903ea7db8427fe8b9cf08fd8d42ef5 (diff) | |
download | node-new-ef945219090de0c04884528f4113435499cc8ec3.tar.gz |
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.
-rw-r--r-- | src/node_zlib.cc | 21 |
1 files 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<v8::Object> 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(); } |