-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Conversation
…mit. This also slightly reduces the amount of data that needs to be copied on module initialization.
- OC: Use indirect access when the mutable globals need more memory than is allocated statically.
…t during module instantiation, since they are no longer correct. We've already checked them during set code anyway.
Depends on #8223 and EOSIO/eos-vm#144 |
max_pages = config.max_pages; | ||
} | ||
mem.reset(max_pages); | ||
EOS_ASSERT(code.starting_memory_pages <= (int)max_pages, wasm_execution_error, "Initial memory out of range"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this line trying to detect when config.max_pages
has been shrunk since the wasm was instantiated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does that check need to happen here instead of a central location?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't a convenient central location to put it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like the check could be wasm_interface::apply()
(by way of placing starting memory pages in the wasm_cache_entry
). But this would incur an additional lookup every execution which would be unfortunate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a big problem with OC & a configurable call depth.
OC uses the native stack (unrelated to wasm stack). At the moment it ensures that no function uses more than 16KB of native stack. The idea is that 16KB*250 is ~4MB which is considerably less than default of 8MB stack across our supported platforms.
Increasing the call depth limit causes obvious problems here. Some improvements could be made, such as calculating more accurate stack usage based on the call graph. Could also try and use a separate stack for execution though that’s tricky for a few reasons and would still ultimately at the end of the day be a fixed size.
Unfortunately, since the depth limit can change transaction to transaction, it seems like OC would need to reevaluate limits each time the limit is changed.
max_call_depth = config.max_call_depth; | ||
max_pages = config.max_pages; | ||
} | ||
mem.reset(max_pages); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Far too dangerous IMO. Could fail to acquire the resources. Also I think if the limit is large (like 2GB or something) it won't even work as-is.
Probably beyond a certain threshold (could be 33MB, could be more, could be less) OC should switch to using mprotect()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it. The threshold for switching to mprotect can be configured at construction.
auto tableElementType = llvm::StructType::get(context,{llvmI8PtrType, llvmI64Type}); | ||
defaultTablePointer = emitLiteralPointer((void*)current_prologue,tableElementType->getPointerTo(256)); | ||
llvm::Type* tableArrayTy = llvm::ArrayType::get(tableElementType, module.tables.defs[0].type.size.min); | ||
defaultTablePointer = new llvm::GlobalVariable(*llvmModule, tableArrayTy, false, llvm::GlobalValue::ExternalLinkage, llvm::ConstantAggregateZero::get(tableArrayTy), getTableSymbolName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need to be marked ExternallyInitialized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. The external initialization should run after the the module is fully loaded.
@@ -133,7 +133,7 @@ namespace LLVMJIT | |||
if(SectionName == ".stack_sizes") { | |||
return stack_sizes.emplace_back(numBytes).data(); | |||
} | |||
WAVM_ASSERT_THROW(isReadOnly); | |||
//WAVM_ASSERT_THROW(isReadOnly); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's going on here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wasmTable is not in a read-only section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah okay. This is a safety check that llvm didn't generate a data section that it expects to write to. The table should be placed in a read only section, and the assert should go back in. AFAIK just setting the GlobalVariable const param to true and using private linkage works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I tried that, but eventually gave up. In order to make it const, the initialization can't be handled externally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a35f580 has an implementation that works.
Can you describe what the behavior is when shrinking a limit after a wasm has been accepted? For example if the initial data max is set to 128KB, my wasm has 96KB worth of data, and then the limit is changed to 64KB. |
The intent is that max_pages and max_call_depth are enforced on apply. The rest are enforced at set_code. |
It seems like wasm memory initialization & memory_api need to be checktime'd now. |
actually, I wonder if some other intrinsics are abusable at large memory sizes, 256MB, or such. |
We need to bump OC's codegen version. I think it's probably possible to keep original code running in this new version by doing things like moving |
For example, something like this will run way over a 30ms deadline on EOS VM JIT, and it's only double the current memory size. (module
(import "env" "eosio_assert" (func $eosio_assert (param i32) (param i32)))
(import "env" "memset" (func $memset (param i32) (param i32) (param i32) (result i32)))
(memory 1024)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(drop (call $memset (i32.const 0) (i32.const 0xff) (i32.const 67108863)))
(i32.store offset=67108860 (i32.const 0) (i32.const 0xffffffff))
(call $eosio_assert (i32.const 1) (i32.const 0))
)
) Can't help but wonder if allowing a knob to control memory limits opens pandora's box on new deadline overrun attacks. Is anyone even asking for more memory? |
I'm somewhat less concerned about deadline overruns, since this is primarily intended for private and permissioned chains. These parameters will definitely cause problems if they are set too high on a public chain. |
…is too high to be safe with the default stack.
…rotect to limit the number of segments when max_pages is changed.
@@ -0,0 +1,13 @@ | |||
.file "switch_stack_linux.s" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really linux only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not strictly linux only, but it won't work on OSX. The code is fine on OSX, but the file format is not.
|
||
template<typename F> | ||
void run(F&& f) { | ||
if (stack_top) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why conditionally gate this? Why not have the altstack used all the time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong opinion either way. It's mostly just to avoid an extra mmap when it isn't actually necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation of the new intrinsics seem to have been lost in the translation to the new host function system.
I haven't reviewed any of the changes relating to EOS VM OC (I will leave that to others). Also, I haven't yet reviewed the changes to the unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the fc submodule.
…ent to prevent a chain from being broken in an unrecoverable way.
…ion of validate to match.
Change Description
Consensus Changes
API Changes
Documentation Additions