profile
viewpoint

denoland/deno 61466

A secure JavaScript and TypeScript runtime

IBM-Swift/BlueSocket 1136

Socket framework for Swift using the Swift Package Manager. Works on iOS, macOS, and Linux.

IBM-Swift/HeliumLogger 161

A lightweight logging framework for Swift

IBM-Swift/Kitura-net 97

Kitura networking

IBM-Swift/Kitura-redis 82

Swift Redis library

IBM-Swift/Kitura-WebSocket 62

WebSocket support for Kitura

IBM-Swift/Configuration 57

Hierarchical configuration manager for Swift applications

IBM-Swift/Kitura-CouchDB 45

CouchDB adapter for Kitura

IBM-Swift/Kitura-Credentials 41

A pluggable framework for validating user credentials in a Swift server using Kitura

creationix/luvmonkey 39

Spidermonkey shell with libuv bindings built-in.

Pull request review commentdenoland/deno

Ops can take several zero copy buffers (#4786)

 fn send(     Err(_) => &[],   }; -  let zero_copy: Option<ZeroCopyBuf> =-    v8::Local::<v8::ArrayBufferView>::try_from(args.get(2))-      .map(ZeroCopyBuf::new)-      .ok();-   let state_rc = CoreIsolate::state(scope.isolate());   let mut state = state_rc.borrow_mut();   assert!(!state.global_context.is_empty());    // If response is empty then it's either async op or exception was thrown-  let maybe_response = state.dispatch_op(scope, op_id, control, zero_copy);+  let maybe_response = match std::cmp::max(args.length() - 2, 0) {+    0 => state.dispatch_op(scope, op_id, control, &mut []),+    1 => {+      let zero_copy_buf =+        match v8::Local::<v8::ArrayBufferView>::try_from(args.get(2)) {+          Ok(view) => ZeroCopyBuf::new(view),+          Err(err) => {+            let s = format!("invalid argument {}", err);+            let msg = v8::String::new(scope, &s).unwrap();+            scope.isolate().throw_exception(msg.into());+            return;+          }+        };+      state.dispatch_op(scope, op_id, control, &mut [zero_copy_buf])+    }+    cap => {+      // Collect all ArrayBufferView's+      let mut zero_copy_bufs =+        Vec::with_capacity(usize::try_from(cap).unwrap());+      for i in 2..args.length() {+        zero_copy_bufs.push(+          match v8::Local::<v8::ArrayBufferView>::try_from(args.get(i)) {+            Ok(view) => ZeroCopyBuf::new(view),+            Err(err) => {+              let s = format!("invalid argument {} at {}", err, i - 2);+              let msg = v8::String::new(scope, &s).unwrap();+              scope.isolate().throw_exception(msg.into());+              return;+            }+          },+        );+      }+      state.dispatch_op(scope, op_id, control, &mut zero_copy_bufs)+    }+  };

I do think that it is a bit more efficient than pushing to a vector in a loop. However I'd be surprised if multi-buffer ops turn out to be a performance critical path.

SyrupThinker

comment created time in 4 hours

Pull request review commentdenoland/deno

Ops can take several zero copy buffers (#4786)

 fn send(     Err(_) => &[],   }; -  let zero_copy: Option<ZeroCopyBuf> =-    v8::Local::<v8::ArrayBufferView>::try_from(args.get(2))-      .map(ZeroCopyBuf::new)-      .ok();-   let state_rc = CoreIsolate::state(scope.isolate());   let mut state = state_rc.borrow_mut();   assert!(!state.global_context.is_empty());    // If response is empty then it's either async op or exception was thrown-  let maybe_response = state.dispatch_op(scope, op_id, control, zero_copy);+  let maybe_response = match std::cmp::max(args.length() - 2, 0) {+    0 => state.dispatch_op(scope, op_id, control, &mut []),+    1 => {+      let zero_copy_buf =+        match v8::Local::<v8::ArrayBufferView>::try_from(args.get(2)) {+          Ok(view) => ZeroCopyBuf::new(view),+          Err(err) => {+            let s = format!("invalid argument {}", err);+            let msg = v8::String::new(scope, &s).unwrap();+            scope.isolate().throw_exception(msg.into());+            return;+          }+        };+      state.dispatch_op(scope, op_id, control, &mut [zero_copy_buf])+    }+    cap => {+      // Collect all ArrayBufferView's+      let mut zero_copy_bufs =+        Vec::with_capacity(usize::try_from(cap).unwrap());+      for i in 2..args.length() {+        zero_copy_bufs.push(+          match v8::Local::<v8::ArrayBufferView>::try_from(args.get(i)) {+            Ok(view) => ZeroCopyBuf::new(view),+            Err(err) => {+              let s = format!("invalid argument {} at {}", err, i - 2);+              let msg = v8::String::new(scope, &s).unwrap();+              scope.isolate().throw_exception(msg.into());+              return;+            }+          },+        );+      }+      state.dispatch_op(scope, op_id, control, &mut zero_copy_bufs)+    }+  };

Not so obvious indeed. This is what I could think of:

  let mut buf_iter = (2..args.length()).map(|i| {
    v8::Local::<v8::ArrayBufferView>::try_from(args.get(i))
      .map(ZeroCopyBuf::new)
      .map_err(|err| {
        let msg = format!("Invalid argument at position {}: {}", i, err);
        v8::String::new(scope, &msg).unwrap()
      })
  });
  let mut buf_one: ZeroCopyBuf; // Initialized only when there is one buffer.
  let mut buf_vec: Vec<ZeroCopyBuf>; // Initialized only when there is more than one buffer.
  let buf_iter_result = match buf_iter.len() {
    0 => Ok(&mut [][..]),
    1 => match buf_iter.next().unwrap() {
      Ok(b) => {
        buf_one = b;
        Ok(std::slice::from_mut(&mut buf_one))
      }
      Err(e) => Err(e),
    },
    _ => match buf_iter.collect::<Result<Vec<_>, _>>() {
      Ok(v) => {
        buf_vec = v;
        Ok(&mut buf_vec[..])
      }
      Err(e) => Err(e),
    },
  };
  let maybe_response = match buf_iter_result {
    Ok(mut bufs) => state.dispatch_op(scope, op_id, control, &mut bufs),
    Err(msg) => {
      scope.isolate().throw_exception(msg.into());
      return;
    }
  };
SyrupThinker

comment created time in 4 hours

pull request commentdenoland/rusty_v8

[WIP] Add ICU support in embedded v8.

We'll have to find a solution to make the crate stay under 10 MB (the limit imposed by crates.io). ICU data might have to live in a separate crate or get downloaded through some other means.

kishiguro

comment created time in 5 hours

push eventpiscisaureus/v8rs

Bert Belder

commit sha 5e5f27f9c7c4a70f541945eecb1fe82830fb6d16

Hmm there's some work to do... :(

view details

push time in 5 hours

push eventpiscisaureus/v8rs

Bert Belder

commit sha aed1d242406220a94c1029264cc13f19203f1cc8

Almost done but.... :/

view details

push time in 10 hours

push eventpiscisaureus/v8rs

Bert Belder

commit sha 8deb6789c088ac8de6643749826478814535e029

Almost done but.... :/

view details

push time in 11 hours

push eventpiscisaureus/v8rs

Bert Belder

commit sha e8c0004891a96b26b3db6d23339e16789687bac0

#%*&^W#^$ effing dropck again

view details

push time in 14 hours

pull request commentdenoland/deno

Ops can take several zero copy buffers (#4786)

This makes the interface a lot more complicated. ZeroCopyBuf is backed by SharedRef, couldn't ZeroCopyBuf implement Clone (internally incrementing the reference count) so the user just clone's it to extend its lifetime?

Yes, that's definitely possible. I think al it needs is #[derive(Clone)]. Cloning a SharedRef is not entirely free but I think it's cheap enough.

SyrupThinker

comment created time in 14 hours

pull request commentdenoland/deno

Ops can take several zero copy buffers (#4786)

I think it'd need to be a &mut &mut [ZeroCopySlice] for that to work. I don't see how it would make sense with &mut [ZeroCopySlice].

I think the problem is that &mut [ZeroCopySlice] is unsized, therefore it cannot be used with take(). &mut &mut [ZeroCopySlice] is possible but it'd be very impractical to use if you are actually dealing with a variable number of buffers -- it wouldn't be possible to create Vec<ZeroCopyBuf> and get a &mut &mut ZeroCopyBuf out of that.

So maybe we add some sort of wrapper type, e.g. BufList.

I wrote a quick prototype:

use std::convert::From;
use std::convert::TryFrom;
use std::error::Error;
use std::fmt;
use std::iter::once;
use std::iter::IntoIterator;

pub struct ZeroCopyBuf {
    _private: (),
}

impl ZeroCopyBuf {
    pub fn mock() -> Self {
        Self { _private: () }
    }
}

pub enum BufList {
    None,
    One(ZeroCopyBuf),
    // Maybe add variant 'Two' if that ends up being used a lot.
    Any(Vec<ZeroCopyBuf>),
}

impl BufList {
    pub fn len(&self) -> usize {
        match self {
            BufList::None => 0,
            BufList::One(_) => 1,
            BufList::Any(l) => l.len(),
        }
    }
}

impl Default for BufList {
    fn default() -> Self {
        Self::None
    }
}

impl From<ZeroCopyBuf> for BufList {
    fn from(buf: ZeroCopyBuf) -> Self {
        Self::One(buf)
    }
}

impl<I: IntoIterator<Item = ZeroCopyBuf>> From<I> for BufList {
    fn from(iter: I) -> Self {
        let mut iter = iter.into_iter();
        if let Some(b0) = iter.next() {
            if let Some(b1) = iter.next() {
                Self::Any(once(b0).chain(once(b1)).chain(iter).collect())
            } else {
                Self::One(b0)
            }
        } else {
            Self::None
        }
    }
}

impl TryFrom<BufList> for () {
    type Error = BufCountError;
    fn try_from(list: BufList) -> Result<Self, Self::Error> {
        match list {
            BufList::None => Ok(()),
            BufList::Any(v) if v.len() == 0 => Ok(()),
            _ => Err(BufCountError::new(list, "0")),
        }
    }
}

impl TryFrom<BufList> for ZeroCopyBuf {
    type Error = BufCountError;
    fn try_from(list: BufList) -> Result<Self, Self::Error> {
        match list {
            BufList::One(b) => Ok(b),
            BufList::Any(v) if v.len() == 1 => Ok(v.into_iter().next().unwrap()),
            _ => Err(BufCountError::new(list, "1")),
        }
    }
}

impl TryFrom<BufList> for Option<ZeroCopyBuf> {
    type Error = BufCountError;
    fn try_from(list: BufList) -> Result<Self, Self::Error> {
        match list {
            BufList::None => Ok(None),
            BufList::One(b) => Ok(Some(b)),
            BufList::Any(v) if v.len() <= 1 => Ok(v.into_iter().next()),
            _ => Err(BufCountError::new(list, "0 or 1")),
        }
    }
}

impl From<BufList> for Vec<ZeroCopyBuf> {
    fn from(list: BufList) -> Self {
        match list {
            BufList::None => vec![],
            BufList::One(b) => vec![b],
            BufList::Any(v) => v,
        }
    }
}

pub struct BufCountError {
    list: BufList,
    expected_len: &'static str,
}
impl BufCountError {
    fn new(list: BufList, expected_len: &'static str) -> Self {
        Self { list, expected_len }
    }
}
impl fmt::Debug for BufCountError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(formatter, "{}", self)
    }
}
impl fmt::Display for BufCountError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            formatter,
            "Incorrect number of buffers: expected {}, but got {}.",
            self.list.len(),
            self.expected_len
        )
    }
}
impl Error for BufCountError {}

#[cfg(test)]
mod test {
    use super::*;
    use std::convert::TryInto;
    use std::iter::repeat_with;

    fn zero_buf_op(bufs: BufList) -> Result<(), BufCountError> {
        let _: () = bufs.try_into()?;
        Ok(())
    }

    fn one_buf_op(bufs: BufList) -> Result<(), BufCountError> {
        let _: ZeroCopyBuf = bufs.try_into()?;
        Ok(())
    }

    fn maybe_buf_op(bufs: BufList) -> Result<(), BufCountError> {
        let _: Option<ZeroCopyBuf> = bufs.try_into()?;
        Ok(())
    }

    fn multi_buf_op(bufs: BufList) {
        let _: Vec<ZeroCopyBuf> = bufs.into();
    }

    #[test]
    fn test_buf_list_ok() {
        let none_buf = Option::<ZeroCopyBuf>::None;
        let some_buf = Some(ZeroCopyBuf::mock());
        let one_buf = ZeroCopyBuf::mock();
        let multi_bufs = repeat_with(ZeroCopyBuf::mock).take(42);

        zero_buf_op(none_buf.into()).unwrap();
        maybe_buf_op(some_buf.into()).unwrap();
        one_buf_op(one_buf.into()).unwrap();
        multi_buf_op(multi_bufs.into());
    }

    #[test]
    fn test_buf_list_err() {
        let none_buf = Option::<ZeroCopyBuf>::None;
        let some_buf = Some(ZeroCopyBuf::mock());
        let many_bufs = repeat_with(ZeroCopyBuf::mock).take(42);

        zero_buf_op(some_buf.into()).unwrap_err();
        maybe_buf_op(many_bufs.into()).unwrap_err();
        one_buf_op(none_buf.into()).unwrap_err();
    }
}
SyrupThinker

comment created time in 15 hours

pull request commentdenoland/deno

Ops can take several zero copy buffers (#4786)

As far as I can see ZeroCopyBuf doesn't implement Default, and I also can't imagine a sensible default value for it, so I can't use std::mem::take

That doesn't matter. You could "take" the entire slice. The slice implements default.

I'll write an example if this is unclear.

SyrupThinker

comment created time in 17 hours

pull request commentdenoland/deno

Ops can take several zero copy buffers (#4786)

OK in that case: I find the extra heap allocation unfortunate. I'd suggest to pass &mut [ZeroCopyBuf]. The op could then take ownership of the buffers by using std::mem::take().

Of course an op that takes a variable number of buffers would still need to heap allocate, but that'd be better than penalizing all ops for the few that would need that.

SyrupThinker

comment created time in 17 hours

push eventpiscisaureus/v8rs

Bert Belder

commit sha c53a6f71111ce4d026fc6c95a2ab9232bf7c6d7b

more baby steps

view details

push time in a day

push eventpiscisaureus/v8rs

Bert Belder

commit sha 7a6a1642f540b855da2a91a3826ad659a7a5eeb3

Baby steps

view details

push time in a day

pull request commentdenoland/deno

Ops can take several zero copy buffers (#4786)

what is the purpose of using multiple ZeroCopy buffers?

SyrupThinker

comment created time in a day

push eventpiscisaureus/v8rs

Bert Belder

commit sha dbaf30a8f6e7c321072581e3098ba5045b53f93e

In progress

view details

push time in 4 days

push eventpiscisaureus/v8rs

Bert Belder

commit sha 07e134deeef761215570a6bd544fbec4e5f67177

Ok, getting real close now...

view details

push time in 4 days

issue commentdenoland/deno

Stack occasionally overflows in a debug build

@kdy1 stack frame size report: https://gist.github.com/f4acf72698d355f916f5997ecd1469ea

seishun

comment created time in 4 days

delete branch piscisaureus/wepoll

delete branch : try

delete time in 4 days

push eventpiscisaureus/wepoll

Bert Belder

commit sha 78bb46e678e801a2c18819739960f36062d4ec6e

port,sock: minor tweaks to 'alloc()' and 'free()' functions

view details

Bert Belder

commit sha 07af653b1759f93d5992861c2f4491df263ca9cf

src: rename 'afd_helper' to the more descriptive 'afd_device'

view details

Bert Belder

commit sha f8a135487de7eb79bc6d8eee270cbd81bd69fbbc

src: improve code comments

view details

Bert Belder

commit sha 2ce1a56c40564c7e99f94b23d027e29c56695172

config: rename macro 'WEPOLL_INTERNAL_VAR' to 'WEPOLL_INTERNAL_EXTERN' The old name was not really appropriate; this attribute should only be used on variable declarations, while the definition of the same variable needs to be tagged with 'WEPOLL_INTERNAL'.

view details

Bert Belder

commit sha e9fa25980bac0ca39f38127c9c398064ad5297cd

config: re-enable overriding 'WEPOLL_EXPORT' when compiling bundle This possibility got inadvertently removed in the big config refactor (3ad20d7), which made building a shared library from the bundled source distribution (as is done by e.g. vcpkg) impossible.

view details

Bert Belder

commit sha 71e9ea666498b84c9cdea4041d7ad4102cc4821c

tools/bundle: don't emit empty line when stripping 'clang-format on|off' comment

view details

Bert Belder

commit sha f8325fba920f6f5c8830c19b438b26b0c930fcf6

ci: don't dump the entire environment into the build log

view details

push time in 4 days

push eventpiscisaureus/wepoll

Bert Belder

commit sha f8325fba920f6f5c8830c19b438b26b0c930fcf6

ci: don't dump the entire environment into the build log

view details

push time in 4 days

create barnchpiscisaureus/wepoll

branch : try

created branch time in 4 days

push eventpiscisaureus/v8rs

Bert Belder

commit sha 2b1b424f796f11284894d21643a4ed979b0cbf44

Bring back ContextScope

view details

push time in 5 days

pull request commentpiscisaureus/wepoll

Make header names lowercase

Would you perhaps be okay with an #ifdef MINGW32 that includes lowercase headers when compiling with mingw?

Yes that is alright. Surpressing the clang warning with a pragma would also be okay with me.

Did anyone verify that wepoll works at all on wine though? My money is on "not even close".

stjepang

comment created time in 5 days

pull request commentpiscisaureus/wepoll

Make header names lowercase

I see your point, but the mixed-case file names do match their actual names.

Changing it to lowercase makes mingw sad: https://ci.appveyor.com/project/piscisaureus/wepoll/builds/33115905/job/ihio591255g4f9r6#L163

stjepang

comment created time in 5 days

push eventpiscisaureus/v8rs

Bert Belder

commit sha 38444a116aeaf417b86e46a1c51bdec48e75f66a

Very WIP

view details

push time in 5 days

push eventpiscisaureus/v8rs

Bert Belder

commit sha 10602af11cb267382592579ffaac51677794e6c8

Broken, but making progress again

view details

push time in 5 days

issue commentdenoland/deno

Stack occasionally overflows in a debug build

Seems very similar to what eventually got fixed here: https://github.com/denoland/deno/pull/5509#issuecomment-629699733

My guess is that swc needs to move some more stuff from the stack into boxes.

cc @kdy1

seishun

comment created time in 5 days

issue openeddenoland/deno

Deno crashes while typing text in inspector console

Only if:

  • script execution is not paused
  • eager evaluation is on

image

created time in 6 days

push eventpiscisaureus/v8rs

Bert Belder

commit sha a82789e965a3eee8b92c4f7ebfdca211138dcbf1

Remove 'Parent' type param from EscapableHandleScope

view details

push time in 6 days

push eventpiscisaureus/v8rs

Bert Belder

commit sha a4f646823ba0710217e95650a2f5a222b1d83734

Add Deref/DerefMut

view details

push time in 6 days

delete branch piscisaureus/deno

delete branch : inspector_crash

delete time in 6 days

PR merged denoland/deno

Reviewers
fix: BorrowMutError when evaluating expression in inspector console

Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector.

Fixes: #5807

+163 -87

0 comment

3 changed files

piscisaureus

pr closed time in 6 days

push eventdenoland/deno

Bert Belder

commit sha ee0b5bb89ec33acc5dafb876de1f9fda5bcfa236

test: add utility function for assigning unique port to inspector (#5822)

view details

Bert Belder

commit sha 131f2a5f0cdcdbebe3e17c447869f92c99a7c051

fix: BorrowMutError when evaluating expression in inspector console (#5822) Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector. Fixes: #5807

view details

push time in 6 days

issue closeddenoland/deno

Inspector causes Rust runtime crash

Trying to call functions within Deno on the inspector console, running deno repl --inspect, causes a crash, due to a cell already being borrowed, as seen here:

thread 'main' panicked at 'already mutably borrowed: BorrowError', /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550\src\libcore\cell.rs:798:9

The culprit of the crash seems to be this line of code: https://github.com/denoland/deno/blob/master/cli/inspector.rs#L547

Which keeps the cell borrowed, while poll_sessions is called, for instance here: https://github.com/denoland/deno/blob/master/cli/inspector.rs#L367

Edit: forgot to mention deno 1.0.2 v8 8.4.300 typescript 3.9.2

closed time in 6 days

sug0
PullRequestEvent

PR closed denoland/deno

fix: BorrowMutError when evaluating expression in inspector console

Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector.

Fixes: #5807

+163 -87

0 comment

3 changed files

piscisaureus

pr closed time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha 131f2a5f0cdcdbebe3e17c447869f92c99a7c051

fix: BorrowMutError when evaluating expression in inspector console (#5822) Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector. Fixes: #5807

view details

push time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha 36ffd682b2082ef3f7e8dfad9e30e366a31745ad

fix: BorrowMutError when evaluating expression in inspector console (#5822) Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector. Fixes: #5807

view details

push time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha ee0b5bb89ec33acc5dafb876de1f9fda5bcfa236

test: add utility function for assigning unique port to inspector (#5822)

view details

Bert Belder

commit sha ae81e69c66570964e9c18e931e439dff2e9bfc20

fix: BorrowMutError when evaluating expression in inspector console (#5822) Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector. Fixes: #5807

view details

push time in 6 days

PullRequestEvent

PR closed denoland/deno

fix: BorrowMutError when evaluating expression in inspector console

Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector.

Fixes: #5807

+160 -87

0 comment

3 changed files

piscisaureus

pr closed time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha f3ec33a9ac11e181f9afa669fed74a656b2fe09f

test: add utility function for assigning unique port to inspector (#5822)

view details

push time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha 1b3cac62e3db932d10083c54b4f7eef0a169d322

tests: add utility function for assigning a unique inspector port (#5822)

view details

push time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha 045796e02ca4b3ab2f038f3de341c20af415f717

fix: BorrowMutError when evaluating expression in inspector console (#5822) Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector. Fixes: #5807

view details

push time in 6 days

delete branch piscisaureus/safe_v8

delete branch : tcl

delete time in 6 days

PR merged denoland/rusty_v8

Use correct lifetime for TryCatch::exception()/message() return value

According to v8.h, "the returned handle is valid until this TryCatch block has been destroyed". This is incorrect, as can be demonstrated with the test below. In practice the return value lives no longer and no shorter than the active HandleScope at the time these methods are called. An issue has been opened about this in the V8 bug tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537.

fn try_catch_bad_lifetimes() {
  let _setup_guard = setup();
  let mut isolate = v8::Isolate::new(Default::default());
  let mut hs = v8::HandleScope::new(&mut isolate);
  let scope = hs.enter();
  let context = v8::Context::new(scope);
  let mut cs = v8::ContextScope::new(scope, context);
  let scope = cs.enter();
  let caught_msg_2 = {
    let mut try_catch = v8::TryCatch::new(scope);
    let try_catch = try_catch.enter();
    let caught_msg_1 = {
      let mut hs = v8::HandleScope::new(scope);
      let scope = hs.enter();

      // Throw exception #1.
      let msg_1 = v8::String::new(scope, "BOOM!").unwrap();
      let exc_1 = v8::Exception::type_error(scope, msg_1);
      scope.isolate().throw_exception(exc_1);
      // Catch exception #1.
      let caught_msg_1 = try_catch.message().unwrap();
      let caught_str_1 =
        caught_msg_1.get(scope).to_rust_string_lossy(scope);
      assert!(caught_str_1.contains("BOOM"));
      // Move `caught_msg_1` out of the HandleScope it was created in.
      // The borrow checker allows this because `caught_msg_1`'s
      // lifetime is contrained to not outlive the TryCatch, but it is
      // allowed to outlive the HandleScope that was active when the
      // exception was caught.
      caught_msg_1
    };
    // Next line crashes.
    let caught_str_1 =
      caught_msg_1.get(scope).to_rust_string_lossy(scope);
    assert!(caught_str_1.contains("BOOM"));

    // Throws exception #2.
    let msg_2 = v8::String::new(scope, "DANG!").unwrap();
    let exc_2 = v8::Exception::type_error(scope, msg_2);
    scope.isolate().throw_exception(exc_2);
    // Catch exception #2.
    let caught_msg_2 = try_catch.message().unwrap();
    let caught_str_2 =
      caught_msg_2.get(scope).to_rust_string_lossy(scope);
    assert!(caught_str_2.contains("DANG"));
    // Move `caught_msg_2` out of the extent of the TryCatch, but still
    // within the extent of its HandleScope. This is unnecessarily
    // rejected at compile time.
    caught_msg_2
  };
  let caught_str_2 =
    caught_msg_2.get(scope).to_rust_string_lossy(scope);
  assert!(caught_str_2.contains("DANG"));
}
+92 -44

0 comment

6 changed files

piscisaureus

pr closed time in 6 days

push eventdenoland/rusty_v8

Bert Belder

commit sha 56c3d9f9c01af4ca5eed0e3219c8457bec568414

Use correct lifetime for TryCatch::exception()/message() return value (#380) According to v8.h, "the returned handle is valid until this TryCatch block has been destroyed". This is incorrect, as can be demonstrated with the test below. In practice the return value lives no longer and no shorter than the active HandleScope at the time these methods are called. An issue has been opened about this in the V8 bug tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537. ```rust fn try_catch_bad_lifetimes() { let _setup_guard = setup(); let mut isolate = v8::Isolate::new(Default::default()); let mut hs = v8::HandleScope::new(&mut isolate); let scope = hs.enter(); let context = v8::Context::new(scope); let mut cs = v8::ContextScope::new(scope, context); let scope = cs.enter(); let caught_msg_2 = { let mut try_catch = v8::TryCatch::new(scope); let try_catch = try_catch.enter(); let caught_msg_1 = { let mut hs = v8::HandleScope::new(scope); let scope = hs.enter(); // Throw exception #1. let msg_1 = v8::String::new(scope, "BOOM!").unwrap(); let exc_1 = v8::Exception::type_error(scope, msg_1); scope.isolate().throw_exception(exc_1); // Catch exception #1. let caught_msg_1 = try_catch.message().unwrap(); let caught_str_1 = caught_msg_1.get(scope).to_rust_string_lossy(scope); assert!(caught_str_1.contains("BOOM")); // Move `caught_msg_1` out of the HandleScope it was created in. // The borrow checker allows this because `caught_msg_1`'s // lifetime is contrained to not outlive the TryCatch, but it is // allowed to outlive the HandleScope that was active when the // exception was caught. caught_msg_1 }; // Next line crashes. let caught_str_1 = caught_msg_1.get(scope).to_rust_string_lossy(scope); assert!(caught_str_1.contains("BOOM")); // Throws exception #2. let msg_2 = v8::String::new(scope, "DANG!").unwrap(); let exc_2 = v8::Exception::type_error(scope, msg_2); scope.isolate().throw_exception(exc_2); // Catch exception #2. let caught_msg_2 = try_catch.message().unwrap(); let caught_str_2 = caught_msg_2.get(scope).to_rust_string_lossy(scope); assert!(caught_str_2.contains("DANG")); // Move `caught_msg_2` out of the extent of the TryCatch, but still // within the extent of its HandleScope. This is unnecessarily // rejected at compile time. caught_msg_2 }; let caught_str_2 = caught_msg_2.get(scope).to_rust_string_lossy(scope); assert!(caught_str_2.contains("DANG")); } ```

view details

push time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha cd78bd46c394eb4084244988793aab04107fbaed

fix: BorrowMutError when evaluating expression in inspector console (#5822) Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector. Fixes: #5807

view details

push time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha abb5d9b3acc8bf78b5c33c973087854146959eba

fix: BorrowMutError when evaluating expression in inspector console (#5822) Note that this does not fix the 'Uncaught ReferenceError' issue that happens when 'eager evaluation' is enabled in the inspector. Fixes: #5807

view details

push time in 6 days

push eventpiscisaureus/deno

Bert Belder

commit sha 039882e2216ea2b3279b1b7aebd61635e494b6c2

Add test demonstrating crash when evaluating expression in inspector Ref: #5807

view details

push time in 6 days

PR opened denoland/deno

[WIP] Fix crash when evaluating expression in inspector console

Ref: #5807

<!-- Before submitting a PR, please read https://github.com/denoland/deno/blob/master/docs/contributing.md -->

+63 -0

0 comment

2 changed files

pr created time in 6 days

create barnchpiscisaureus/deno

branch : inspector_crash

created branch time in 6 days

pull request commentdenoland/rusty_v8

Remove python as a required dependency for non-source builds

I'm in favor of this. In fact, I'd prefer to try and use curl only for not-from-source builds. Otherwise the likelihood of this breaking is pretty high, given that all the maintainers are going to have python2 installed anyway.

GeorgeHahn

comment created time in 6 days

issue commentdenoland/deno

Inspector causes Rust runtime crash

So the problem is an invalid double borrow of 'State'. This bug has probably been introduced when the inspector object was moved from Worker to State in e34a3b61f449cf6197b6d701770a85d9205c2a7b (#5250).

sug0

comment created time in 6 days

issue commentdenoland/deno

Inspector causes Rust runtime crash

More useful stack trace below. There is another (known but possibly related) issue: typing anything in the inspector console makes deno crash if the script isn't paused.

thread 'main' panicked at 'already mutably borrowed: BorrowError', /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\cell.rs:798:9
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized
             at C:\Users\VssAdministrator\.cargo\registry\src\github.com-1ecc6299db9ec823\backtrace-0.3.44\src\backtrace\mod.rs:66
   1: std::sys_common::backtrace::_print_fmt
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\sys_common\backtrace.rs:78
   2: std::sys_common::backtrace::_print::{{impl}}::fmt
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\sys_common\backtrace.rs:59
   3: core::fmt::write
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libcore\fmt\mod.rs:1063
   4: std::io::Write::write_fmt<std::sys::windows::stdio::Stderr>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\io\mod.rs:1426
   5: std::sys_common::backtrace::_print
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\sys_common\backtrace.rs:62
   6: std::sys_common::backtrace::print
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\sys_common\backtrace.rs:49
   7: std::panicking::default_hook::{{closure}}
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\panicking.rs:204
   8: std::panicking::default_hook
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\panicking.rs:224
   9: std::panicking::rust_panic_with_hook
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\panicking.rs:470
  10: std::panicking::begin_panic_handler
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\panicking.rs:378
  11: core::panicking::panic_fmt
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libcore\panicking.rs:85
  12: core::option::expect_none_failed
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libcore\option.rs:1211
  13: core::result::Result<core::cell::Ref<deno::state::StateInner>, core::cell::BorrowError>::expect<core::cell::Ref<deno::state::StateInner>,core::cell::BorrowError>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\result.rs:961
  14: core::cell::RefCell<deno::state::StateInner>::borrow<deno::state::StateInner>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\cell.rs:798
  15: deno::state::State::check_read
             at .\cli\state.rs:468
  16: deno::ops::fs::op_cwd
             at .\cli\ops\fs.rs:959
  17: core::ops::function::Fn::call<fn(deno::state::State*, serde_json::value::Value, core::option::Option<deno_core::isolate::ZeroCopyBuf>) -> core::result::Result<deno::ops::dispatch_json::JsonOp, deno::op_error::OpError>,(deno::state::State*, serde_json::val
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\ops\function.rs:72
  18: deno::state::{{impl}}::stateful_op::{{closure}}<fn(deno::state::State*, serde_json::value::Value, core::option::Option<deno_core::isolate::ZeroCopyBuf>) -> core::result::Result<deno::ops::dispatch_json::JsonOp, deno::op_error::OpError>>
             at .\cli\state.rs:203
  19: deno::ops::dispatch_json::json_op::{{closure}}::{{closure}}<closure-0>
             at .\cli\ops\dispatch_json.rs:69
  20: core::result::Result<serde_json::value::Value, deno::op_error::OpError>::and_then<serde_json::value::Value,deno::op_error::OpError,deno::ops::dispatch_json::JsonOp,closure-0>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\result.rs:727
  21: deno::ops::dispatch_json::json_op::{{closure}}<closure-0>
             at .\cli\ops\dispatch_json.rs:67
  22: deno::state::{{impl}}::core_op::{{closure}}<closure-0>
             at .\cli\state.rs:115
  23: deno_core::isolate::CoreIsolate::dispatch_op<rusty_v8::scope::Entered<rusty_v8::function::FunctionCallbackInfo, ()>>
             at .\core\isolate.rs:366
  24: deno_core::bindings::send
             at .\core\bindings.rs:470
  25: core::ops::function::Fn::call<fn(mut rusty_v8::scope::Entered<rusty_v8::function::FunctionCallbackInfo, ()>*, rusty_v8::function::FunctionCallbackArguments, rusty_v8::function::ReturnValue),(mut rusty_v8::scope::Entered<rusty_v8::function::FunctionCallbac
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\ops\function.rs:72
  26: rusty_v8::function::{{impl}}::mapping::{{closure}}<fn(mut rusty_v8::scope::Entered<rusty_v8::function::FunctionCallbackInfo, ()>*, rusty_v8::function::FunctionCallbackArguments, rusty_v8::function::ReturnValue)>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\rusty_v8-0.4.2\src\function.rs:251
  27: rusty_v8::support::{{impl}}::mapping::c_fn<closure-0,(),const rusty_v8::function::FunctionCallbackInfo*>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\rusty_v8-0.4.2\src\support.rs:584
  28: v8::internal::FunctionCallbackArguments::Call
             at .\..\..\..\..\v8\src\api\api-arguments-inl.h:158
  29: v8::internal::`anonymous namespace'::HandleApiCallHelper<0>
             at .\..\..\..\..\v8\src\builtins\builtins-api.cc:111
  30: v8::internal::Builtin_Impl_HandleApiCall
             at .\..\..\..\..\v8\src\builtins\builtins-api.cc:141
  31: v8::internal::Builtin_HandleApiCall
             at .\..\..\..\..\v8\src\builtins\builtins-api.cc:129
  32: Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit
  33: Builtins_InterpreterEntryTrampoline
  34: Builtins_InterpreterEntryTrampoline
  35: Builtins_InterpreterEntryTrampoline
  36: Builtins_InterpreterEntryTrampoline
  37: Builtins_JSEntryTrampoline
  38: Builtins_JSEntry
  39: v8::internal::`anonymous namespace'::Invoke
             at .\..\..\..\..\v8\src\execution\execution.cc:367
  40: v8::internal::Execution::Call
             at .\..\..\..\..\v8\src\execution\execution.cc:461
  41: v8::internal::DebugEvaluate::Global
             at .\..\..\..\..\v8\src\debug\debug-evaluate.cc:54
  42: v8::debug::EvaluateGlobal
             at .\..\..\..\..\v8\src\api\api.cc:10065
  43: v8_inspector::V8RuntimeAgentImpl::evaluate
             at .\..\..\..\..\v8\src\inspector\v8-runtime-agent-impl.cc:288
  44: v8_inspector::protocol::Runtime::DomainDispatcherImpl::evaluate
             at .\gen\v8\src\inspector\protocol\Runtime.cpp:2085
  45: std::__1::__function::__policy_invoker<void (const v8_crdtp::Dispatchable &)>::__call_impl<std::__1::__function::__default_alloc_func<`lambda at gen/v8/src/inspector/protocol/Runtime.cpp:1726:10',void (const v8_crdtp::Dispatchable &)>>
             at .\..\..\..\..\buildtools\third_party\libc++\trunk\include\functional:2071
  46: v8_crdtp::UberDispatcher::DispatchResult::Run
             at .\..\..\..\..\v8\third_party\inspector_protocol\crdtp\dispatch.cc:501
  47: v8_inspector::V8InspectorSessionImpl::dispatchProtocolMessage
             at .\..\..\..\..\v8\src\inspector\v8-inspector-session-impl.cc:378
  48: v8_inspector__V8InspectorSession__dispatchProtocolMessage
             at .\..\..\..\..\src\binding.cc:1476
  49: rusty_v8::inspector::V8InspectorSession::dispatch_protocol_message
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\rusty_v8-0.4.2\src\inspector.rs:563
  50: deno::inspector::{{impl}}::receive_from_websocket::{{closure}}::{{closure}}
             at .\cli\inspector.rs:740
  51: futures_util::stream::try_stream::map_ok::{{impl}}::poll_next::{{closure}}::{{closure}}::{{closure}}<futures_channel::mpsc::UnboundedReceiver<core::result::Result<warp::filters::ws::Message, warp::error::Error>>,closure-0,()>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\stream\try_stream\map_ok.rs:95
  52: core::result::Result<warp::filters::ws::Message, warp::error::Error>::map<warp::filters::ws::Message,warp::error::Error,(),closure-0>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\result.rs:519
  53: futures_util::stream::try_stream::map_ok::{{impl}}::poll_next::{{closure}}::{{closure}}<futures_channel::mpsc::UnboundedReceiver<core::result::Result<warp::filters::ws::Message, warp::error::Error>>,closure-0,()>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\stream\try_stream\map_ok.rs:95
  54: core::option::Option<core::result::Result<warp::filters::ws::Message, warp::error::Error>>::map<core::result::Result<warp::filters::ws::Message, warp::error::Error>,core::result::Result<(), warp::error::Error>,closure-0>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\option.rs:456
  55: futures_util::stream::try_stream::map_ok::{{impl}}::poll_next::{{closure}}<futures_channel::mpsc::UnboundedReceiver<core::result::Result<warp::filters::ws::Message, warp::error::Error>>,closure-0,()>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\stream\try_stream\map_ok.rs:95
  56: core::task::poll::Poll<core::option::Option<core::result::Result<warp::filters::ws::Message, warp::error::Error>>>::map<core::option::Option<core::result::Result<warp::filters::ws::Message, warp::error::Error>>,core::option::Option<core::result::Result<()
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\task\poll.rs:33
  57: futures_util::stream::try_stream::map_ok::{{impl}}::poll_next<futures_channel::mpsc::UnboundedReceiver<core::result::Result<warp::filters::ws::Message, warp::error::Error>>,closure-0,()>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\stream\try_stream\map_ok.rs:92
  58: futures_core::stream::{{impl}}::try_poll_next<futures_util::stream::try_stream::map_ok::MapOk<futures_channel::mpsc::UnboundedReceiver<core::result::Result<warp::filters::ws::Message, warp::error::Error>>, closure-0>,(),warp::error::Error>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-core-0.3.4\src\stream.rs:193
  59: futures_util::stream::try_stream::try_collect::{{impl}}::poll<futures_util::stream::try_stream::map_ok::MapOk<futures_channel::mpsc::UnboundedReceiver<core::result::Result<warp::filters::ws::Message, warp::error::Error>>, closure-0>,()>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\stream\try_stream\try_collect.rs:56
  60: std::future::poll_with_tls_context<futures_util::stream::try_stream::try_collect::TryCollect<futures_util::stream::try_stream::map_ok::MapOk<futures_channel::mpsc::UnboundedReceiver<core::result::Result<warp::filters::ws::Message, warp::error::Error>>, cl
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libstd\future.rs:102
  61: deno::inspector::{{impl}}::receive_from_websocket::{{closure}}
             at .\cli\inspector.rs:736
  62: std::future::{{impl}}::poll<generator-0>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libstd\future.rs:44
  63: core::future::future::{{impl}}::poll<alloc::boxed::Box<Future>>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\future\future.rs:118
  64: futures_util::future::future::FutureExt::poll_unpin<core::pin::Pin<alloc::boxed::Box<Future>>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\future\mod.rs:507
  65: deno::inspector::{{impl}}::poll
             at .\cli\inspector.rs:796
  66: alloc::boxed::{{impl}}::poll<deno::inspector::DenoInspectorSession>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\liballoc\boxed.rs:1157
  67: futures_util::stream::futures_unordered::{{impl}}::poll_next<alloc::boxed::Box<deno::inspector::DenoInspectorSession>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\stream\futures_unordered\mod.rs:544
  68: futures_util::stream::stream::StreamExt::poll_next_unpin<futures_util::stream::futures_unordered::FuturesUnordered<alloc::boxed::Box<deno::inspector::DenoInspectorSession>>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\stream\stream\mod.rs:1184
  69: deno::inspector::DenoInspector::poll_sessions
             at .\cli\inspector.rs:489
  70: deno::inspector::{{impl}}::poll
             at .\cli\inspector.rs:367
  71: alloc::boxed::{{impl}}::poll<deno::inspector::DenoInspector>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\liballoc\boxed.rs:1157
  72: futures_util::future::future::FutureExt::poll_unpin<alloc::boxed::Box<deno::inspector::DenoInspector>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\future\mod.rs:507
  73: deno::worker::{{impl}}::poll::{{closure}}
             at .\cli\worker.rs:208
  74: core::option::Option<mut alloc::boxed::Box<deno::inspector::DenoInspector>*>::map<mut alloc::boxed::Box<deno::inspector::DenoInspector>*,core::task::poll::Poll<()>,closure-0>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\option.rs:456
  75: deno::worker::{{impl}}::poll
             at .\cli\worker.rs:208
  76: core::future::future::{{impl}}::poll<deno::worker::Worker>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\future\future.rs:106
  77: std::future::poll_with_tls_context<mut deno::worker::Worker*>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libstd\future.rs:102
  78: deno::run_repl::{{closure}}
             at .\cli\main.rs:506
  79: std::future::{{impl}}::poll<generator-0>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libstd\future.rs:44
  80: core::future::future::{{impl}}::poll<alloc::boxed::Box<Future>>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libcore\future\future.rs:118
  81: tokio::runtime::basic_scheduler::{{impl}}::block_on::{{closure}}::{{closure}}<tokio::park::either::Either<tokio::time::driver::Driver<tokio::park::either::Either<tokio::io::driver::Driver, tokio::park::thread::ParkThread>>, tokio::park::either::Either<tok
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\basic_scheduler.rs:131
  82: tokio::coop::budget::{{closure}}<closure-0,core::task::poll::Poll<core::result::Result<(), deno_core::any_error::ErrBox>>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\coop.rs:97
  83: std::thread::local::LocalKey<core::cell::Cell<usize>>::try_with<core::cell::Cell<usize>,closure-0,core::task::poll::Poll<core::result::Result<(), deno_core::any_error::ErrBox>>>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libstd\thread\local.rs:262
  84: std::thread::local::LocalKey<core::cell::Cell<usize>>::with<core::cell::Cell<usize>,closure-0,core::task::poll::Poll<core::result::Result<(), deno_core::any_error::ErrBox>>>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libstd\thread\local.rs:239
  85: tokio::coop::budget
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\coop.rs:79
  86: tokio::runtime::basic_scheduler::{{impl}}::block_on::{{closure}}<tokio::park::either::Either<tokio::time::driver::Driver<tokio::park::either::Either<tokio::io::driver::Driver, tokio::park::thread::ParkThread>>, tokio::park::either::Either<tokio::io::drive
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\basic_scheduler.rs:131
  87: tokio::runtime::basic_scheduler::enter::{{closure}}<closure-0,core::result::Result<(), deno_core::any_error::ErrBox>,tokio::park::either::Either<tokio::time::driver::Driver<tokio::park::either::Either<tokio::io::driver::Driver, tokio::park::thread::ParkTh
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\basic_scheduler.rs:213
  88: tokio::macros::scoped_tls::ScopedKey<tokio::runtime::basic_scheduler::Context>::set<tokio::runtime::basic_scheduler::Context,closure-0,core::result::Result<(), deno_core::any_error::ErrBox>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\macros\scoped_tls.rs:64
  89: tokio::runtime::basic_scheduler::enter<closure-0,core::result::Result<(), deno_core::any_error::ErrBox>,tokio::park::either::Either<tokio::time::driver::Driver<tokio::park::either::Either<tokio::io::driver::Driver, tokio::park::thread::ParkThread>>, tokio
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\basic_scheduler.rs:213
  90: tokio::runtime::basic_scheduler::BasicScheduler<tokio::park::either::Either<tokio::time::driver::Driver<tokio::park::either::Either<tokio::io::driver::Driver, tokio::park::thread::ParkThread>>, tokio::park::either::Either<tokio::io::driver::Driver, tokio:
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\basic_scheduler.rs:123
  91: tokio::runtime::{{impl}}::block_on::{{closure}}<core::pin::Pin<alloc::boxed::Box<Future>>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\mod.rs:444
  92: tokio::runtime::context::enter<closure-0,core::result::Result<(), deno_core::any_error::ErrBox>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\context.rs:72
  93: tokio::runtime::handle::Handle::enter<closure-0,core::result::Result<(), deno_core::any_error::ErrBox>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\handle.rs:71
  94: tokio::runtime::Runtime::block_on<core::pin::Pin<alloc::boxed::Box<Future>>>
             at C:\Users\BertBelder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.20\src\runtime\mod.rs:441
  95: deno::tokio_util::run_basic<core::pin::Pin<alloc::boxed::Box<Future>>,core::result::Result<(), deno_core::any_error::ErrBox>>
             at .\cli\tokio_util.rs:18
  96: deno::main
             at .\cli\main.rs:669
  97: std::rt::lang_start::{{closure}}<()>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\src\libstd\rt.rs:67
  98: std::rt::lang_start_internal::{{closure}}
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\rt.rs:52
  99: std::panicking::try::do_call<closure-0,i32>
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libstd\panicking.rs:303
 100: panic_unwind::__rust_maybe_catch_panic
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd\/src\libpanic_unwind\lib.rs:86
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
sug0

comment created time in 6 days

push eventpiscisaureus/safe_v8

Bert Belder

commit sha 56c3d9f9c01af4ca5eed0e3219c8457bec568414

Use correct lifetime for TryCatch::exception()/message() return value (#380) According to v8.h, "the returned handle is valid until this TryCatch block has been destroyed". This is incorrect, as can be demonstrated with the test below. In practice the return value lives no longer and no shorter than the active HandleScope at the time these methods are called. An issue has been opened about this in the V8 bug tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537. ```rust fn try_catch_bad_lifetimes() { let _setup_guard = setup(); let mut isolate = v8::Isolate::new(Default::default()); let mut hs = v8::HandleScope::new(&mut isolate); let scope = hs.enter(); let context = v8::Context::new(scope); let mut cs = v8::ContextScope::new(scope, context); let scope = cs.enter(); let caught_msg_2 = { let mut try_catch = v8::TryCatch::new(scope); let try_catch = try_catch.enter(); let caught_msg_1 = { let mut hs = v8::HandleScope::new(scope); let scope = hs.enter(); // Throw exception #1. let msg_1 = v8::String::new(scope, "BOOM!").unwrap(); let exc_1 = v8::Exception::type_error(scope, msg_1); scope.isolate().throw_exception(exc_1); // Catch exception #1. let caught_msg_1 = try_catch.message().unwrap(); let caught_str_1 = caught_msg_1.get(scope).to_rust_string_lossy(scope); assert!(caught_str_1.contains("BOOM")); // Move `caught_msg_1` out of the HandleScope it was created in. // The borrow checker allows this because `caught_msg_1`'s // lifetime is contrained to not outlive the TryCatch, but it is // allowed to outlive the HandleScope that was active when the // exception was caught. caught_msg_1 }; // Next line crashes. let caught_str_1 = caught_msg_1.get(scope).to_rust_string_lossy(scope); assert!(caught_str_1.contains("BOOM")); // Throws exception #2. let msg_2 = v8::String::new(scope, "DANG!").unwrap(); let exc_2 = v8::Exception::type_error(scope, msg_2); scope.isolate().throw_exception(exc_2); // Catch exception #2. let caught_msg_2 = try_catch.message().unwrap(); let caught_str_2 = caught_msg_2.get(scope).to_rust_string_lossy(scope); assert!(caught_str_2.contains("DANG")); // Move `caught_msg_2` out of the extent of the TryCatch, but still // within the extent of its HandleScope. This is unnecessarily // rejected at compile time. caught_msg_2 }; let caught_str_2 = caught_msg_2.get(scope).to_rust_string_lossy(scope); assert!(caught_str_2.contains("DANG")); } ```

view details

push time in 6 days

push eventpiscisaureus/safe_v8

Bert Belder

commit sha 12255884b1e51da6c1bb5955889a05b24f267773

Use correct lifetime for TryCatch::exception()/message() return value (#380) According to v8.h, "the returned handle is valid until this TryCatch block has been destroyed". This is incorrect, as can be demonstrated with the test below. In practice the return value lives no longer and no shorter than the active HandleScope at the time these methods are called. An issue has been opened about this in the V8 bug tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537. ```rust fn try_catch_bad_lifetimes() { let _setup_guard = setup(); let mut isolate = v8::Isolate::new(Default::default()); let mut hs = v8::HandleScope::new(&mut isolate); let scope = hs.enter(); let context = v8::Context::new(scope); let mut cs = v8::ContextScope::new(scope, context); let scope = cs.enter(); let caught_msg_2 = { let mut try_catch = v8::TryCatch::new(scope); let try_catch = try_catch.enter(); let caught_msg_1 = { let mut hs = v8::HandleScope::new(scope); let scope = hs.enter(); // Throw exception #1. let msg_1 = v8::String::new(scope, "BOOM!").unwrap(); let exc_1 = v8::Exception::type_error(scope, msg_1); scope.isolate().throw_exception(exc_1); // Catch exception #1. let caught_msg_1 = try_catch.message().unwrap(); let caught_str_1 = caught_msg_1.get(scope).to_rust_string_lossy(scope); assert!(caught_str_1.contains("BOOM")); // Move `caught_msg_1` out of the HandleScope it was created in. // The borrow checker allows this because `caught_msg_1`'s // lifetime is contrained to not outlive the TryCatch, but it is // allowed to outlive the HandleScope that was active when the // exception was caught. caught_msg_1 }; // Next line crashes. let caught_str_1 = caught_msg_1.get(scope).to_rust_string_lossy(scope); assert!(caught_str_1.contains("BOOM")); // Throws exception #2. let msg_2 = v8::String::new(scope, "DANG!").unwrap(); let exc_2 = v8::Exception::type_error(scope, msg_2); scope.isolate().throw_exception(exc_2); // Catch exception #2. let caught_msg_2 = try_catch.message().unwrap(); let caught_str_2 = caught_msg_2.get(scope).to_rust_string_lossy(scope); assert!(caught_str_2.contains("DANG")); // Move `caught_msg_2` out of the extent of the TryCatch, but still // within the extent of its HandleScope. This is unnecessarily // rejected at compile time. caught_msg_2 }; let caught_str_2 = caught_msg_2.get(scope).to_rust_string_lossy(scope); assert!(caught_str_2.contains("DANG")); } ```

view details

push time in 6 days

PR opened denoland/rusty_v8

Use correct lifetime for TryCatch::exception()/message() return value

According to v8.h, "the returned handle is valid until this TryCatch block has been destroyed". This is incorrect, as can be demonstrated with the test below. In practice the return value lives no longer and no shorter than the active HandleScope at the time these methods are called. An issue has been opened about this in the V8 bug tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537.

fn try_catch_bad_lifetimes() {
  let _setup_guard = setup();
  let mut isolate = v8::Isolate::new(Default::default());
  let mut hs = v8::HandleScope::new(&mut isolate);
  let scope = hs.enter();
  let context = v8::Context::new(scope);
  let mut cs = v8::ContextScope::new(scope, context);
  let scope = cs.enter();
  let caught_msg_2 = {
    let mut try_catch = v8::TryCatch::new(scope);
    let try_catch = try_catch.enter();
    let caught_msg_1 = {
      let mut hs = v8::HandleScope::new(scope);
      let scope = hs.enter();

      // Throw exception #1.
      let msg_1 = v8::String::new(scope, "BOOM!").unwrap();
      let exc_1 = v8::Exception::type_error(scope, msg_1);
      scope.isolate().throw_exception(exc_1);
      // Catch exception #1.
      let caught_msg_1 = try_catch.message().unwrap();
      let caught_str_1 =
        caught_msg_1.get(scope).to_rust_string_lossy(scope);
      assert!(caught_str_1.contains("BOOM"));
      // Move `caught_msg_1` out of the HandleScope it was created in.
      // The borrow checker allows this because `caught_msg_1`'s
      // lifetime is contrained to not outlive the TryCatch, but it is
      // allowed to outlive the HandleScope that was active when the
      // exception was caught.
      caught_msg_1
    };
    // Next line crashes.
    let caught_str_1 =
      caught_msg_1.get(scope).to_rust_string_lossy(scope);
    assert!(caught_str_1.contains("BOOM"));

    // Throws exception #2.
    let msg_2 = v8::String::new(scope, "DANG!").unwrap();
    let exc_2 = v8::Exception::type_error(scope, msg_2);
    scope.isolate().throw_exception(exc_2);
    // Catch exception #2.
    let caught_msg_2 = try_catch.message().unwrap();
    let caught_str_2 =
      caught_msg_2.get(scope).to_rust_string_lossy(scope);
    assert!(caught_str_2.contains("DANG"));
    // Move `caught_msg_2` out of the extent of the TryCatch, but still
    // within the extent of its HandleScope. This is unnecessarily
    // rejected at compile time.
    caught_msg_2
  };
  let caught_str_2 =
    caught_msg_2.get(scope).to_rust_string_lossy(scope);
  assert!(caught_str_2.contains("DANG"));
}
+92 -44

0 comment

6 changed files

pr created time in 6 days

push eventpiscisaureus/safe_v8

Jen

commit sha 3fb278e7e82cc2781678d6c21f45a24f58e0a5f6

Fix typos in README.md (#375)

view details

Bert Belder

commit sha b49de9b96d8cece076a0da7883c5eab4228d84b6

Use correct lifetime for TryCatch::exception()/message() return value According to v8.h, "the returned handle is valid until this TryCatch block has been destroyed". This is incorrect, as can be demonstrated with the test below. In practice the return value lives no longer and no shorter than the active HandleScope at the time these methods are called. An issue has been opened about this in the V8 bug tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537. ```rust fn try_catch_bad_lifetimes() { let _setup_guard = setup(); let mut isolate = v8::Isolate::new(Default::default()); let mut hs = v8::HandleScope::new(&mut isolate); let scope = hs.enter(); let context = v8::Context::new(scope); let mut cs = v8::ContextScope::new(scope, context); let scope = cs.enter(); let caught_msg_2 = { let mut try_catch = v8::TryCatch::new(scope); let try_catch = try_catch.enter(); let caught_msg_1 = { let mut hs = v8::HandleScope::new(scope); let scope = hs.enter(); // Throw exception #1. let msg_1 = v8::String::new(scope, "BOOM!").unwrap(); let exc_1 = v8::Exception::type_error(scope, msg_1); scope.isolate().throw_exception(exc_1); // Catch exception #1. let caught_msg_1 = try_catch.message().unwrap(); let caught_str_1 = caught_msg_1.get(scope).to_rust_string_lossy(scope); assert!(caught_str_1.contains("BOOM")); // Move `caught_msg_1` out of the HandleScope it was created in. // The borrow checker allows this because `caught_msg_1`'s // lifetime is contrained to not outlive the TryCatch, but it is // allowed to outlive the HandleScope that was active when the // exception was caught. caught_msg_1 }; // Next line crashes. let caught_str_1 = caught_msg_1.get(scope).to_rust_string_lossy(scope); assert!(caught_str_1.contains("BOOM")); // Throws exception #2. let msg_2 = v8::String::new(scope, "DANG!").unwrap(); let exc_2 = v8::Exception::type_error(scope, msg_2); scope.isolate().throw_exception(exc_2); // Catch exception #2. let caught_msg_2 = try_catch.message().unwrap(); let caught_str_2 = caught_msg_2.get(scope).to_rust_string_lossy(scope); assert!(caught_str_2.contains("DANG")); // Move `caught_msg_2` out of the extent of the TryCatch, but still // within the extent of its HandleScope. This is unnecessarily // rejected at compile time. caught_msg_2 }; let caught_str_2 = caught_msg_2.get(scope).to_rust_string_lossy(scope); assert!(caught_str_2.contains("DANG")); } ```

view details

push time in 6 days

create barnchpiscisaureus/safe_v8

branch : tcl

created branch time in 6 days

issue commentdenoland/deno

Inspector causes Rust runtime crash

@sug0 I do believe that you are experiencing a crash, but I'm not convinced that you identified the right "culprit". If only because that line of code isn't (or at least - shouldn't) run when you use '--inspect'.

Could you share the full stack trace?

sug0

comment created time in 7 days

PullRequestEvent

PR closed denoland/deno

Add APIs that give plugins access to the resource table

Closes: #3637 Closes: #5248

+157 -8

2 comments

4 changed files

piscisaureus

pr closed time in 8 days

PullRequestEvent

PR closed denoland/rusty_v8

android support 64 bit

see https://chromium.googlesource.com/chromium/src/+/master/docs/android_build_instructions.md ref denoland/deno#3839

Successful build on aarch-linux-android and x86_64-linux-android 🙌 Other arch (arm and i686) are not currently available

How to

Clone the repo

git clone git@github.com:denoland/rusty_v8 ./rusty_v8
cd ./rusty_v8
git submodule update --init --recursive

Install cross

cargo install cross

Build aarch64

docker build --target aarch64-linux-android --tag denoland/rusty_v8:aarch64-linux-android .
V8_FROM_SOURCE=1 cross build -vv --target aarch64-linux-android

Build x86_64

docker build --target x86_64-linux-android --tag denoland/rusty_v8:x86_64-linux-android .
V8_FROM_SOURCE=1 cross build -vv --target x86_64-linux-android
+188 -23

19 comments

7 changed files

gponsinet

pr closed time in 8 days

pull request commentdenoland/rusty_v8

android support 64 bit

Let's try this.

gponsinet

comment created time in 8 days

pull request commentdenoland/rusty_v8

android support 64 bit

Github actions cache can be a bit fickle. Also once cached it will not update the cache for a branch/PR unless you change the cache key.

gponsinet

comment created time in 8 days

push eventpiscisaureus/deno

Bert Belder

commit sha b374cc532452cad426f62cf51a6bebf3b7e7ea3c

s/ref_resource/rc/g and comment update

view details

push time in 9 days

push eventpiscisaureus/deno

David Sherret

commit sha ee710994925e8840ea387e1853d9c15f3eb73149

fix(fmt): Do not panic on new expr with no parens. (#5734) Closes #5567

view details

Bert Belder

commit sha d4dd550d73ea7844981ef03b5e8d973ae07b2738

Merge remote-tracking branch 'origin/master'

view details

Bert Belder

commit sha 043f11ac44d2c218ddbcfdfc73fcb11232f73cc2

s/ref_resource/rc/g and comment update

view details

push time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 pub type DispatchOpFn =  pub trait Interface {   fn register_op(&mut self, name: &str, dispatcher: DispatchOpFn) -> OpId;+  fn resource_table(&mut self) -> &mut dyn ResourceTable;+}++/// Similar to `struct ResourceTable` for normal ops, but uses dynamic dispatch+/// instead of type parameters for its methods.+pub trait ResourceTable {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn close(&mut self, rid: ResourceId) -> Option<()>;+  fn get(&self, rid: ResourceId) -> Option<&dyn Resource>;+  fn get_mut(&mut self, rid: ResourceId) -> Option<&mut dyn Resource>;+  fn has(&self, rid: ResourceId) -> bool;

Structs as such are not the problem though -- it's type parameters, closures, things that get monophormized and end up in the plugin lib that causes problems. ZeroCopyBuf is a struct and we expose it without any issues.

That doesn't mean I think that exposing CoreIsolate makes a lot of sense. That struct is full of internal stuff that we really ought to clean up some day. Definitely not something you want to freeze into a (future stable) API. The only things that I can imagine would matter to people is the v8::Isolate and v8::Global, which we could just as easily expose directly on Interface.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 impl Drop for PluginOpAsyncFuture {     self.fut.take();   } }++struct PluginResourceTable<'a> {+  inner: RefMut<'a, ResourceTable>,+  plugin_lib: &'a Rc<Library>,+}++impl<'a> PluginResourceTable<'a> {+  fn new(+    resource_table: &'a mut Rc<RefCell<ResourceTable>>,+    plugin_lib: &'a Rc<Library>,+  ) -> Self {+    Self {+      inner: resource_table.borrow_mut(),+      plugin_lib,+    }+  }+}++/// A resource that has been inserted in the resource table by a dynamically+/// loaded plugin.+struct RefResource {+  inner: Box<dyn Resource>,+  _plugin_lib: Rc<Library>,+}++impl<'a> plugin_api::ResourceTable for PluginResourceTable<'a> {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {+    // Resources inserted by plugins are wrapped in a RefResource wrapper, so+    // we can ensure a reference to Rc<Library> is kept for as long as the+    // resource stays in the resource table.

Did the rename, added the comment as requested.

piscisaureus

comment created time in 9 days

push eventpiscisaureus/deno

Bert Belder

commit sha 2fc2329c075deddae04798467d8ba75a29210960

s/PluginResourceTable/ResourceTableRef/g + add comment

view details

push time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 pub type DispatchOpFn =  pub trait Interface {   fn register_op(&mut self, name: &str, dispatcher: DispatchOpFn) -> OpId;+  fn resource_table(&mut self) -> &mut dyn ResourceTable;+}++/// Similar to `struct ResourceTable` for normal ops, but uses dynamic dispatch+/// instead of type parameters for its methods.+pub trait ResourceTable {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn close(&mut self, rid: ResourceId) -> Option<()>;+  fn get(&self, rid: ResourceId) -> Option<&dyn Resource>;+  fn get_mut(&mut self, rid: ResourceId) -> Option<&mut dyn Resource>;+  fn has(&self, rid: ResourceId) -> bool;

The isolate was never exposed... And they're not supposed to touch v8? But if we wanted to add that we could.

piscisaureus

comment created time in 9 days

push eventpiscisaureus/deno

moyinzi

commit sha 8d8a2f573f32e0b2680eb114739902c5953f7b99

fix(std/http): file_server's target directory (#5695)

view details

Bert Belder

commit sha 95e89f730147800feebbe90e5491881947466c8b

Merge remote-tracking branch 'origin/master'

view details

Bartek Iwańczuk

commit sha 491feb859f30f56bc25d6afc730a1c709a0bb807

fix: --inspect flag working like --inspect-brk (#5697)

view details

Bert Belder

commit sha 5f3e9585e9541e4350b320b7489d5aceacc632cb

Merge remote-tracking branch 'origin/master'

view details

Bert Belder

commit sha c5aac23740ac18c69d6a0fab8694dec971e41bf5

s/RefResource/PluginDefinedResource/g

view details

push time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 impl Drop for PluginOpAsyncFuture {     self.fut.take();   } }++struct PluginResourceTable<'a> {+  inner: RefMut<'a, ResourceTable>,+  plugin_lib: &'a Rc<Library>,+}++impl<'a> PluginResourceTable<'a> {+  fn new(+    resource_table: &'a mut Rc<RefCell<ResourceTable>>,+    plugin_lib: &'a Rc<Library>,+  ) -> Self {+    Self {+      inner: resource_table.borrow_mut(),+      plugin_lib,+    }+  }+}++/// A resource that has been inserted in the resource table by a dynamically+/// loaded plugin.+struct RefResource {+  inner: Box<dyn Resource>,+  _plugin_lib: Rc<Library>,+}++impl<'a> plugin_api::ResourceTable for PluginResourceTable<'a> {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {+    // Resources inserted by plugins are wrapped in a RefResource wrapper, so+    // we can ensure a reference to Rc<Library> is kept for as long as the+    // resource stays in the resource table.

I see, can you add a comment about that? It's really not obvious at first glance

Sure. Or would renaming it to ResourceTableRef help?

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 impl Drop for PluginOpAsyncFuture {     self.fut.take();   } }++struct PluginResourceTable<'a> {+  inner: RefMut<'a, ResourceTable>,+  plugin_lib: &'a Rc<Library>,+}++impl<'a> PluginResourceTable<'a> {+  fn new(+    resource_table: &'a mut Rc<RefCell<ResourceTable>>,+    plugin_lib: &'a Rc<Library>,+  ) -> Self {+    Self {+      inner: resource_table.borrow_mut(),+      plugin_lib,+    }+  }+}++/// A resource that has been inserted in the resource table by a dynamically+/// loaded plugin.+struct RefResource {+  inner: Box<dyn Resource>,+  _plugin_lib: Rc<Library>,+}++impl<'a> plugin_api::ResourceTable for PluginResourceTable<'a> {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {+    // Resources inserted by plugins are wrapped in a RefResource wrapper, so+    // we can ensure a reference to Rc<Library> is kept for as long as the+    // resource stays in the resource table.

Then when are they closed? This is surprising, I would expect that closing plugin resource results in immediate drop of its associated data.

Yeah, but how would that work? When the 'Drop' handler for 'PluginResource' runs it *could * loop over the resource table, but it currently has no way to identify which resources were created by the dropped resource.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 pub type DispatchOpFn =  pub trait Interface {   fn register_op(&mut self, name: &str, dispatcher: DispatchOpFn) -> OpId;+  fn resource_table(&mut self) -> &mut dyn ResourceTable;+}++/// Similar to `struct ResourceTable` for normal ops, but uses dynamic dispatch+/// instead of type parameters for its methods.+pub trait ResourceTable {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn close(&mut self, rid: ResourceId) -> Option<()>;+  fn get(&self, rid: ResourceId) -> Option<&dyn Resource>;+  fn get_mut(&mut self, rid: ResourceId) -> Option<&mut dyn Resource>;+  fn has(&self, rid: ResourceId) -> bool;

Not really I'm afraid. It's here for the same reason as the the other stuff in plugin_api -- to make dynamically imported plugins not crash when they're dropped.

I think I disagree with you that this is unfortunate though. I think it provides a clean delineation between the public API and our overall pretty messy implementation. We should move it to it's own crate at some point so it can provide a stable "plugin api" snapshot; since this is a trait it would not break as long as the trait definition stays the same, even if core moves on and changes APIs.

Also, you don't have to use it when you're writing a statically linked plugin.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 pub type DispatchOpFn =  pub trait Interface {   fn register_op(&mut self, name: &str, dispatcher: DispatchOpFn) -> OpId;+  fn resource_table(&mut self) -> &mut dyn ResourceTable;+}++/// Similar to `struct ResourceTable` for normal ops, but uses dynamic dispatch+/// instead of type parameters for its methods.+pub trait ResourceTable {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn close(&mut self, rid: ResourceId) -> Option<()>;+  fn get(&self, rid: ResourceId) -> Option<&dyn Resource>;+  fn get_mut(&mut self, rid: ResourceId) -> Option<&mut dyn Resource>;

I do think that the real resource table could implement this trait with almost no effort tho.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 pub type DispatchOpFn =  pub trait Interface {   fn register_op(&mut self, name: &str, dispatcher: DispatchOpFn) -> OpId;+  fn resource_table(&mut self) -> &mut dyn ResourceTable;+}++/// Similar to `struct ResourceTable` for normal ops, but uses dynamic dispatch+/// instead of type parameters for its methods.+pub trait ResourceTable {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn close(&mut self, rid: ResourceId) -> Option<()>;+  fn get(&self, rid: ResourceId) -> Option<&dyn Resource>;+  fn get_mut(&mut self, rid: ResourceId) -> Option<&mut dyn Resource>;

They cannot. See comment at top of the file.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 impl Drop for PluginOpAsyncFuture {     self.fut.take();   } }++struct PluginResourceTable<'a> {+  inner: RefMut<'a, ResourceTable>,+  plugin_lib: &'a Rc<Library>,+}++impl<'a> PluginResourceTable<'a> {+  fn new(+    resource_table: &'a mut Rc<RefCell<ResourceTable>>,+    plugin_lib: &'a Rc<Library>,+  ) -> Self {+    Self {+      inner: resource_table.borrow_mut(),+      plugin_lib,+    }+  }+}++/// A resource that has been inserted in the resource table by a dynamically+/// loaded plugin.+struct RefResource {+  inner: Box<dyn Resource>,+  _plugin_lib: Rc<Library>,+}++impl<'a> plugin_api::ResourceTable for PluginResourceTable<'a> {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {+    // Resources inserted by plugins are wrapped in a RefResource wrapper, so+    // we can ensure a reference to Rc<Library> is kept for as long as the+    // resource stays in the resource table.

Oh i see what you mean. The PluginResourceTable object is really short lived -- it's basically a wrapper around RefMut<ResourceTable>. It gets dropped when an op returns.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 impl Drop for PluginOpAsyncFuture {     self.fut.take();   } }++struct PluginResourceTable<'a> {+  inner: RefMut<'a, ResourceTable>,+  plugin_lib: &'a Rc<Library>,+}++impl<'a> PluginResourceTable<'a> {+  fn new(+    resource_table: &'a mut Rc<RefCell<ResourceTable>>,+    plugin_lib: &'a Rc<Library>,+  ) -> Self {+    Self {+      inner: resource_table.borrow_mut(),+      plugin_lib,+    }+  }+}++/// A resource that has been inserted in the resource table by a dynamically+/// loaded plugin.+struct RefResource {+  inner: Box<dyn Resource>,+  _plugin_lib: Rc<Library>,+}++impl<'a> plugin_api::ResourceTable for PluginResourceTable<'a> {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {+    // Resources inserted by plugins are wrapped in a RefResource wrapper, so+    // we can ensure a reference to Rc<Library> is kept for as long as the+    // resource stays in the resource table.

No if you close the plugin resource then resources created by the op can still remain in the table.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Add APIs that give plugins access to the resource table

 pub type DispatchOpFn =  pub trait Interface {   fn register_op(&mut self, name: &str, dispatcher: DispatchOpFn) -> OpId;+  fn resource_table(&mut self) -> &mut dyn ResourceTable;+}++/// Similar to `struct ResourceTable` for normal ops, but uses dynamic dispatch+/// instead of type parameters for its methods.+pub trait ResourceTable {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn close(&mut self, rid: ResourceId) -> Option<()>;+  fn get(&self, rid: ResourceId) -> Option<&dyn Resource>;+  fn get_mut(&mut self, rid: ResourceId) -> Option<&mut dyn Resource>;+  fn has(&self, rid: ResourceId) -> bool;

Avoid what?

piscisaureus

comment created time in 9 days

delete branch piscisaureus/deno

delete branch : plugin_resource

delete time in 9 days

push eventpiscisaureus/deno

Bert Belder

commit sha de4e8f4a5f6aa4f8d8e6a11c8eb9bc6ccf1f692f

Test tweak

view details

push time in 9 days

push eventpiscisaureus/deno

Bert Belder

commit sha 1a63892dd2e6b511ddd88dbc5a8d6a43e8942422

Make that actually true...

view details

push time in 9 days

push eventpiscisaureus/deno

Bert Belder

commit sha 849bda6f3b043559e851df3756b42275ebd035dc

typo

view details

push time in 9 days

Pull request review commentdenoland/deno

Plugin resources (take 2)

 pub use crate::Buf; pub use crate::Op; pub use crate::OpId;+pub use crate::Resource;+pub use crate::ResourceId; pub use crate::ZeroCopyBuf; +use std::cell::Ref;+use std::cell::RefMut;+ pub type InitFn = fn(&mut dyn Interface);  pub type DispatchOpFn =   fn(&mut dyn Interface, &[u8], Option<ZeroCopyBuf>) -> Op; +/// Equivalent to ResourceTable for normal ops, but uses dynamic dispatch+/// rather than type parameters for the `get`, `get_mut`, and `remove` methods.+pub trait ResourceTable {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn get(&self, rid: ResourceId) -> Option<Ref<dyn Resource>>;

Fixed. Best of both worlds now.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Plugin resources (take 2)

 impl Drop for PluginOpAsyncFuture {     self.fut.take();   } }++/// A resource that has been inserted in the resource table by a dynamically+/// loaded plugin.+struct RefResource {+  inner: Box<dyn Resource>,+  _plugin_lib: Rc<Library>,+}++impl<'a> plugin_api::ResourceTable for PluginInterface<'a> {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {+    let ref_resource = RefResource {+      inner: resource,+      _plugin_lib: self.plugin_lib.clone(),+    };+    self.resource_table_mut().add(name, Box::new(ref_resource))+  }++  fn get(&self, rid: ResourceId) -> Option<Ref<dyn Resource>> {+    // Resources inserted by plugins are wrapped in a RefResource wrapper, so+    // we can ensure a reference to Rc<Library> is kept for as long as the+    // resource stays in the resource table.+    let table = self.resource_table();+    match table.get::<RefResource>(rid) {+      Some(_) => Some(Ref::map(table, |t| {+        &*t.get::<RefResource>(rid).unwrap().inner+      })),+      None => None,+    }+  }++  fn get_mut(&mut self, rid: ResourceId) -> Option<RefMut<dyn Resource>> {+    let mut table = self.resource_table_mut();+    match table.get_mut::<RefResource>(rid) {+      Some(_) => Some(RefMut::map(table, |t| {+        &mut *t.get_mut::<RefResource>(rid).unwrap().inner+      })),+      None => None,+    }+  }++  fn remove(&mut self, rid: ResourceId) -> Option<Box<dyn Resource>> {+    let mut table = self.resource_table_mut();+    match table.get_mut::<RefResource>(rid) {+      Some(_) => table.remove::<RefResource>(rid).map(|rc| rc.inner),+      None => None, // `rid` does not reference a RefResource, so leave it.

I made it so that 'close()' and 'has()' work for all types of resources. For get()/get_mut() that won't be possible because the actual ResourceTable doesn't support that.

piscisaureus

comment created time in 9 days

pull request commentdenoland/deno

Plugin resources (take 2)

@afinch7 I think it is very nice now.

piscisaureus

comment created time in 9 days

push eventpiscisaureus/deno

skdltmxn

commit sha 49c85a2c2396d6d010296503faf0b0b8712e9cd0

feat(std/hash): add md5 (#5719)

view details

Khang Dinh

commit sha 65f4e5912293bea5c59e2923cabfa8c0373a05a7

typos (#5713)

view details

Bert Belder

commit sha 86d113c9170624993d1c7684044feab10a60fdb0

Get rid of refcells

view details

Bert Belder

commit sha 6053240eef92b014f4473422751763a19cfd54a4

Merge remote-tracking branch 'origin/master'

view details

Bert Belder

commit sha fc532a3ad98de297221cab99a6b5f6a1eb8d0dea

Remove `remove()`, bless `close()`, tweaks

view details

push time in 9 days

create barnchpiscisaureus/deno

branch : plugin_resource

created branch time in 9 days

Pull request review commentdenoland/deno

Plugin resources (take 2)

 impl Drop for PluginOpAsyncFuture {     self.fut.take();   } }++/// A resource that has been inserted in the resource table by a dynamically+/// loaded plugin.+struct RefResource {+  inner: Box<dyn Resource>,+  _plugin_lib: Rc<Library>,+}++impl<'a> plugin_api::ResourceTable for PluginInterface<'a> {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {+    let ref_resource = RefResource {+      inner: resource,+      _plugin_lib: self.plugin_lib.clone(),+    };+    self.resource_table_mut().add(name, Box::new(ref_resource))+  }++  fn get(&self, rid: ResourceId) -> Option<Ref<dyn Resource>> {+    // Resources inserted by plugins are wrapped in a RefResource wrapper, so+    // we can ensure a reference to Rc<Library> is kept for as long as the+    // resource stays in the resource table.+    let table = self.resource_table();+    match table.get::<RefResource>(rid) {+      Some(_) => Some(Ref::map(table, |t| {+        &*t.get::<RefResource>(rid).unwrap().inner+      })),+      None => None,+    }+  }++  fn get_mut(&mut self, rid: ResourceId) -> Option<RefMut<dyn Resource>> {+    let mut table = self.resource_table_mut();+    match table.get_mut::<RefResource>(rid) {+      Some(_) => Some(RefMut::map(table, |t| {+        &mut *t.get_mut::<RefResource>(rid).unwrap().inner+      })),+      None => None,+    }+  }++  fn remove(&mut self, rid: ResourceId) -> Option<Box<dyn Resource>> {+    let mut table = self.resource_table_mut();+    match table.get_mut::<RefResource>(rid) {+      Some(_) => table.remove::<RefResource>(rid).map(|rc| rc.inner),+      None => None, // `rid` does not reference a RefResource, so leave it.

Well... that was not necessarily the intention here, but in the old code, the the resource was not a RefResource, it would remove the resource and then return None. That just seemed wrong.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Plugin resources (take 2)

 impl Drop for PluginOpAsyncFuture {     self.fut.take();   } }++/// A resource that has been inserted in the resource table by a dynamically+/// loaded plugin.+struct RefResource {+  inner: Box<dyn Resource>,+  _plugin_lib: Rc<Library>,+}++impl<'a> plugin_api::ResourceTable for PluginInterface<'a> {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {+    let ref_resource = RefResource {+      inner: resource,+      _plugin_lib: self.plugin_lib.clone(),+    };+    self.resource_table_mut().add(name, Box::new(ref_resource))+  }++  fn get(&self, rid: ResourceId) -> Option<Ref<dyn Resource>> {+    // Resources inserted by plugins are wrapped in a RefResource wrapper, so+    // we can ensure a reference to Rc<Library> is kept for as long as the+    // resource stays in the resource table.+    let table = self.resource_table();+    match table.get::<RefResource>(rid) {+      Some(_) => Some(Ref::map(table, |t| {+        &*t.get::<RefResource>(rid).unwrap().inner+      })),+      None => None,+    }+  }++  fn get_mut(&mut self, rid: ResourceId) -> Option<RefMut<dyn Resource>> {+    let mut table = self.resource_table_mut();+    match table.get_mut::<RefResource>(rid) {+      Some(_) => Some(RefMut::map(table, |t| {+        &mut *t.get_mut::<RefResource>(rid).unwrap().inner+      })),+      None => None,+    }+  }++  fn remove(&mut self, rid: ResourceId) -> Option<Box<dyn Resource>> {+    let mut table = self.resource_table_mut();+    match table.get_mut::<RefResource>(rid) {+      Some(_) => table.remove::<RefResource>(rid).map(|rc| rc.inner),

Or ... let's just remove the 'remove' function. get_mut() + close() should be enough.

piscisaureus

comment created time in 9 days

Pull request review commentdenoland/deno

Plugin resources (take 2)

 pub use crate::Buf; pub use crate::Op; pub use crate::OpId;+pub use crate::Resource;+pub use crate::ResourceId; pub use crate::ZeroCopyBuf; +use std::cell::Ref;+use std::cell::RefMut;+ pub type InitFn = fn(&mut dyn Interface);  pub type DispatchOpFn =   fn(&mut dyn Interface, &[u8], Option<ZeroCopyBuf>) -> Op; +/// Equivalent to ResourceTable for normal ops, but uses dynamic dispatch+/// rather than type parameters for the `get`, `get_mut`, and `remove` methods.+pub trait ResourceTable {+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn get(&self, rid: ResourceId) -> Option<Ref<dyn Resource>>;

What I like better about @afinch7's original patch is that get() (well, get_boxed() that is) returns an Option<&dyn Resource>.

Unfortunately the trade off there is that resource_table() returns some boxed contraption. Ideally resource_table() would return a RefMut<dyn plugin_api::ResourceTable> but that probably means the implementation of plugin_api::ResourceTable for core::ResourceTable needs to move to core; rust doesn't permit the impl trait to sit in cli because neither the trait nor the type it is implemented for are defined in cli (they're both in core).

piscisaureus

comment created time in 10 days

Pull request review commentdenoland/deno

feat: plugin resource access

 pub use crate::Buf; pub use crate::Op; pub use crate::OpId;+pub use crate::Resource;+pub use crate::ResourceId;+pub use crate::ResourceTable; pub use crate::ZeroCopyBuf;  pub type InitFn = fn(&mut dyn Interface);  pub type DispatchOpFn =   fn(&mut dyn Interface, &[u8], Option<ZeroCopyBuf>) -> Op; +/// Equivilent to ResourceTable for normal ops, but only includes+/// non generic("boxed") versions of get, get_mut, and remove.+/// We can't have generic functions on a trait and use it as a object+/// this is a limtation of rust.+pub trait WrappedResourceTable {+  fn has(&self, rid: ResourceId) -> bool;+  fn get_boxed(&self, rid: ResourceId) -> Option<&dyn Resource>;+  fn get_mut_boxed(&mut self, rid: ResourceId) -> Option<&mut dyn Resource>;+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn entries(&self) -> Vec<(ResourceId, String)>;

It might be helpful for testing. Any reason not to?

It's going to be a public API. The reason not to is that we only want to add things to the public API that we're willing to maintain forever.

We can consider this feature when someone brings up an important use case that really needs it. For testing we can have internal APis.

Also, if anything, it should be an iterator.

afinch7

comment created time in 10 days

pull request commentdenoland/deno

Plugin resources (take 2)

@afinch7 Would you mind reviewing this?

piscisaureus

comment created time in 10 days

PR opened denoland/deno

Plugin resources (take 2)

<!-- Before submitting a PR, please read https://github.com/denoland/deno/blob/master/docs/contributing.md -->

+148 -1

0 comment

4 changed files

pr created time in 10 days

create barnchpiscisaureus/deno

branch : plugin_resources

created branch time in 10 days

Pull request review commentdenoland/deno

feat: plugin resource access

 pub use crate::Buf; pub use crate::Op; pub use crate::OpId;+pub use crate::Resource;+pub use crate::ResourceId;+pub use crate::ResourceTable; pub use crate::ZeroCopyBuf;  pub type InitFn = fn(&mut dyn Interface);  pub type DispatchOpFn =   fn(&mut dyn Interface, &[u8], Option<ZeroCopyBuf>) -> Op; +/// Equivilent to ResourceTable for normal ops, but only includes+/// non generic("boxed") versions of get, get_mut, and remove.+/// We can't have generic functions on a trait and use it as a object+/// this is a limtation of rust.+pub trait WrappedResourceTable {+  fn has(&self, rid: ResourceId) -> bool;+  fn get_boxed(&self, rid: ResourceId) -> Option<&dyn Resource>;+  fn get_mut_boxed(&mut self, rid: ResourceId) -> Option<&mut dyn Resource>;+  fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId;+  fn entries(&self) -> Vec<(ResourceId, String)>;

Let's not give plugins access to that.

afinch7

comment created time in 10 days

Pull request review commentdenoland/deno

feat: plugin resource access

 impl PluginResource {   } } +/// Custom resource type used to ensure that a copy of the Rc<Library> for a plugin+/// is held with any resource inserted by that plugin to prevent segfaults.+struct RefResource {+  _lib: Rc<Library>,+  inner: Box<dyn Resource>,+}++struct PluginResourceTable<'a> {+  resource_table: RefMut<'a, ResourceTable>,+  lib: Rc<Library>,+}++impl<'a> plugin_api::WrappedResourceTable for PluginResourceTable<'a> {+  fn has(&self, rid: ResourceId) -> bool {+    self.resource_table.has(rid)+  }++  fn get_boxed(&self, rid: ResourceId) -> Option<&dyn Resource> {+    use std::borrow::Borrow;+    // Resources inserted by plugins are inserted in a RefResource wrapper, so+    // we can ensure a Rc<Library> is held for the plugin to avoid segfaults.+    // To keep this as similar as possible to the way that normal ops access+    // resources we need this wrapping to transparent. This just unwrapps all

unwraps

afinch7

comment created time in 10 days

more