ref-fvm icon indicating copy to clipboard operation
ref-fvm copied to clipboard

EVM Runtime: Runtime stack will panic from malformed asm

Open mriise opened this issue 3 years ago • 8 comments

EVM stack will panic with negative overflow if bytecode doesnt have all the values it expects to pop off. This will happen with malformed bytecode but we shouldn't panic from it. this can be done easily enough in asm with the return opcode by itself:

let evm_bytecode = "
{constructor bytecode omitted} 
return # runtime will panic
"; 

mriise avatar Sep 07 '22 22:09 mriise

In this case, we should probably check stack heights from the EVM dispatch code (we record the stack height requirements). That should make error handling simpler.

Stebalien avatar Sep 08 '22 22:09 Stebalien

This is likely to be prohibitively expensive.

Ideally we'd have guard pages around the stack and a proper segfault handler and.... oh wait, we are writing in this in rust. We should let the thing panic if it can.

vyzo avatar Sep 09 '22 04:09 vyzo

We should let the thing panic if it can.

This makes DELEGATECALL a bit tricker.

  • We can handle a panic (and, e.g., exit with the correct code).
  • We cannot recover from a panic (in rust).

This is likely to be prohibitively expensive.

if we do it right, it'll actually be faster. At the moment, every stack pop checks to make sure we have enough elements on the stack. If we check up-front (and convince the compiler to inline the instructions), we can elide all the individual checks.

Stebalien avatar Sep 09 '22 05:09 Stebalien

wait, why does it panic if it checks already?

Or is that check causing the panic?

In that case yes, we are already paying the prohibitive cost and doing the full stack check upfront will be faster if we can elide the subsequent checks.

vyzo avatar Sep 09 '22 05:09 vyzo

Or is that check causing the panic?

This. Rust is a memory-safe language.

Stebalien avatar Sep 09 '22 05:09 Stebalien

something or other people call it a fast language? :)

Joking aside, there has to be a way to do a single check upfront somehow.

vyzo avatar Sep 09 '22 05:09 vyzo

Yes. If you do a check up-front, rust will elide the other checks.

However, if you do this in two separate functions and rust doesn't inline the called function, it can't elide the checks.

One workaround is to pass in a fixed-sized "stack". Given that EVM operations specify how many elements they read/push, we can define Stack<N> object that's internally backed by a &[U256; N] array. If we pass that, the rust compiler should be able to get rid of the checks.

Stebalien avatar Sep 09 '22 05:09 Stebalien

#[inline] forces inlining even in nested functions no?

mriise avatar Sep 12 '22 18:09 mriise

@vyzo you've fixed this with the stack checks, right?

Stebalien avatar Oct 10 '22 04:10 Stebalien

(has that been merged and/or do you have a PR number?)

Stebalien avatar Oct 10 '22 04:10 Stebalien

hasnt been merged yet and i want to do the refactoring we discussed first, but yes, it will be fixed.

vyzo avatar Oct 10 '22 04:10 vyzo

ba 646

vyzo avatar Oct 10 '22 04:10 vyzo

@vyzo confirmed fixed?

Stebalien avatar Nov 29 '22 16:11 Stebalien

yes with 1-\epsilon, will add a regression test tonight.

vyzo avatar Nov 29 '22 16:11 vyzo