diff --git a/Cargo.lock b/Cargo.lock index c5b365a24c51be..c038cc6cba69b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,6 +205,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/core/BUILD.gn b/core/BUILD.gn index 3b43e903744608..93a0ff2888697e 100644 --- a/core/BUILD.gn +++ b/core/BUILD.gn @@ -23,6 +23,7 @@ main_extern_rlib = [ "libc", "serde_json", "log", + "tokio_signal" ] rust_rlib("deno") { diff --git a/core/Cargo.toml b/core/Cargo.toml index 7e1c7ff4d9edff..770c344b31045f 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,6 +19,7 @@ lazy_static = "1.3.0" libc = "0.2.55" log = "0.4.6" serde_json = "1.0.39" +tokio-signal = "0.2.7" [[example]] name = "deno_core_http_bench" diff --git a/core/isolate.rs b/core/isolate.rs index b51b7fe47fe5f7..a747325fd346e5 100644 --- a/core/isolate.rs +++ b/core/isolate.rs @@ -19,6 +19,7 @@ use futures::task; use futures::Async::*; use futures::Future; use futures::Poll; +use tokio_signal; use libc::c_void; use std::ffi::CStr; use std::ffi::CString; @@ -27,6 +28,8 @@ use std::sync::{Arc, Mutex, Once, ONCE_INIT}; pub type Buf = Box<[u8]>; +pub type Custom = futures::FlattenStream + std::marker::Send>, Error=std::io::Error> + std::marker::Send>>; + pub type OpAsyncFuture = Box + Send>; pub enum Op { @@ -86,6 +89,7 @@ pub struct Isolate { shared: SharedQueue, pending_ops: FuturesUnordered, have_unpolled_ops: bool, + ctrl_c: Custom, } unsafe impl Send for Isolate {} @@ -138,6 +142,7 @@ impl Isolate { }; let libdeno_isolate = unsafe { libdeno::deno_new(libdeno_config) }; + let ctrl_c = tokio_signal::ctrl_c().flatten_stream(); let mut core_isolate = Self { libdeno_isolate, @@ -147,6 +152,7 @@ impl Isolate { needs_init, pending_ops: FuturesUnordered::new(), have_unpolled_ops: false, + ctrl_c, }; // If we want to use execute this has to happen here sadly. @@ -274,7 +280,11 @@ impl Isolate { libdeno::deno_check_promise_errors(self.libdeno_isolate); } } - + fn throw_error(&self) { + unsafe { + libdeno::deno_print_stack_trace(self.libdeno_isolate); + } + } fn respond(&mut self, maybe_buf: Option<&[u8]>) -> Result<(), JSError> { let buf = match maybe_buf { None => deno_buf::empty(), @@ -464,7 +474,10 @@ impl Future for Isolate { // The other side should have shifted off all the messages. assert_eq!(self.shared.size(), 0); } - + match self.ctrl_c.poll() { + Ok(Ready(_)) => self.throw_error(), + _ => println!("..."), + } if overflow_response.is_some() { let buf = overflow_response.take().unwrap(); self.respond(Some(&buf))?; diff --git a/core/libdeno.rs b/core/libdeno.rs index 046caaef655985..ee1faca85feae8 100644 --- a/core/libdeno.rs +++ b/core/libdeno.rs @@ -261,6 +261,7 @@ extern "C" { js_source: *const c_char, ); pub fn deno_terminate_execution(i: *const isolate); + pub fn deno_print_stack_trace(i: *const isolate); // Modules @@ -296,4 +297,5 @@ extern "C" { #[allow(dead_code)] pub fn deno_snapshot_delete(s: &mut deno_snapshot); + } diff --git a/core/libdeno/api.cc b/core/libdeno/api.cc index bcdf7131b75bc6..d10b02616f9794 100644 --- a/core/libdeno/api.cc +++ b/core/libdeno/api.cc @@ -243,4 +243,11 @@ void deno_terminate_execution(Deno* d_) { deno::DenoIsolate* d = reinterpret_cast(d_); d->isolate_->TerminateExecution(); } + +void deno_print_stack_trace(Deno * d_){ + deno::DenoIsolate* d = reinterpret_cast(d_); + auto* isolate = d->isolate_; + CHECK_NOT_NULL(isolate); + deno::ThrowInvalidArgument(isolate); +} } diff --git a/core/libdeno/binding.cc b/core/libdeno/binding.cc index 4aeb6003afcd3f..90a7b20ce5922b 100644 --- a/core/libdeno/binding.cc +++ b/core/libdeno/binding.cc @@ -96,9 +96,11 @@ void PromiseRejectCallback(v8::PromiseRejectMessage promise_reject_message) { } void Print(const v8::FunctionCallbackInfo& args) { - CHECK_GE(args.Length(), 1); - CHECK_LE(args.Length(), 3); auto* isolate = args.GetIsolate(); + int argsLen = args.Length(); + if (argsLen < 1 || argsLen > 2) { + ThrowInvalidArgument(isolate); + } DenoIsolate* d = DenoIsolate::FromIsolate(isolate); auto context = d->context_.Get(d->isolate_); v8::HandleScope handle_scope(isolate); @@ -220,7 +222,7 @@ void Send(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); DenoIsolate* d = DenoIsolate::FromIsolate(isolate); DCHECK_EQ(d->isolate_, isolate); - + v8::HandleScope handle_scope(isolate); deno_buf control = {nullptr, 0}; @@ -375,7 +377,11 @@ void EvalContext(const v8::FunctionCallbackInfo& args) { auto context = d->context_.Get(isolate); v8::Context::Scope context_scope(context); - CHECK(args[0]->IsString()); + if (!(args[0]->IsString())) { + ThrowInvalidArgument(isolate); + return; + } + auto source = args[0].As(); auto output = v8::Array::New(isolate, 2); diff --git a/core/libdeno/exceptions.cc b/core/libdeno/exceptions.cc index 85f0ca340886be..8f5779acdcad2d 100644 --- a/core/libdeno/exceptions.cc +++ b/core/libdeno/exceptions.cc @@ -214,4 +214,9 @@ void HandleExceptionMessage(v8::Local context, CHECK_NOT_NULL(d); d->last_exception_ = json_str; } + +void ThrowInvalidArgument(v8::Isolate* isolate) { + isolate->ThrowException(v8::Exception::TypeError(v8_str("Invalid Argument"))); +} + } // namespace deno diff --git a/core/libdeno/exceptions.h b/core/libdeno/exceptions.h index e07ff183a1a07e..413bcb7ef6119d 100644 --- a/core/libdeno/exceptions.h +++ b/core/libdeno/exceptions.h @@ -18,6 +18,8 @@ void HandleException(v8::Local context, void HandleExceptionMessage(v8::Local context, v8::Local message); + +void ThrowInvalidArgument(v8::Isolate* isolate); } // namespace deno #endif // EXCEPTIONS_H_ diff --git a/core/libdeno/libdeno_test.cc b/core/libdeno/libdeno_test.cc index e09a973b21e4c4..485c95bff25623 100644 --- a/core/libdeno/libdeno_test.cc +++ b/core/libdeno/libdeno_test.cc @@ -235,6 +235,20 @@ TEST(LibDenoTest, LibDenoEvalContextError) { deno_delete(d); } +TEST(LibDenoTest, LibDenoEvalContextInvalidArgument) { + Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr}); + deno_execute(d, nullptr, "a.js", "LibDenoEvalContextInvalidArgument();"); + EXPECT_EQ(nullptr, deno_last_exception(d)); + deno_delete(d); +} + +TEST(LibDenoTest, LibDenoPrintInvalidArgument) { + Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr}); + deno_execute(d, nullptr, "a.js", "LibDenoPrintInvalidArgument();"); + EXPECT_EQ(nullptr, deno_last_exception(d)); + deno_delete(d); +} + TEST(LibDenoTest, SharedAtomics) { int32_t s[] = {0, 1, 2}; deno_buf shared = {reinterpret_cast(s), sizeof s}; diff --git a/core/libdeno/libdeno_test.js b/core/libdeno/libdeno_test.js index 156af1e471c6f6..17a6343cfc2f28 100644 --- a/core/libdeno/libdeno_test.js +++ b/core/libdeno/libdeno_test.js @@ -195,3 +195,27 @@ global.LibDenoEvalContextError = () => { assert(!errInfo5.isCompileError); // is NOT a compilation error! (just eval) assert(errInfo5.thrown.message === "Unexpected end of input"); }; + +global.LibDenoEvalContextInvalidArgument = () => { + try { + Deno.core.evalContext(); + } catch (e) { + assert(e instanceof TypeError); + assert(e.message === "Invalid Argument"); + } +}; + +global.LibDenoPrintInvalidArgument = () => { + try { + Deno.core.print(); + } catch (e) { + assert(e instanceof TypeError); + assert(e.message === "Invalid Argument"); + } + try { + Deno.core.print(2, 3, 4); + } catch (e) { + assert(e instanceof TypeError); + assert(e.message === "Invalid Argument"); + } +};