Last active
December 17, 2015 05:08
-
-
Save bjouhier/5555142 to your computer and use it in GitHub Desktop.
Demonstrates crash with V8 generators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function isGenerator(val) { | |
return Object.prototype.toString.call(val) === "[object Generator]"; | |
} | |
var PENDING = {}; | |
function run(fn, args, idx) { | |
var cb = args[idx], | |
g; | |
function resume(err, val) { | |
while (g) { | |
try { | |
val = err ? g. | |
throw (err) : g.send(val); | |
val = val.done ? undefined : val.value; | |
err = null; | |
// if we get PENDING, the current call completed with a pending I/O | |
// resume will be called again when the I/O completes. So just save the context and return here. | |
if (val === PENDING) { | |
return; | |
} | |
// if we get [PENDING, e, r], the current call invoked its callback synchronously | |
// we just loop to send/throw what the callback gave us. | |
if (val && val[0] === PENDING) { | |
err = val[1]; | |
val = val[2]; | |
} | |
// else, if g yielded a value which is not a generator, g is done. | |
// so we unwind it we send val to the parent generator (or through cb if we are at the top) | |
else if (!isGenerator(val)) { | |
//g.close(); | |
g = g.prev; | |
} | |
// else, we got a new generator which means that g called another generator function | |
// the new generator become current and we loop with g.send(undefined) (equiv to g.next()) | |
else { | |
val.prev = g; | |
g = val; | |
val = undefined; | |
} | |
} catch (ex) { | |
// the send/throw call failed. | |
// we unwind the current generator and we rethrow into the parent generator (or through cb if at the top) | |
//g.close(); | |
g = g.prev; | |
err = makeError(ex); | |
val = undefined; | |
} | |
} | |
// we have exhausted the stack of generators. | |
// return the result or error through the callback. | |
try { | |
cb(err, val); | |
} catch (ex) { | |
trap(ex); | |
} | |
} | |
// set resume as the new callback | |
args[idx] = resume; | |
// call fn to get the initial generator | |
g = fn.apply(this, args); | |
// start the resume loop | |
resume(); | |
} | |
function create(fn, idx) { | |
function F() { | |
//if (arguments[idx] == null) return future.call(this, F, arguments, idx); | |
return run.call(this, fn, arguments, idx); | |
}; | |
// Memoize the original function for fast passing later | |
F.gstreamlineFunction = fn; | |
return F; | |
} | |
function invoke(that, fn, args, idx) { | |
// Resolve the function to be called | |
if (typeof fn !== 'function') { | |
if (typeof that === 'function' && that.gstreamlineFunction && fn === 'call') { | |
return that.gstreamlineFunction.apply(args[0], args.slice(1)); | |
} | |
fn = that[fn]; | |
} | |
// If we're waiting on a fstreamline.create function we can just call it directly instead | |
if (fn.gstreamlineFunction) return fn.gstreamlineFunction.apply(that, args); | |
// Set things up so that call returns: | |
// * PENDING if it completes with a pending I/O (and cb will be called later) | |
// * [PENDING, e, r] if the callback is called synchronously. | |
var result = PENDING, | |
sync = true; | |
var cb = args[idx]; | |
args[idx] = function(e, r) { | |
if (sync) { | |
result = [PENDING, e, r]; | |
} else { | |
cb(e, r); | |
} | |
} | |
fn.apply(that, args); | |
sync = false; | |
return result; | |
} | |
function fib(n) { | |
return n <= 1 ? 1 : fib(n - 1) + fib(n - 2); | |
} | |
var bench = create(function *bench(prefix, n, loop, modulo, asyncFn, _) { | |
var fibo_ = create(fibo, 0); | |
var count = 0; | |
function *fibo(_, nn) { | |
if (modulo && count++ % modulo === 0)(yield invoke(null, asyncFn, [_], 0)); | |
if (nn <= 1) yield(1); | |
yield((yield fibo(_, nn - 1)) + (yield fibo(_, nn - 2))); | |
} | |
var expected = fib(n); | |
var t0 = Date.now(); | |
for (var i = 0; i < loop; i++) { | |
var got = (yield fibo(_, n)); | |
if (got !== expected) throw new Error("bench failed: got " + got + ', expected ' + expected); | |
} | |
var tabs = (prefix.length < 7) ? '\t\t' : '\t'; | |
console.log(prefix + ':' + tabs + (Date.now() - t0) + "ms"); | |
yield(count); | |
}, 5); | |
bench("generators", 25, 1, 3, setImmediate, function(err) { | |
if (err) throw err; | |
console.log("BENCH DONE"); | |
}) |
Here is what I get with gdb:
(gdb) run --harmony junk/fiboCrash
Starting program: /usr/local/bin/node --harmony junk/fiboCrash
Reading symbols for shared libraries +++++++...................................................................................................................................... done
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000000000004a1
v8::internal::LinearSearch<(v8::internal::SearchMode)1, v8::internal::DescriptorArray> (array=0x18dc937517e1, name=0x49a, len=1178, valid_entries=7) at objects-inl.h:2154
2154 objects-inl.h: No such file or directory.
in objects-inl.h
(gdb) where
#0 v8::internal::LinearSearch<(v8::internal::SearchMode)1, v8::internal::DescriptorArray> (array=0x18dc937517e1, name=0x49a, len=1178, valid_entries=7) at objects-inl.h:2154
#1 0x00000001002f6993 in v8::internal::Search<(v8::internal::SearchMode)1, v8::internal::DescriptorArray> () at objects-inl.h:2192
#2 0x00000001002f6993 in v8::internal::DescriptorArray::Search () at :2201
#3 0x00000001002f6993 in v8::internal::Map::LookupDescriptor (this=0x3bede4105f19, holder=0x18dc937517c1, name=0x49a, result=0x7fff5fbff430) at objects-inl.h:2154
#4 0x00000001002c3dc1 in v8::internal::PropertyDetails::type () at ../deps/v8/src/objects.cc:3100
#5 v8::internal::LookupResult::IsField () at :299
#6 0x00000001002c3dc1 in v8::internal::JSObject::LocalLookupRealNamedProperty (this=0x18dc937517c1, name=0xffffffff) at ../deps/v8/src/objects.cc:2154
#7 0x00000001002ccaf2 in v8::internal::LookupResult::IsFound () at :5506
#8 0x00000001002ccaf2 in v8::internal::JSReceiver::LocalLookup (this=0x18dc937517c1, name=0x49a) at ../deps/v8/src/objects.cc:2154
#9 0x00000001002c1a50 in v8::internal::LookupResult::IsFound () at :5524
#10 v8::internal::JSReceiver::Lookup () at :5525
#11 0x00000001002c1a50 in v8::internal::Object::Lookup (this=<value temporarily unavailable, due to optimizations>, name=0x49a, result=0x7fff5fbff430) at ../deps/v8/src/objects.cc:2154
#12 0x000000010025de1e in v8::internal::LookupResult::IsInterceptor () at :451
#13 0x000000010025de1e in LookupForRead (lookup=0x7fff5fbff430) at ../deps/v8/src/ic.cc:2154
#14 0x000000010025eefe in v8::internal::LookupResult::IsFound () at :928
#15 0x000000010025eefe in v8::internal::LoadIC::Load (this=0x7fff5fbff518, state=v8::internal::UNINITIALIZED) at ../deps/v8/src/ic.cc:2154
#16 0x0000000100263507 in __RT_impl_LoadIC_Miss [inlined] () at :2169
#17 0x0000000100263507 in v8::internal::LoadIC_Miss () at ../deps/v8/src/ic.cc:2154
#18 0x00003fe0b0f0616e in ?? ()
#19 0x00003fe0b0f16a9f in ?? ()
#20 0x00003fe0b0f71343 in ?? ()
#21 0x00003fe0b0f70dc2 in ?? ()
#22 0x00003fe0b0f77591 in ?? ()
#23 0x00003fe0b0f0c374 in ?? ()
#24 0x00003fe0b0f83588 in ?? ()
#25 0x00003fe0b0f26604 in ?? ()
#26 0x00003fe0b0f077f7 in ?? ()
#27 0x00000001001adffa in Invoke (is_construct=<value temporarily unavailable, due to optimizations>, argc=0, args=0x0, has_pending_exception=0x7fff5fbff8a7) at ../deps/v8/src/execution.cc:119
#28 0x000000010014dc12 in v8::Function::Call (this=0x10204b290, argc=0, argv=0x0) at ../deps/v8/src/api.cc:4044
#29 0x0000000100007309 in node::MakeCallback (argc=0, argv=0x0) at ../src/node.cc:1021
#30 0x0000000100007420 in node::MakeCallback (argc=<value temporarily unavailable, due to optimizations>, argv=<value temporarily unavailable, due to optimizations>) at ../src/node.cc:1057
#31 0x000000010000c1fa in CheckImmediate (handle=<value temporarily unavailable, due to optimizations>, status=<value temporarily unavailable, due to optimizations>) at ../src/node.cc:228
#32 0x000000010012f6e1 in uv__run_check (loop=<value temporarily unavailable, due to optimizations>) at ../deps/uv/src/unix/loop-watcher.c:63
#33 0x000000010012bf03 in uv__run_closing_handles [inlined] () at :315
#34 0x000000010012bf03 in uv_run (loop=0x100737930, mode=<value temporarily unavailable, due to optimizations>) at ../deps/uv/src/unix/core.c:2154
#35 0x000000010000bec1 in node::Start (argc=3, argv=0x100c0ec00) at ../src/node.cc:3167
#36 0x0000000100001574 in start ()
I've filed down the test case: http://code.google.com/p/v8/issues/detail?id=2681
Fixed, and updated my node mirror. Thanks for the report. If you find something else, please use v8's issue tracker; thanks :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This example works ok on my macboook but if I change the 4th parameter from 3 to 1 or 2 in the
bench
call, I get a segmentation fault.