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.
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() {
assert(!ctx->write_in_progress_ && "write already in progress");
ctx->write_in_progress_ = true;
+ ctx->Ref();
unsigned int flush = args[0]->Uint32Value();
Bytef *in;
ZCtx::Process,
ZCtx::After);
- ctx->Ref();
-
return ctx->handle_;
}
MakeCallback(ctx->handle_, onerror_sym, ARRAY_SIZE(args), args);
// no hope of rescue.
+ ctx->write_in_progress_ = false;
ctx->Unref();
}