ironm73 / pyv8

Automatically exported from code.google.com/p/pyv8
0 stars 0 forks source link

cannot access stacktrace when catching JSError #113

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?

    ctxt = PyV8.JSContext()     
    ctxt.enter()                
    ctxt.eval("""function f() {
                throw "err";
            }""")
    ctxt.eval("function g() {f();}")

    try:
        ctxt.eval("g();")
    except Exception, e:
        # here, I get the correct error but stackTrace is empty
        print sys.exc_info()[1].stackTrace

What is the expected output? What do you see instead?

I was hoping for a list of tuples here, much like the one returned from 
python's traceback.extract_tb(tracebk), something that gives information about 
each step in the stacktrace -- here, there's no info about what went wrong in 
g(). if I get the full stacktrace as a list I could make my own nice string 
representation of it, and hide the underlying python mechanics from an 
unsuspecting javascript user. right now, the stacktrace property is an empty 
string and sys.exc_info() doesn't help me either.

Original issue reported on code.google.com by jo...@roxendal.com on 29 Nov 2011 at 10:44

GoogleCodeExporter commented 8 years ago
It's a design issue, Google v8 will not generate the stack trace if you throw 
something except a JS error object, because it store the stack trace in the 
error object when it was created.

v8::Local<Value> v8::TryCatch::StackTrace() const {
  ASSERT(isolate_ == i::Isolate::Current());
  if (HasCaught()) {
    i::Object* raw_obj = reinterpret_cast<i::Object*>(exception_);
    if (!raw_obj->IsJSObject()) return v8::Local<Value>();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    i::HandleScope scope(isolate_);
    i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj), isolate_);
    i::Handle<i::String> name = isolate_->factory()->LookupAsciiSymbol("stack");
    if (!obj->HasProperty(*name)) return v8::Local<Value>();
    i::Handle<i::Object> value = i::GetProperty(obj, name);
    if (value.is_null()) return v8::Local<Value>();
    return v8::Utils::ToLocal(scope.CloseAndEscape(value));
  } else {
    return v8::Local<Value>();
  }
}

Original comment by flier...@gmail.com on 1 Dec 2011 at 5:54

GoogleCodeExporter commented 8 years ago
btw: if you want the detail of stack trace, please pass a name argument to the 
eval method

ctxt = PyV8.JSContext()
ctxt.enter()
ctxt.eval("""function f() {
            throw Error("err");
        }""", 'test1')
ctxt.eval("function g() {f();}", 'test2')

try:
    ctxt.eval("g();", 'test3')

and you could got the name and position

Error: err
    at Error (unknown source)
    at f (test1:2:19)
    at g (test2:1:15)
    at test3:1:1

the string format is easy to parse, I have add a JSError.frames property for it

     def testParseStack(self):
        self.assertEquals([
            ('Error', 'unknown source', None, None),
            ('test', 'native', None, None),
            ('<anonymous>', 'test0', 3, 5),
            ('f', 'test1', 2, 19),
            ('g', 'test2', 1, 15),
            (None, 'test3', 1, None),
            (None, 'test3', 1, 1),
        ], JSError.parse_stack("""Error: err
            at Error (unknown source)
            at test (native)
            at new <anonymous> (test0:3:5)
            at f (test1:2:19)
            at g (test2:1:15)
            at test3:1
            at test3:1:1"""))

Original comment by flier...@gmail.com on 1 Dec 2011 at 10:58