Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion framework/base/src/types/managed/managed_type_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub trait ManagedType<M: ManagedTypeApi>: Sized {
}

fn get_raw_handle(&self) -> RawHandle {
self.get_handle().cast_or_signal_error::<M, _>()
self.get_handle().get_raw_handle()
}

fn get_raw_handle_unchecked(&self) -> RawHandle {
Expand Down
3 changes: 3 additions & 0 deletions framework/scenario/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@ version = "=0.5.1"
[dependencies.multiversx-chain-vm]
version = "=0.22.0"
path = "../../chain/vm"

[dev-dependencies]
static_assertions = "1.1"
3 changes: 2 additions & 1 deletion framework/scenario/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ mod vm_api_vh;

pub(crate) use impl_vh::i32_to_bool;
pub use impl_vh::{
DebugApi, DebugApiBackend, DebugHandle, SingleTxApi, StaticApi, VMHooksApi, VMHooksApiBackend,
DebugApi, DebugApiBackend, DebugHandle, SingleTxApi, StaticApi, StaticApiHandle, VMHooksApi,
VMHooksApiBackend,
};
6 changes: 4 additions & 2 deletions framework/scenario/src/api/impl_vh.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
mod debug_api;
mod debug_handle_vh;
mod debug_handle;
mod single_tx_api;
mod static_api;
mod static_api_handle;
mod vh_single_tx_api;
mod vh_static_api;
mod vm_hooks_api;
mod vm_hooks_backend;

pub use debug_api::{DebugApi, DebugApiBackend};
pub use debug_handle_vh::DebugHandle;
pub use debug_handle::DebugHandle;
pub use single_tx_api::SingleTxApi;
pub use static_api::StaticApi;
pub use static_api_handle::StaticApiHandle;
pub use vh_single_tx_api::{SingleTxApiData, SingleTxApiVMHooksContext};
pub use vh_static_api::StaticApiVMHooksContext;
pub use vm_hooks_api::VMHooksApi;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::marker::PhantomData;
use std::sync::Weak;

use multiversx_chain_vm::host::context::{TxContext, TxContextRef};
Expand All @@ -14,6 +15,12 @@ pub struct DebugHandle {
/// Using the pointer after the context is released will panic.
pub(crate) context: Weak<TxContext>,
raw_handle: RawHandle,

/// This field causes DebugHandle not to be `Send` or `Sync`,
/// which is desirable since the handle is only valid on the thread of the original context.
///
/// This restriction is not enough to ensure safety (the context also helps), but it is an additional line of defense against misuse.
_phantom: PhantomData<*const ()>,
}

impl DebugHandle {
Expand All @@ -22,6 +29,7 @@ impl DebugHandle {
Self {
context,
raw_handle,
_phantom: PhantomData,
}
}

Expand Down Expand Up @@ -101,3 +109,13 @@ impl From<i32> for DebugHandle {
}

impl TryStaticCast for DebugHandle {}

#[cfg(test)]
mod tests {
use super::DebugHandle;

// DebugHandle intentionally does not implement Send or Sync
// (enforced via PhantomData<*const ()>), since a handle is only valid
// on the thread that created the underlying context.
static_assertions::assert_not_impl_any!(DebugHandle: Send, Sync);
}
9 changes: 6 additions & 3 deletions framework/scenario/src/api/impl_vh/static_api.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use multiversx_chain_vm::host::vm_hooks::VMHooksDispatcher;
use multiversx_chain_vm_executor::VMHooksEarlyExit;
use multiversx_sc::{api::RawHandle, types::Address};
use multiversx_sc::types::Address;
use std::sync::Mutex;

use crate::executor::debug::{StaticVarData, VMHooksDebugger};
use crate::{
api::StaticApiHandle,
executor::debug::{StaticVarData, VMHooksDebugger},
};

use super::{StaticApiVMHooksContext, VMHooksApi, VMHooksApiBackend};

Expand All @@ -21,7 +24,7 @@ thread_local! {
pub struct StaticApiBackend;

impl VMHooksApiBackend for StaticApiBackend {
type HandleType = RawHandle;
type HandleType = StaticApiHandle;

fn with_vm_hooks<R, F>(f: F) -> R
where
Expand Down
79 changes: 79 additions & 0 deletions framework/scenario/src/api/impl_vh/static_api_handle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use core::marker::PhantomData;

use multiversx_sc::{
api::{HandleConstraints, RawHandle},
codec::TryStaticCast,
};

#[derive(Clone)]
pub struct StaticApiHandle {
raw_handle: RawHandle,

/// This field causes StaticApiHandle not to be `Send` or `Sync`,
/// which is desirable since the handle is only valid on the thread of the original context.
_phantom: PhantomData<*const ()>,
}

impl StaticApiHandle {
/// Should almost never call directly, only used directly in a test.
pub fn new(raw_handle: RawHandle) -> Self {
Self {
raw_handle,
_phantom: PhantomData,
}
}
}

impl core::fmt::Debug for StaticApiHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
RawHandle::fmt(&self.raw_handle, f)
}
}

impl HandleConstraints for StaticApiHandle {
fn new(handle: multiversx_sc::api::RawHandle) -> Self {
StaticApiHandle::new(handle)
}

fn to_be_bytes(&self) -> [u8; 4] {
self.raw_handle.to_be_bytes()
}

fn get_raw_handle(&self) -> RawHandle {
self.raw_handle
}

fn get_raw_handle_unchecked(&self) -> RawHandle {
self.raw_handle
}
}

impl PartialEq<RawHandle> for StaticApiHandle {
fn eq(&self, other: &RawHandle) -> bool {
&self.raw_handle == other
}
}

impl PartialEq<StaticApiHandle> for StaticApiHandle {
fn eq(&self, other: &StaticApiHandle) -> bool {
self.raw_handle == other.raw_handle
}
}

impl From<i32> for StaticApiHandle {
fn from(handle: i32) -> Self {
StaticApiHandle::new(handle)
}
}

impl TryStaticCast for StaticApiHandle {}

#[cfg(test)]
mod tests {
use super::StaticApiHandle;

// StaticApiHandle intentionally does not implement Send or Sync
// (enforced via PhantomData<*const ()>), since a handle is only valid
// on the thread that created the underlying context.
static_assertions::assert_not_impl_any!(StaticApiHandle: Send, Sync);
}
4 changes: 4 additions & 0 deletions framework/scenario/tests/big_float_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use multiversx_sc::types::{BigFloat, BigInt, BigUint};
use multiversx_sc_scenario::api::StaticApi;

// BigFloat intentionally does not implement Send or Sync,
// since it holds a managed handle that is only valid on the thread of the original context.
static_assertions::assert_not_impl_any!(BigFloat::<StaticApi>: Send, Sync);

#[test]
fn big_float_overflow_test_rs() {
let exp = 1_080i32;
Expand Down
4 changes: 4 additions & 0 deletions framework/scenario/tests/big_int_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use multiversx_sc::types::BigInt;
use multiversx_sc_scenario::api::StaticApi;

// BigInt intentionally does not implement Send or Sync,
// since it holds a managed handle that is only valid on the thread of the original context.
static_assertions::assert_not_impl_any!(BigInt::<StaticApi>: Send, Sync);

#[test]
fn test_big_int_add() {
let x = BigInt::<StaticApi>::from(2);
Expand Down
4 changes: 4 additions & 0 deletions framework/scenario/tests/big_uint_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use multiversx_sc::types::BigUint;
use multiversx_sc_scenario::api::StaticApi;

// BigUint intentionally does not implement Send or Sync,
// since it holds a managed handle that is only valid on the thread of the original context.
static_assertions::assert_not_impl_any!(BigUint::<StaticApi>: Send, Sync);

fn assert_big_uint_ln(x: u32, ln_str: &str) {
let x = BigUint::<StaticApi>::from(x);
let ln_x = x.ln();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use multiversx_sc::{
api::ManagedTypeApi,
api::{HandleConstraints, ManagedTypeApi},
codec::{
self,
derive::{NestedDecode, NestedEncode, TopDecode, TopEncode},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use multiversx_sc::{
api::ManagedTypeApi,
api::{HandleConstraints, ManagedTypeApi},
codec::{
self,
derive::{NestedDecode, NestedEncode, TopDecode, TopEncode},
Expand Down
4 changes: 4 additions & 0 deletions framework/scenario/tests/managed_map_unit_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use multiversx_sc::types::{ManagedBuffer, ManagedMap};
use multiversx_sc_scenario::api::StaticApi;

// ManagedMap intentionally does not implement Send or Sync,
// since it holds a managed handle that is only valid on the thread of the original context.
static_assertions::assert_not_impl_any!(ManagedMap::<StaticApi>: Send, Sync);

#[test]
fn key_mutability_test() {
let mut map = ManagedMap::<StaticApi>::new();
Expand Down
4 changes: 4 additions & 0 deletions framework/scenario/tests/token_id_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ use multiversx_sc_scenario::{
multiversx_sc, token_id,
};

// TokenId intentionally does not implement Send or Sync,
// since it holds a managed handle that is only valid on the thread of the original context.
static_assertions::assert_not_impl_any!(TokenId::<StaticApi>: Send, Sync);

#[test]
fn test_egld() {
assert!(EgldOrEsdtTokenIdentifier::<StaticApi>::egld().is_egld());
Expand Down
8 changes: 8 additions & 0 deletions tools/managed-mem-bench/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ version = "0.1.0"
edition = "2024"
publish = false

[[bin]]
name = "bench-leak"
path = "src/bench_leak.rs"

[[bin]]
name = "bench-threading"
path = "src/bench_threading.rs"

[dependencies.multiversx-sc]
version = "0.65.0"
path = "../../framework/base"
Expand Down
Loading
Loading