Re: Exception handling

82 views
Skip to first unread message

Philipp Pirozhkov

unread,
Sep 21, 2012, 8:53:54 AM9/21/12
to therub...@googlegroups.com
0.11.0beta8 has a bit different V8::Error, and it allows calling .cause to get the original exception
So the code can be

begin
  begin
    cxt.eval script
  rescue V8::Error => e
    raise e.cause if e.in_ruby?
    # JS specific error handling
   end
rescue SomeCustomError => e
  ...
end


Charles Lowell

unread,
Sep 27, 2012, 9:46:14 AM9/27/12
to therub...@googlegroups.com, javascript-...@googlegroups.com

On Sep 21, 2012, at 12:50 PM, Philipp Pirozhkov wrote:

Hi all,

I would like to describe my concerns on current exception handling below.
How it is handled currently:

def a
  some_method_that_doesnt_exist
end

begin
  cxt['a'] = method :a
  cxt.eval('a')
rescue V8::JSError => e
  if e.in_ruby?
    puts "some ruby error'
  else
    puts "some JS error'
  end
end

Doesn't look so good, right?

First proposal is to split V8::JSError into V8::JSError::Ruby and V8::JSError:JS, thus we can rescue them individually or together, using their common ancestor. (described in https://github.com/cowboyd/therubyracer/issues/200)

My second concern is that there's no sane way to understand what kind of exception we got from ruby:

    require 'v8'

    class Ex < StandardError
    end

    class A
      def c
        puts "raising"
        raise Ex.new "i'm a specific ruby exception"
      end
    end

    c = V8::Context.new
    c['a'] = A.new

    begin
      c.eval('a.c')
    rescue Ex => e
      puts "rescued ex: #{e}"
    rescue V8::JSError => e2
      puts "rescued js: #{e2.inspect}"
      puts e2.in_ruby?
    rescue StandardError => e3
      puts "rescued se: #{e3}"
    end

Guess, which one is rescued?
V8::JSError, and `in_ruby?` is returning true.

If we are passing a wrapper for Net::HTTP to JS code, how do we distinguish between Net::HTTPBadResponse and NoMethodError?
In first case there's an error with networking, and it is recoverable in JS code (try another host, report, log et c.).
The second case is quite different and means there's an error in evaluated JS.
How do we distinguish these two?


Does the new error handling in 0.11.0 address these concerns?



Let's move to my third concern.
JS is known to be a safe sandbox. If JS is trying to do something malicious, we should be notified.

require 'v8'

class MaliciousScript < Exception
end

class A
  def a path
    raise MaliciousScript.new "hey, the script is trying to `rm -rf /`!" if path =~ /\//
  end
end

c = V8::Context.new
c['a'] = A.new

begin
  c.eval 'a.a("my")'
  puts "ok"
  c.eval <<-EOF
try {
  a.a("/")
} catch(e){
  // Hey let's hack those bastards!
}
EOF
  puts "No exception!"
rescue MaliciousScript => e
  puts "rescued maliciuos script: #{e}"
rescue V8::JSError => e2
  puts "rescued js: #{e2.inspect}"
  puts e2.in_ruby?
rescue Exception => e3
  puts "rescued se: #{e3}"
end

Guess what?
ok
No exception!
\

This is definitely NOT good. Thanks for spotting this. 


My proposals here abridged:

1. Split V8::JSError into two, JS specific and Ruby specific
2. Let Ruby catch ruby specific exceptions in a straightforward way

we could mix in modules to the V8::Error instance indicating whether the root cause was in ruby or Javascript

module V8::Error:JS
end
module V8::Error::Ruby
end

that way, you could distinguish (optionally) in your rescue

begin
rescue V8::Error::JavaScriptError => e
  #root cause from JS
rescue V8::Error::RubyError => e
  #root cause was from Ruby
rescue V8::Error
 #don't care which language originated the exception, only that one did occur during JS evaluation
end

3. Restrict JS from catching exceptions it's not intended to catch

This is tichy, need to dig into V8 to see how to do this, but it is critical for sandboxing. This is easier in Rhino, I think.



Please let me know what you think.

PS Just for the case you may have questions regarding what i'm doing. I'm working on a platform which allows users to host and execute JS, and it's Ruby controlled/based. I provide an API to JS, and would like to do so in a controlled way.

I'd love to hear your thoughts on this. If you want to take a stab at time boxing scripts in V8 (like you can already do with Rhino) I'd be happy to help you with it.


PPS Should I crosspost/move this to javascript-and-friends? Not sure if it's common to therubyrhino or execjs.

Since therubyracer and therubyrhino share a common api, I think it is wise. I'll do so.


BR, Phil

Charles Lowell 
thefrontside.net | twitter: @cowboyd | github: cowboyd




Philipp Pirozhkov

unread,
Oct 3, 2012, 5:29:10 PM10/3/12
to therub...@googlegroups.com, javascript-...@googlegroups.com
Does the new error handling in 0.11.0 address these concerns?
It's really really better now. I've finally moved to 0.11 today and that was the only way to handle one kind of errors. I believe this could be done by major refactorings, but with 0.11 it was quick and simple to get the root error as `cause` and set an `if`.


we could mix in modules to the V8::Error instance indicating whether the root cause was in ruby or Javascript
Both subclassing and mixins should work and will look just the same from caller/rescuer's perspective.
 
that way, you could distinguish (optionally) in your rescue

begin
rescue V8::Error::JavaScriptError => e
  #root cause from JS
rescue V8::Error::RubyError => e
  #root cause was from Ruby
rescue V8::Error
 #don't care which language originated the exception, only that one did occur during JS evaluation
end
Yep, looks perfect.


I'd love to hear your thoughts on this. If you want to take a stab at time boxing scripts in V8 (like you can already do with Rhino) I'd be happy to help you with it.
Really appreciated. Will time boxing allow for limiting the execution of the script somehow? I wonder if this is V8 already. Is that something like Firefox's feature "the script processing is taking to long, do you want to stop it?" ? 


BR, Phil 

Charles Lowell

unread,
Oct 3, 2012, 6:15:08 PM10/3/12
to therub...@googlegroups.com, javascript-...@googlegroups.com
On Oct 3, 2012, at 4:29 PM, Philipp Pirozhkov wrote:

Does the new error handling in 0.11.0 address these concerns?
It's really really better now. I've finally moved to 0.11 today and that was the only way to handle one kind of errors. I believe this could be done by major refactorings, but with 0.11 it was quick and simple to get the root error as `cause` and set an `if`.


we could mix in modules to the V8::Error instance indicating whether the root cause was in ruby or Javascript
Both subclassing and mixins should work and will look just the same from caller/rescuer's perspective.
 
that way, you could distinguish (optionally) in your rescue

begin
rescue V8::Error::JavaScriptError => e
  #root cause from JS
rescue V8::Error::RubyError => e
  #root cause was from Ruby
rescue V8::Error
 #don't care which language originated the exception, only that one did occur during JS evaluation
end
Yep, looks perfect.

Karol, is this agreeable then if we use a scheme like this with subclasses and/or modules? 


class V8::JavaScriptError < V8::Error # in_ruby? == false; in_javascript? == true

class V8::RubyError < V8::Error # in_ruby? == true; in_javascript? == false

I'm open to other names for the exceptions.



I'd love to hear your thoughts on this. If you want to take a stab at time boxing scripts in V8 (like you can already do with Rhino) I'd be happy to help you with it.
Really appreciated. Will time boxing allow for limiting the execution of the script somehow? I wonder if this is V8 already. Is that something like Firefox's feature "the script processing is taking to long, do you want to stop it?" ? 


This facility does exist in V8 and it is exposed in 0.11, but only at the very low-level metal. We'd need to implement the Rhino interface for V8 based on this low level. Unfortunately, V8 does not give you instruction level callbacks from the JavaScript VM. Instead you have to have a monitoring thread that pre-empts the javascript execution thread and terminates it forcibly if it exceeds the allotted time box. Would love to get together and work on this. When are you available generally?


cheers,
Charles



BR, Phil 
Reply all
Reply to author
Forward
0 new messages