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

Add new test exposing mysterious bug #8

Merged
merged 1 commit into from
Sep 22, 2023

Conversation

marcospb19
Copy link
Contributor

@marcospb19 marcospb19 commented Sep 22, 2023

Hi, it's me once again 👋.

Tests are failing in ouch again so I went investigating and minifying the error, until I landed at this minimal repro test that exposes some mysterious bug.

Output looks duplicated and the other formats break when dealing with it.

assertion failed:
  left: [1, 2, 3]
 right: [1, 2, 3, 1, 2, 3]

Comment on lines +70 to +80
&mut write::Bz3Encoder::new(&mut output, 100 * KB).unwrap(),
)
.unwrap();

output
};

let decompressed = {
let mut output = vec![];
io::copy(
&mut read::Bz3Decoder::new(compressed.as_slice()).unwrap(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

To make sure that this test is coherent, you can apply these diffs:

- &mut write::Bz3Encoder::new(&mut output, 100 * KB).unwrap(),
+ &mut xz2::write::XzEncoder::new(&mut output, 6),

and

- &mut read::Bz3Decoder::new(compressed.as_slice()).unwrap(),
+ &mut xz2::read::XzDecoder::new(compressed.as_slice()),

Then run this:

cargo add --dev xz2
cargo test -- test_compressing_and_decompressing_small_input

And the test will pass, I am assuming xz2 is battle-tested and is behaving correctly right here.

@marcospb19 marcospb19 changed the title Add new test exposing misterious bug Add new test exposing mysterious bug Sep 22, 2023
@bczhc bczhc merged commit 4c3a8dd into bczhc:master Sep 22, 2023
1 check failed
@bczhc
Copy link
Owner

bczhc commented Sep 22, 2023

Ok merged. I'll take a look.

@bczhc
Copy link
Owner

bczhc commented Sep 22, 2023

Wait, you say the test in this PR will fail? But I tested it and no error encounters.

~/code/bzip3-rs master ⇡2 *1 ❯ cargo test test_compressing_and_decompressing_small_input                         16:36:55
warning: /home/bczhc/code/bzip3-rs/Cargo.toml: version requirement `0.3.3+1.3.2` for dependency `libbzip3-sys` includes semver metadata which will be ignored, removing the metadata is recommended to avoid confusion
    Finished test [unoptimized + debuginfo] target(s) in 0.18s
     Running unittests src/lib.rs (target/debug/deps/bzip3-bfe851b9cfe33af3)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/test.rs (target/debug/deps/test-b5911d9001814aa1)

running 1 test
test test_compressing_and_decompressing_small_input ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in 0.00s

~/code/bzip3-rs master ⇡2 *1 ❯ cargo test -r test_compressing_and_decompressing_small_input                      16:37:45
warning: /home/bczhc/code/bzip3-rs/Cargo.toml: version requirement `0.3.3+1.3.2` for dependency `libbzip3-sys` includes semver metadata which will be ignored, removing the metadata is recommended to avoid confusion
    Finished release [optimized] target(s) in 0.18s
     Running unittests src/lib.rs (target/release/deps/bzip3-a973389c0044f02a)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/test.rs (target/release/deps/test-7125935edaffd8d9)

running 1 test
test test_compressing_and_decompressing_small_input ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in 0.00s

@marcospb19
Copy link
Contributor Author

marcospb19 commented Sep 22, 2023

Yeah, it was failing here locally and well as in your CI, right?

@bczhc
Copy link
Owner

bczhc commented Sep 22, 2023

Weird. Failed in the CI, but OK on my side. Maybe this issue should be dug in some more.
image

@bczhc
Copy link
Owner

bczhc commented Sep 22, 2023

I think it only has something to do with the Rust toolchain version... I may need to do some bisecting. With the latest stable toolchain it passes; with the latest nightly toolchain it fails.

@bczhc
Copy link
Owner

bczhc commented Sep 22, 2023

cargo-bisect result:

Regression in https://github.com/rust-lang-ci/rust/commit/303fb317e843fae51e54a4b72960c5baaba9644b
==================================================================================
= Please file this regression report on the rust-lang/rust GitHub repository     =
=        New issue: https://github.com/rust-lang/rust/issues/new                 =
=     Known issues: https://github.com/rust-lang/rust/issues                     =
= Copy and paste the text below into the issue report thread.  Thanks!           =
==================================================================================

searched nightlies: from nightly-2022-11-21 to nightly-2023-09-21
regressed nightly: nightly-2023-07-10
searched commit range: https://github.com/rust-lang/rust/compare/83964c156db1f444050a38b2498dbd0da6d5d503...1065d876cdbc34a872b9e17c78caaa59ea0c94d4
regressed commit: https://github.com/rust-lang/rust/commit/a9eba8d793696d75c51a87ca731983bf5967028f

<details>
<summary>bisected with <a href='https://github.com/rust-lang/cargo-bisect-rustc'>cargo-bisect-rustc</a> v0.6.7</summary>


Host triple: x86_64-unknown-linux-gnu
Reproduce with:
```bash
cargo bisect-rustc -vv --start=2022-11-21 --end=2023-09-21 -- test -r --features bundled test_compressing_and_decompressing_small_input 
```
</details>

OMG I will figure out the root cause later...

@bczhc
Copy link
Owner

bczhc commented Sep 22, 2023

Using my own io_copy function, it can pass. This is a bit fascinating.

fn my_io_copy<R: Read, W: Write>(mut reader: R, mut writer: W) -> io::Result<()> {
    const BUF_SIZE: usize = 40960;
    let mut buf = [0_u8; BUF_SIZE];
    loop {
        let size = reader.read(&mut buf)?;
        if size == 0 {
            return Ok(());
        }
        writer.write_all(&buf[..size])?;
    }
}

@bczhc
Copy link
Owner

bczhc commented Sep 22, 2023

use std::io;
use std::io::Read;

fn main() {
    let mut reader = DemoReader::new();
    let mut vec = vec![];

    let len = io::copy(&mut reader, &mut vec).unwrap();
    println!("{} {:?}", len, vec);
}

/// Expect only one byte to read
struct DemoReader {
    n: u32,
}

impl DemoReader {
    fn new() -> DemoReader {
        Self { n: 0 }
    }
}

impl Read for DemoReader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        assert!(buf.len() > 1);
        println!("read call: {}, requested size: {}", self.n, buf.len());

        match self.n {
            0 => {
                buf[0] = 1;
                self.n += 1;
                Ok(1)
            }
            1 => {
                self.n += 1;
                Ok(0)
            }
            2 => {
                self.n += 1;
                buf[0] = 2;
                Ok(1)
            }
            3 => {
                self.n += 1;
                Ok(0)
            }
            _ => {
                unreachable!()
            }
        }
    }
}

Here's a demo code snippet. Before rust-lang/rust#113493, the output is:

read call: 0, requested size: 8192
read call: 1, requested size: 8192
1 [1]

After that PR, it outputs:

read call: 0, requested size: 8192
read call: 1, requested size: 8191
read call: 2, requested size: 8192
read call: 3, requested size: 16384
2 [1, 2]

Seems io::copy now won't stop immediately after a 0 read(..) return-value. And, if after an EOF (0 return-value) the read function still returns non-zero values, io::copy will continue reading it and filling the buffer. Maybe this is to meet https://doc.rust-lang.org/stable/src/std/io/mod.rs.html#585-588. But before this PR, the Rust doc also states like that, and I don't know how they handle this case (append more data after a File's EOF) before.

I would need to take some time to check more and find a solution later.

bczhc added a commit that referenced this pull request Sep 22, 2023
@bczhc
Copy link
Owner

bczhc commented Sep 22, 2023

I made a hurry fix... Check it out. Sorry for my limited time and I will leave my laptop for ~1day from now on.

@marcospb19 marcospb19 deleted the add-test-for-new-error branch September 22, 2023 15:48
@marcospb19
Copy link
Contributor Author

Thanks for the help, I'm still getting other errors and trying to solve them.

I'll let you know if I succeed.

@the8472
Copy link

the8472 commented Nov 4, 2023

Hi, the change in behavior was unintended. rust-lang/rust#117576 should fix it.
If in doubt feel free to report such things.

@bczhc
Copy link
Owner

bczhc commented Nov 4, 2023

Oh i see lol. Thanks @the8472!

bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 6, 2023
…lacrum

Fix excessive initialization and reads beyond EOF in `io::copy(_, Vec<u8>)` specialization

fixes rust-lang#117545 and bczhc/bzip3-rs#8
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Nov 15, 2023
Fix excessive initialization and reads beyond EOF in `io::copy(_, Vec<u8>)` specialization

fixes #117545 and bczhc/bzip3-rs#8
lnicola pushed a commit to lnicola/rust-analyzer that referenced this pull request Apr 7, 2024
Fix excessive initialization and reads beyond EOF in `io::copy(_, Vec<u8>)` specialization

fixes #117545 and bczhc/bzip3-rs#8
RalfJung pushed a commit to RalfJung/rust-analyzer that referenced this pull request Apr 27, 2024
Fix excessive initialization and reads beyond EOF in `io::copy(_, Vec<u8>)` specialization

fixes #117545 and bczhc/bzip3-rs#8
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