mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-23 15:50:11 -05:00
Add V8::set_entropy_source() (#460)
This commit is contained in:
parent
b31dbc89dc
commit
d60e367a9b
3 changed files with 103 additions and 0 deletions
46
src/V8.rs
46
src/V8.rs
|
@ -8,10 +8,12 @@ use std::vec::Vec;
|
|||
|
||||
use crate::platform::Platform;
|
||||
use crate::support::UniqueRef;
|
||||
use crate::support::UnitType;
|
||||
|
||||
extern "C" {
|
||||
fn v8__V8__SetFlagsFromCommandLine(argc: *mut c_int, argv: *mut *mut c_char);
|
||||
fn v8__V8__SetFlagsFromString(flags: *const u8, length: usize);
|
||||
fn v8__V8__SetEntropySource(callback: EntropySource);
|
||||
fn v8__V8__GetVersion() -> *const c_char;
|
||||
fn v8__V8__InitializePlatform(platform: *mut Platform);
|
||||
fn v8__V8__Initialize();
|
||||
|
@ -19,6 +21,42 @@ extern "C" {
|
|||
fn v8__V8__ShutdownPlatform();
|
||||
}
|
||||
|
||||
/// EntropySource is used as a callback function when v8 needs a source
|
||||
/// of entropy.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct EntropySource(RawEntropySource);
|
||||
|
||||
pub trait IntoEntropySource:
|
||||
UnitType + Into<EntropySource> + FnOnce(&mut [u8]) -> bool
|
||||
{
|
||||
}
|
||||
|
||||
impl<F> IntoEntropySource for F where
|
||||
F: UnitType + Into<EntropySource> + FnOnce(&mut [u8]) -> bool
|
||||
{
|
||||
}
|
||||
|
||||
type RawEntropySource = extern "C" fn(*mut u8, usize) -> bool;
|
||||
|
||||
impl<F> From<F> for EntropySource
|
||||
where
|
||||
F: UnitType + FnOnce(&mut [u8]) -> bool,
|
||||
{
|
||||
fn from(_: F) -> Self {
|
||||
#[inline(always)]
|
||||
extern "C" fn adapter<F: IntoEntropySource>(
|
||||
buffer: *mut u8,
|
||||
length: usize,
|
||||
) -> bool {
|
||||
let buffer = unsafe { std::slice::from_raw_parts_mut(buffer, length) };
|
||||
(F::get())(buffer)
|
||||
}
|
||||
|
||||
Self(adapter::<F>)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum GlobalState {
|
||||
Uninitialized,
|
||||
|
@ -87,6 +125,14 @@ pub fn set_flags_from_string(flags: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Allows the host application to provide a callback which can be used
|
||||
/// as a source of entropy for random number generators.
|
||||
pub fn set_entropy_source(
|
||||
callback: impl UnitType + Into<EntropySource> + FnOnce(&mut [u8]) -> bool,
|
||||
) {
|
||||
unsafe { v8__V8__SetEntropySource(callback.into()) };
|
||||
}
|
||||
|
||||
/// Get the version string.
|
||||
pub fn get_version() -> &'static str {
|
||||
let version = unsafe { v8__V8__GetVersion() };
|
||||
|
|
|
@ -97,6 +97,10 @@ void v8__V8__SetFlagsFromString(const char* flags, size_t length) {
|
|||
v8::V8::SetFlagsFromString(flags, length);
|
||||
}
|
||||
|
||||
void v8__V8__SetEntropySource(v8::EntropySource callback) {
|
||||
v8::V8::SetEntropySource(callback);
|
||||
}
|
||||
|
||||
const char* v8__V8__GetVersion() { return v8::V8::GetVersion(); }
|
||||
|
||||
void v8__V8__InitializePlatform(v8::Platform* platform) {
|
||||
|
|
53
tests/test_api_entropy_source.rs
Normal file
53
tests/test_api_entropy_source.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Tests from the same file run in a single process. That's why this test
|
||||
// is in its own file, because changing the entropy source affects the
|
||||
// whole process.
|
||||
use rusty_v8 as v8;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
static CALLS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[test]
|
||||
fn set_entropy_source() {
|
||||
const N: usize = 3;
|
||||
|
||||
v8::V8::set_entropy_source(|buf| {
|
||||
CALLS.fetch_add(1, Ordering::SeqCst);
|
||||
for c in buf {
|
||||
*c = 42;
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
v8::V8::initialize_platform(v8::new_default_platform().unwrap());
|
||||
v8::V8::initialize();
|
||||
|
||||
// Assumes that every isolate creates a PRNG from scratch, which is currently true.
|
||||
let mut results = vec![];
|
||||
for _ in 0..N {
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let source = v8::String::new(scope, "Math.random()").unwrap();
|
||||
let script = v8::Script::compile(scope, source, None).unwrap();
|
||||
let result = script.run(scope).unwrap();
|
||||
let result = result.to_string(scope).unwrap();
|
||||
let result = result.to_rust_string_lossy(scope);
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
v8::V8::dispose();
|
||||
}
|
||||
v8::V8::shutdown_platform();
|
||||
|
||||
// All runs should have produced the same value.
|
||||
assert_eq!(results.len(), N);
|
||||
results.dedup();
|
||||
assert_eq!(results.len(), 1);
|
||||
|
||||
// Doesn't have to be exactly N because V8 also calls
|
||||
// the EntropySource for things like hash seeds and ASLR.
|
||||
assert!(CALLS.load(Ordering::SeqCst) >= N);
|
||||
}
|
Loading…
Reference in a new issue