Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::chain::webassembly::eosvmoc Namespace Reference

Classes

struct  eos_vm_oc_execution_interface
 
struct  eos_vm_oc_type_converter
 
class  eosvmoc_instantiated_module
 
class  eosvmoc_runtime
 
struct  result_resolver
 
struct  wasm_function_type_provider
 
struct  wasm_function_type_provider< Ret(Args...)>
 
struct  wasm_to_rvalue_type
 
struct  wasm_to_rvalue_type< F32 >
 
struct  wasm_to_rvalue_type< F64 >
 
struct  wasm_to_rvalue_type< U32 >
 
struct  wasm_to_rvalue_type< U64 >
 
struct  wasm_to_rvalue_type< void >
 
struct  wasm_to_value_type
 
struct  wasm_to_value_type< F32 >
 
struct  wasm_to_value_type< F64 >
 
struct  wasm_to_value_type< U32 >
 
struct  wasm_to_value_type< U64 >
 

Functions

template<typename T >
void * array_ptr_impl (size_t ptr, size_t length)
 
char * null_terminated_ptr_impl (uint64_t ptr)
 
auto convert_native_to_wasm (char *ptr)
 
template<typename Args , std::size_t... Is>
auto get_ct_args (std::index_sequence< Is... >)
 
uint32_t make_native_type (vm::i32_const_t x)
 
uint64_t make_native_type (vm::i64_const_t x)
 
float make_native_type (vm::f32_const_t x)
 
double make_native_type (vm::f64_const_t x)
 
template<typename TC , typename Args , std::size_t... Is>
auto get_ct_args_one (std::index_sequence< Is... >)
 
template<typename TC , typename T >
auto get_ct_args_i ()
 
template<auto F, typename Interface , typename Preconditions , bool is_injected, typename... A>
auto fn (A... a)
 
template<auto F, typename Preconditions , typename Args , bool is_injected, std::size_t... Is>
constexpr auto create_function (std::index_sequence< Is... >)
 
template<auto F, typename Preconditions , bool is_injected>
constexpr auto create_function ()
 
template<auto F, bool injected, typename Preconditions , typename Name >
void register_eosvm_oc (Name n)
 

Variables

template<typename T >
constexpr auto wasm_to_value_type_v = wasm_to_value_type<T>::value
 
template<typename T >
constexpr auto wasm_to_rvalue_type_v = wasm_to_rvalue_type<T>::value
 

Function Documentation

◆ array_ptr_impl()

template<typename T >
void * sysio::chain::webassembly::eosvmoc::array_ptr_impl ( size_t ptr,
size_t length )
inline

validate an in-wasm-memory array

Template Parameters
T

When a pointer will be invalid we want to stop execution right here right now. This is accomplished by forcing a read from an address that must always be bad. A better approach would probably be to call in to a function that notes the invalid parameter and host function and then bubbles up a more useful error message; maybe some day. Prior to WASM_LIMITS the code just simply did a load from address 33MB via an immediate. 33MB was always invalid since 33MB was the most WASM memory you could have. Post WASM_LIMITS you theoretically could have up to 4GB, but we can't do a load from a 4GB immediate since immediates are limited to signed 32bit ranges.

So instead access the first_invalid_memory_address which by its name will always be invalid. Or will it? No... it won't, since it's initialized to -1*64KB in the case WASM has no memory! We actually cannot clamp first_invalid_memory_address to 0 during initialization in such a case since there is some historical funny business going on when end==0 (note how jle will pass when end==0 & first_invalid_memory_address==0)

So instead just bump first_invalid_memory_address another 64KB before accessing it. If it's -64KB it'll go to 0 which fails correctly in that case. If it's 4GB it'll go to 4GB+64KB which still fails too (there is an entire 8GB range of WASM memory set aside). There are other more straightforward ways of accomplishing this, but at least this approach has zero overhead (e.g. no additional register usage, etc) in the nominal case.

Definition at line 63 of file sys-vm-oc.hpp.

64{
65 constexpr int cb_full_linear_memory_start_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(full_linear_memory_start);
66 constexpr int cb_first_invalid_memory_address_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(first_invalid_memory_address);
67
68 size_t end = ptr + length*sizeof(T);
69
70 asm volatile("cmp %%gs:%c[firstInvalidMemory], %[End]\n"
71 "jle 1f\n"
72 "mov %%gs:%c[firstInvalidMemory], %[End]\n" // sets End with a known failing address
73 "add %[sizeOfOneWASMPage], %[End]\n" // see above comment
74 "mov %%gs:(%[End]), %[Ptr]\n" // loads from the known failing address
75 "1:\n"
76 "add %%gs:%c[linearMemoryStart], %[Ptr]\n"
77 : [Ptr] "+r" (ptr),
78 [End] "+r" (end)
79 : [linearMemoryStart] "i" (cb_full_linear_memory_start_segment_offset),
80 [firstInvalidMemory] "i" (cb_first_invalid_memory_address_segment_offset),
81 [sizeOfOneWASMPage] "i" (wasm_constraints::wasm_page_size)
82 : "cc"
83 );
84
85
86 return (void*)ptr;
87}
#define OFFSET_OF_CONTROL_BLOCK_MEMBER(M)
Definition memory.hpp:66
#define T(meth, val, expected)
Here is the caller graph for this function:

◆ convert_native_to_wasm()

auto sysio::chain::webassembly::eosvmoc::convert_native_to_wasm ( char * ptr)
inline

Definition at line 122 of file sys-vm-oc.hpp.

122 {
123 constexpr int cb_full_linear_memory_start_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(full_linear_memory_start);
124 char* full_linear_memory_start;
125 asm("mov %%gs:%c[fullLinearMemOffset], %[fullLinearMem]\n"
126 : [fullLinearMem] "=r" (full_linear_memory_start)
127 : [fullLinearMemOffset] "i" (cb_full_linear_memory_start_offset)
128 );
129 U64 delta = (U64)(ptr - full_linear_memory_start);
130 return (U32)delta;
131}
uint64_t U64
Definition BasicTypes.h:11
uint32_t U32
Definition BasicTypes.h:9
Here is the caller graph for this function:

◆ create_function() [1/2]

template<auto F, typename Preconditions , bool is_injected>
auto sysio::chain::webassembly::eosvmoc::create_function ( )
constexpr

Definition at line 376 of file sys-vm-oc.hpp.

376 {
377 using native_args = vm::flatten_parameters_t<AUTO_PARAM_WORKAROUND(F)>;
378 using wasm_args = decltype(get_ct_args<native_args>(std::make_index_sequence<std::tuple_size_v<native_args>>()));
379 return create_function<F, Preconditions, wasm_args, is_injected>(std::make_index_sequence<std::tuple_size_v<wasm_args>>());
380}
decltype(flatten_parameters(AUTO_PARAM_WORKAROUND(FN))) flatten_parameters_t
#define AUTO_PARAM_WORKAROUND(X)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_function() [2/2]

template<auto F, typename Preconditions , typename Args , bool is_injected, std::size_t... Is>
auto sysio::chain::webassembly::eosvmoc::create_function ( std::index_sequence< Is... > )
constexpr

Definition at line 371 of file sys-vm-oc.hpp.

371 {
372 return &fn<F, webassembly::interface, Preconditions, is_injected, std::tuple_element_t<Is, Args>...>;
373}
Here is the call graph for this function:

◆ fn()

template<auto F, typename Interface , typename Preconditions , bool is_injected, typename... A>
auto sysio::chain::webassembly::eosvmoc::fn ( A... a)

Definition at line 336 of file sys-vm-oc.hpp.

336 {
337 try {
338 if constexpr(!is_injected) {
339 constexpr int cb_current_call_depth_remaining_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(current_call_depth_remaining);
340 constexpr int depth_assertion_intrinsic_offset = OFFSET_OF_FIRST_INTRINSIC - (int) find_intrinsic_index("eosvmoc_internal.depth_assert") * 8;
341
342 asm volatile("cmpl $1,%%gs:%c[callDepthRemainOffset]\n"
343 "jne 1f\n"
344 "callq *%%gs:%c[depthAssertionIntrinsicOffset]\n"
345 "1:\n"
346 :
347 : [callDepthRemainOffset] "i" (cb_current_call_depth_remaining_segment_offset),
348 [depthAssertionIntrinsicOffset] "i" (depth_assertion_intrinsic_offset)
349 : "cc");
350 }
351 using native_args = vm::flatten_parameters_t<AUTO_PARAM_WORKAROUND(F)>;
352 sysio::vm::native_value stack[] = { a... };
353 constexpr int cb_ctx_ptr_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(ctx);
354 apply_context* ctx;
355 asm("mov %%gs:%c[applyContextOffset], %[cPtr]\n"
356 : [cPtr] "=r" (ctx)
357 : [applyContextOffset] "i" (cb_ctx_ptr_offset)
358 );
359 Interface host(*ctx);
360 eos_vm_oc_type_converter tc{&host, eos_vm_oc_execution_interface{stack + sizeof...(A)}};
361 return result_resolver{tc}, sysio::vm::invoke_with_host<F, Preconditions, native_args>(tc, &host, std::make_index_sequence<sizeof...(A)>());
362 }
363 catch(...) {
364 *reinterpret_cast<std::exception_ptr*>(eos_vm_oc_get_exception_ptr()) = std::current_exception();
365 }
366 siglongjmp(*eos_vm_oc_get_jmp_buf(), SYSVMOC_EXIT_EXCEPTION);
367 __builtin_unreachable();
368}
#define OFFSET_OF_FIRST_INTRINSIC
Definition memory.hpp:67
sigjmp_buf * eos_vm_oc_get_jmp_buf()
void * eos_vm_oc_get_exception_ptr()
constexpr std::size_t find_intrinsic_index(std::string_view hf)
decltype(auto) invoke_with_host(Type_Converter &tc, Host *host, std::index_sequence< Is... >)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
schedule config_dir_name data_dir_name p2p_port http_port file_size name host(p2p_endpoint)) FC_REFLECT(tn_node_def
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_ct_args()

template<typename Args , std::size_t... Is>
auto sysio::chain::webassembly::eosvmoc::get_ct_args ( std::index_sequence< Is... > )

Definition at line 321 of file sys-vm-oc.hpp.

321 {
322 return std::tuple_cat(get_ct_args_i<eos_vm_oc_type_converter, std::tuple_element_t<Is, Args>>()...);
323}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_ct_args_i()

template<typename TC , typename T >
auto sysio::chain::webassembly::eosvmoc::get_ct_args_i ( )

Definition at line 311 of file sys-vm-oc.hpp.

311 {
312 if constexpr (vm::detail::has_from_wasm_v<T, TC>) {
314 return get_ct_args_one<TC, args_tuple>(std::make_index_sequence<std::tuple_size_v<args_tuple>>());
315 } else {
316 return std::tuple<decltype(make_native_type(std::declval<TC>().as_result(std::declval<T>())))>();
317 }
318}
strip_tag< flatten_parameters_t<&TC::template from_wasm< T > > > from_wasm_type_deducer_t
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_ct_args_one()

template<typename TC , typename Args , std::size_t... Is>
auto sysio::chain::webassembly::eosvmoc::get_ct_args_one ( std::index_sequence< Is... > )

Definition at line 306 of file sys-vm-oc.hpp.

306 {
307 return std::tuple<decltype(make_native_type(std::declval<TC>().as_result(std::declval<std::tuple_element_t<Is, Args>>())))...>();
308}
Here is the caller graph for this function:

◆ make_native_type() [1/4]

float sysio::chain::webassembly::eosvmoc::make_native_type ( vm::f32_const_t x)
inline

Definition at line 302 of file sys-vm-oc.hpp.

302{ return x.data.f; }

◆ make_native_type() [2/4]

double sysio::chain::webassembly::eosvmoc::make_native_type ( vm::f64_const_t x)
inline

Definition at line 303 of file sys-vm-oc.hpp.

303{ return x.data.f; }

◆ make_native_type() [3/4]

uint32_t sysio::chain::webassembly::eosvmoc::make_native_type ( vm::i32_const_t x)
inline

Definition at line 300 of file sys-vm-oc.hpp.

300{ return x.data.ui; }
Here is the caller graph for this function:

◆ make_native_type() [4/4]

uint64_t sysio::chain::webassembly::eosvmoc::make_native_type ( vm::i64_const_t x)
inline

Definition at line 301 of file sys-vm-oc.hpp.

301{ return x.data.ui; }

◆ null_terminated_ptr_impl()

char * sysio::chain::webassembly::eosvmoc::null_terminated_ptr_impl ( uint64_t ptr)
inline

validate an in-wasm-memory char array that must be null terminated

Definition at line 92 of file sys-vm-oc.hpp.

93{
94 constexpr int cb_full_linear_memory_start_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(full_linear_memory_start);
95 constexpr int cb_first_invalid_memory_address_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(first_invalid_memory_address);
96
97 char dumpster;
98 uint64_t scratch;
99
100 asm volatile("mov %%gs:(%[Ptr]), %[Dumpster]\n" //probe memory location at ptr to see if valid
101 "mov %%gs:%c[firstInvalidMemory], %[Scratch]\n" //get first invalid memory address
102 "cmpb $0, %%gs:-1(%[Scratch])\n" //is last byte in valid linear memory 0?
103 "je 2f\n" //if so, this will be a null terminated string one way or another
104 "mov %[Ptr],%[Scratch]\n"
105 "1:\n" //start loop looking for either 0, or until we SEGV
106 "inc %[Scratch]\n"
107 "cmpb $0,%%gs:-1(%[Scratch])\n"
108 "jne 1b\n"
109 "2:\n"
110 "add %%gs:%c[linearMemoryStart], %[Ptr]\n" //add address of linear memory 0 to ptr
111 : [Ptr] "+r" (ptr),
112 [Dumpster] "=r" (dumpster),
113 [Scratch] "=r" (scratch)
114 : [linearMemoryStart] "i" (cb_full_linear_memory_start_segment_offset),
115 [firstInvalidMemory] "i" (cb_first_invalid_memory_address_segment_offset)
116 : "cc"
117 );
118
119 return (char*)ptr;
120}
unsigned __int64 uint64_t
Definition stdint.h:136
Here is the caller graph for this function:

◆ register_eosvm_oc()

template<auto F, bool injected, typename Preconditions , typename Name >
void sysio::chain::webassembly::eosvmoc::register_eosvm_oc ( Name n)

Definition at line 383 of file sys-vm-oc.hpp.

383 {
384 // Has special handling
385 if(n == BOOST_HANA_STRING("env.sysio_exit")) return;
386 constexpr auto fn = create_function<F, Preconditions, injected>();
387 constexpr auto index = find_intrinsic_index(n.c_str());
388 intrinsic the_intrinsic(
389 n.c_str(),
390 wasm_function_type_provider<std::remove_pointer_t<decltype(fn)>>::type(),
391 reinterpret_cast<void*>(fn),
392 index
393 );
394}
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ wasm_to_rvalue_type_v

template<typename T >
auto sysio::chain::webassembly::eosvmoc::wasm_to_rvalue_type_v = wasm_to_rvalue_type<T>::value
constexpr

Definition at line 183 of file sys-vm-oc.hpp.

◆ wasm_to_value_type_v

template<typename T >
auto sysio::chain::webassembly::eosvmoc::wasm_to_value_type_v = wasm_to_value_type<T>::value
constexpr

Definition at line 156 of file sys-vm-oc.hpp.