Description
Hi, I'm encountering an issue running rusty v8, version 0.82.0, on Linux (x86 64 bit). I'm writing a crate library that integrates v8 to implement a scripting feature. I've created a function to execute V8 scripts. In the function, I'm using sync::Once to ensure the platform is initialized only once. After that, I create an isolate, scope, compile code, etc. and it's fine. I can call the function more than once and it all works perfectly.
However, if I have two unit tests that call that function, I get a SIGSEGV: invalid memory reference
. My first thought was there was some sort of threading issue, but running with --test-threads=1
doesn't help. Below I've included a sample file demonstrating the issue.
I don't think I'm doing anything wrong, but I'm a Rust and V8 newbie, so any advice is appreciated. Obviously, writing unit tests to call V8 is a fringe case, but I want to make sure I'm not doing something else that is causing the SIGSEGV's once I release my library.
You can exercise by running the following:
cargo test
# executes two calls to v8 in the same functioncargo test -F individual
# executes two unit tests each calling V8, crashes with SIGSEGVcargo test -F individual -- --test-threads=1
# executes two unit tests each calling V8 with one thread, crashes with SIGSEGV
lib.rs
use std::sync::Once;
use uuid::Uuid;
static V8_INIT: Once = Once::new();
pub fn execute() -> String {
let callid = Uuid::new_v4().to_string();
println!();
println!("{} Before V8 call_once: {}", callid, V8_INIT.is_completed());
V8_INIT.call_once(|| {
// Initialize V8
println!("{} Beginning V8 init", callid);
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
println!("{} Completed V8 init", callid);
});
println!("{} After V8 call_once: {}", callid, V8_INIT.is_completed());
// Create a new Isolate and make it the current one.
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
// Create a stack-allocated handle scope.
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);
let code = String::from("(1 + 1).toString()");
// Compile and run the source code
let v8_code = v8::String::new(scope, &code).unwrap();
let script = v8::Script::compile(scope, v8_code, None).unwrap();
let value = script.run(scope).unwrap();
// Extract and return the results
let result = value.to_string(scope);
result.unwrap().to_rust_string_lossy(scope)
}
#[cfg(test)]
mod tests {
use crate::execute;
#[cfg(not(feature = "individual"))]
#[test]
fn test_attempt_combined() {
assert_eq!(execute(), "2");
assert_eq!(execute(), "2");
}
#[cfg(feature = "individual")]
#[test]
fn test_attempt_1() {
assert_eq!(execute(), "2");
}
#[cfg(feature = "individual")]
#[test]
fn test_attempt_2() {
assert_eq!(execute(), "2");
}
}
Cargo.toml
[package]
name = "v8-demo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
uuid = { version = "1.6.1", features = ["v4"] }
v8 = "0.82.0"
[features]
individual=[]
Output (two V8 calls in same test function)
$ cargo test
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running unittests src/lib.rs (target/debug/deps/v8_demo-b0467449950f74d0)
running 1 test
test tests::test_attempt_combined ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests v8-demo
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Output (two test functions calling V8 once)
$ cargo test
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running unittests src/lib.rs (target/debug/deps/v8_demo-b0467449950f74d0)
running 1 test
test tests::test_attempt_combined ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests v8-demo
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Output (two unit test functions calling V8 once)
$ cargo test -F individual
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running unittests src/lib.rs (target/debug/deps/v8_demo-baa9331bf38bd06c)
running 2 tests
error: test failed, to rerun pass `--lib`
Caused by:
process didn't exit successfully: `/mnt/data/projects/Personal/apicize/rust/@apicize/v8-demo/target/debug/deps/v8_demo-baa9331bf38bd06c` (signal: 11, SIGSEGV: invalid memory reference)
Output (two unit test functions calling V8 once, single thread)
$ cargo test -F individual -- --test-threads=1
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running unittests src/lib.rs (target/debug/deps/v8_demo-baa9331bf38bd06c)
running 2 tests
test tests::test_attempt_1 ... ok
test tests::test_attempt_2 ... error: test failed, to rerun pass `--lib`
Caused by:
process didn't exit successfully: `/mnt/data/projects/Personal/apicize/rust/@apicize/v8-demo/target/debug/deps/v8_demo-baa9331bf38bd06c --test-threads=1` (signal: 11, SIGSEGV: invalid memory reference)
Activity