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

fix: bug with unaligned short read #1557

Merged
merged 15 commits into from
Apr 2, 2024
Merged

fix: bug with unaligned short read #1557

merged 15 commits into from
Apr 2, 2024

Conversation

austinabell
Copy link
Contributor

@austinabell austinabell commented Mar 15, 2024

So what's currently happening is when requesting an unaligned amount of bytes and the read is short, such that it crosses a word boundary, the guest will overwrite the last word with the lastword return from the host. This is a workaround to avoid changing the host.

Right now what this does is:

|----------request 15 bytes---------------|
|-----3x SyscallRecord words------|
00 01 02 03 04 05 06 07 08 09 0a 00

and then the last word writes over the end of the buffer, zeroing the bytes written in the last word until aligned:

                        |lastword-|
00 01 02 03 04 05 06 07 00 00 00 00

Alternative being the host doesn't statically set the guest memory based on #requested.floor_div(4), but instead only create a SyscallRecord with the full words written, and re-use this fill from last word logic.

|----------request 15 bytes---------------|
|--2x SyscallRecord---| |lastword|
00 01 02 03 04 05 06 07 08 09 0a

where currently what it does in this case (from changes in this PR) is just removing writing the lastword if a short read past a word boundary: Edit: this functionality was changed to write zero bytes in the lastword slot, such that zeroes are filled until the request length

|----------request 15 bytes---------------|
|-----3x SyscallRecord words------|
00 01 02 03 04 05 06 07 08 09 0a 00

Note that with this proposed implementation, as well as the current implementation, if a lot more bytes are requested than available, there are more words in the SyscallRecord created than necessary, setting all of the buffer bytes to 0. Unclear to me how much of an impact this has on proving.

|---------------request 19 bytes------------------------|
|----------4x SyscallRecord words-------------|
00 01 02 03 04 05 06 07 08 09 0a 00 00 00 00 00

I don't know what is more ideal, but hope this workaround or at least one of these tests is helpful. Those tests were just created to help narrow down the issue, happy to change them if this PR actually comes through :)

Copy link

vercel bot commented Mar 15, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
website ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 1, 2024 9:48pm

Copy link

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-1557.d1uc3c4lom8wx5.amplifyapp.com

assert_eq!(num_read, len as usize);
debug_assert!(num_read <= len as usize);
Copy link
Contributor

Choose a reason for hiding this comment

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

This debug_assert will get compiled into the guest. We should instead make the assert test the more accurate condition we need to check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah this was just changed because one of the tests doesn't uphold this (since it does a valid short read). Not sure why I switched it to a debug assert though, that was a mistype

Happy to refactor this if that test specifically is kept.

risc0/zkvm/src/host/server/exec/tests.rs Outdated Show resolved Hide resolved
risc0/zkvm/methods/guest/src/bin/multi_test.rs Outdated Show resolved Hide resolved
risc0/zkvm/src/host/server/exec/tests.rs Show resolved Hide resolved
risc0/zkvm/src/host/server/exec/tests.rs Show resolved Hide resolved
@nategraf
Copy link
Contributor

After discussion, we confirmed this issue but clarified the expected behavior. When the guest requests more data than the host provides, the circuit constrains the copy-in will overwrite exactly as many words as the number of bytes requested, rounded down to the nearest multiple of WORD_SIZE=4. In the code adjusted with 2e41d84, the guest upholds the simple invariant that it will overwrite the entire region pointed to in the sys_read request. When the host has less data to send, any data in the tail past what the host provides will be filled with zeroes, up to and including any trailing unaligned writes. (If we are being very precise, the host always provides exactly as much data as the guest requests, but it will set this tail to zeroes and return the length of meaningful data in it's return registers from the ecall)

@@ -44,6 +44,14 @@ fn main() {
let args: Vec<String> = std::env::args().collect();
risc0_zkvm::guest::env::commit(&args);
}
"BUF_READ" => {
use std::io::BufRead;
Copy link
Member

Choose a reason for hiding this comment

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

This should go to the top of file

Comment on lines 50 to 51
let mut reader =
std::io::BufReader::with_capacity(capacity, risc0_zkvm::guest::env::stdin());
Copy link
Member

Choose a reason for hiding this comment

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

A use would be good here

@nategraf
Copy link
Contributor

nategraf commented Apr 1, 2024

Looks like the Ethereum CI is failing with an issue on recursive checkout.
https://github.com/risc0/risc0/actions/runs/8514140789/job/23319263768?pr=1557#step:5:168

I am going to look into that issue. Also, I feel quite confident that this PR is not at risk of breaking the risc0-ethereum, so someone wants to hit the (red) merge button, feel free. I don't want to make that call by myself.

@flaub flaub merged commit a7000a9 into main Apr 2, 2024
34 of 36 checks passed
@flaub flaub deleted the austin/short_read_bugfix branch April 2, 2024 00:11
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.

3 participants