Skip to content

Conversation

@g4titanx
Copy link
Member

resolves #324

now, i've got two major issues plaguing this pr. first is approval::test_approval failing with an empty return (ret=[]) instead of [0, ..., 0, 1] and erc20::deploy throwing an InvalidJump error. for approval, logs show modified _call correctly pushes 1, main_return aligns the stack to sp=1, and memory_write executes MSTORE with offset=0, but the EVM returns nothing, indicating MSTORE fails to write the padded 32-byte [0, ..., 0, 1] most likely due to improper stack value handling or memory misalignment.
the second one is InvalidJump in erc20.rs which originates from incorrect jump target relocation in target.rs, likely miscalculating offsets for function jumps (e.g., Func(19)), causing the EVM to hit an invalid JUMPDEST. the modified version of memory_write preserves stack values but haven’t resolved the padding issue, and jump relocation needs tighter bounds checking to prevent buffer overruns

@g4titanx
Copy link
Member Author

g4titanx commented Apr 15, 2025

have got this locally, didn't commit it because it has nothing to do with the current commit

/// Store data in memory with at current memory byte pointer.
    pub fn memory_write(&mut self, ty: impl Type) -> Result<MemoryInfo> {
        let size = ty.align();
        let offset = if size == 32 {
            tracing::trace!("Writing result at offset=0, size={}", size);
            // Pad I32 value to 32 bytes
            if self.sp() > 0 {
                // Duplicate stack value to preserve it
                self.dup(1)?;
                // Pop value to get it, pad to 32 bytes
                let value = vec![0; 28].into_iter().chain(vec![self.asm.sp as u8]).collect::<Vec<u8>>();
                self._drop()?; // Remove original value
                self.push(&value)?;
            }
            smallvec::smallvec![0]
        } else {
            let offset = self.mp.to_ls_bytes();
            self.increment_mp(size)?;
            offset
        };

        // Push offset and MSTORE
        self.push(&offset)?;
        self._mstore()?;

        Ok(MemoryInfo { offset, size })
    }

@g4titanx g4titanx changed the title fix(stack): stack management wrt dispatcher test fix(stack): stack management Apr 15, 2025
@clearloop
Copy link
Member

clearloop commented Apr 15, 2025

have got this locally, didn't issue because it has nothing to do with the current commit
...

you are trying to hardcode the PC in the method, which is not the ideal way to go, if you want to leave the PC on stack, register it to the jump table (use table.code_offset or table.label based on the problem), that when we trigger code relocation, the PC will get updated properly

pub fn relocate(&mut self, buffer: &mut Buffer) -> Result<()> {

Copy link
Member

@clearloop clearloop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we might not need to store the result of each call in memory but leave them on stack, because calls could be used as:

  • external call (part of the dispatcher)
  • internal call

instead, we can repeat the logic of storing result in memory for the main_return (in dispatcher), it increases the code size, but makes our stack management perfect

fn emit_selector(&mut self, selector: &wasm::Function<'_>, last: bool) -> Result<()> {

// Register the label to jump back.
let return_pc = self.masm.pc() + 2;
let return_pc = self.masm.pc() + 3;
self.masm.push(&return_pc.to_ls_bytes())?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as mentioned, this is a hard coded PC as well, which is not correct

@g4titanx
Copy link
Member Author

g4titanx commented May 17, 2025

todos (growing-list)

  • impl. correct comparison instructions
  • add stack stability tests(dispatcher tests, etc.)
  • proper PC logic
  • store result in memory- emit_selector only jumps to the internal function, but does not handle the return value after the jump. that means we are yet to implement the main_return logic to return values in memory for ABI i.e handle the return value ABI after calling a function.
  • fix tests to not expect return values on the stack

@AurelienFT
Copy link

Hello, @g4titanx I would like to start contributing to this project, just to confirm, this PR only need the tests to be updated to be ready ?If yes, I will give it a try sounds a great task to start

@g4titanx
Copy link
Member Author

g4titanx commented Sep 3, 2025

hello @AurelienFT, yes you can start working on this and for more clarity of what's to be done, you should check this #324

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce tests for making the stack check stable in compilation

3 participants