Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: codecopy fails on high offset value #233

Closed
greged93 opened this issue Aug 30, 2023 · 11 comments · Fixed by #234
Closed

bug: codecopy fails on high offset value #233

greged93 opened this issue Aug 30, 2023 · 11 comments · Fixed by #234
Labels
bug Something isn't working

Comments

@greged93
Copy link
Contributor

Bug Report

Kakarot version: 32b516e

Current behavior:
The CODECOPY opcode will fail if provided with a high value for the offset argument. However, specs state that if offset is > bytecode length, 0s should simply be copied in the memory.

Expected behavior:
Testing with a high value for the bytecode offset should pass with memory being filled with 0s.

Steps to reproduce:

Add the below test to the suite of tests and run scarb test:

#[test]
#[available_gas(20000000)]
fn test_codecopy_error() {
    test_codecopy(0, 0xFFFFFFFD, 2)
}

Test should fail with

evm::tests::test_instructions::test_environment_information::test_codecopy_error - panicked with [155785504329508738615720351733824384887 ('u32_sub Overflow'), ].
@greged93 greged93 added the bug Something isn't working label Aug 30, 2023
@github-project-automation github-project-automation bot moved this to 🆕 Backlog in Kakarot on Starknet Aug 30, 2023
@greged93 greged93 added this to the Q4-2023 Bug Hunt 🐛 milestone Aug 30, 2023
@lambda-0x
Copy link
Contributor

lambda-0x commented Aug 30, 2023

@greged93 can you link which part of the spec says that?

EDIT: spec is kinda hard to read, but evm.codes confirms that it should copy 0's

@lambda-0x
Copy link
Contributor

lambda-0x commented Aug 30, 2023

panic is happening inside this branch, will open a PR with fix

let slice_size = if (offset + size > bytecode.len()) {
bytecode.len() - offset
} else {

@greged93
Copy link
Contributor Author

I think you need to be careful about offset + size as well. This is the way geth and reth handle this.

@lambda-0x
Copy link
Contributor

good point, also i am not sure why we are converting all offsets, and size variable inside implementation to u32 does spec says anything about what can be the maximum value of those variables?

geth and reth also are converting them to u64 and usize (which most probably is u64)

CC: @khaeljy @enitrat

@lambda-0x lambda-0x mentioned this issue Aug 30, 2023
2 tasks
@khaeljy
Copy link
Contributor

khaeljy commented Aug 30, 2023

Nice one!
I did test if offset + size > bytecode.len(), but I forgot to check if offset > bytecode.len()!

I use a u32 because bytecode is a Span, and Span is indexed in u32 in cairo (unless I'm mistaken).
This raises a broader question: wouldn't it be necessary to review the management of memory, call_data and bytecode to allow u64 indexing?

@lambda-0x
Copy link
Contributor

lambda-0x commented Aug 30, 2023

right, i came to same conclusion (#234 (comment)) when trying to test cases where offset + size > u32::MAX but due to indexing issue wasn't able to do it.

Is it possible to implement IndexView trait on Array and Span for u64 ourself?

@enitrat
Copy link
Contributor

enitrat commented Aug 30, 2023

Is it possible to implement IndexView trait on Array and Span for u64 outself?

I don't believe it is, at least I've never seen it

This raises a broader question: wouldn't it be necessary to review the management of memory, call_data and bytecode to allow u64 indexing?

A:

The MSTORE opcode stores 256 bits to memory and costs 3 units of gas and the gas limit of a transaction is 30 million, so if you put a maximum-sized transaction through you could store ~2.5 gigabits to memory. That would be pointless, though, since memory is volatile and that would all just poof away when the transaction was done and there's no room in that transaction for other operations to actually do anything with that data.

2.5 gigabits is 3.125e+8 bytes, which is way less than whatever a usize allows us to store, so I'm going to keep the memory usize-indexed

offset + size > u32::MAX

in practice that would never happen because the gas costs for this would be insanely high and beyond tx gas limits

@enitrat
Copy link
Contributor

enitrat commented Aug 30, 2023

I think you need to be careful about offset + size as well. This is the way geth and reth handle this.

I raised this in #203 (comment) aswell

@greged93
Copy link
Contributor Author

greged93 commented Aug 30, 2023

Offset is offset in bytecode no? So you could have high offset in bytecode (just because, doesn't cost anything) and low length. Then offset + size overflows

Concerning your comment 203, it concerns returndatacopy, but imo codecopy should not be able to fail in the same manner

@enitrat
Copy link
Contributor

enitrat commented Aug 31, 2023

imo codecopy should not be able to fail in the same manner

whh not? In both cases values from the stack can eventually be too high 🤔

@greged93
Copy link
Contributor Author

Well specs and evm codes dont mention any reverts on high values, too high of a code offset should be handled gracefully as here

@github-project-automation github-project-automation bot moved this from 🆕 Backlog to ✅ Done in Kakarot on Starknet Aug 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
No open projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants