diff --git a/leveldown.js b/leveldown.js index 43c82dcf..ad4651d5 100644 --- a/leveldown.js +++ b/leveldown.js @@ -88,6 +88,11 @@ LevelDOWN.prototype.getProperty = function (property) { } LevelDOWN.prototype._iterator = function (options) { + if (this.status !== 'open') { + // Prevent segfault + throw new Error('cannot call iterator() before open()') + } + return new Iterator(this, options) } diff --git a/test/segfault-test.js b/test/segfault-test.js new file mode 100644 index 00000000..ec3f0fd4 --- /dev/null +++ b/test/segfault-test.js @@ -0,0 +1,43 @@ +const test = require('tape') +const testCommon = require('./common') + +// Open issue: https://github.com/Level/leveldown/issues/157 +test.skip('close() does not segfault if there is a pending write', function (t) { + t.plan(3) + + const db = testCommon.factory() + + db.open(function (err) { + t.ifError(err, 'no open error') + + // The "sync" option seems to be a reliable way to trigger a segfault, + // but is not necessarily the cause of that segfault. More likely, it + // exposes a race condition that's already there. + db.put('foo', 'bar', { sync: true }, function (err) { + // We never get here, due to segfault. + t.ifError(err, 'no put error') + }) + + db.close(function (err) { + // We never get here, due to segfault. + t.ifError(err, 'no close error') + }) + }) +}) + +// See https://github.com/Level/leveldown/issues/134 +test('iterator() does not segfault if db is not open', function (t) { + t.plan(2) + + const db = testCommon.factory() + + try { + db.iterator() + } catch (err) { + t.is(err.message, 'cannot call iterator() before open()') + } + + db.close(function (err) { + t.ifError(err, 'no close error') + }) +})