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

Async request sending can be interrupted, causing the connection to go out of sync with respect to packet boundaries #20

Closed
psychon opened this issue Jan 9, 2021 · 0 comments · Fixed by #21

Comments

@psychon
Copy link

psychon commented Jan 9, 2021

This is what I actually wanted to test when I ran into #19. The following is tested with my hack/patch from #19 (comment) to make async request sending actually work with partial writes.

This is the same example as in #19, but extended with a timeout. You might have to "play" a bit with the timeout value to make this break.

The idea is to send a big request with a timeout. The timeout should fire "in the middle" of request sending, so that the request was only sent partially. Since the timeout causes the request sending future to be just dropped, nothing can send the rest of the request. Thus, the partial write is never resolved and the X11 server cannot figure out where the next request begins (since it still expects more data from the last request).

use std::time::Duration;
use breadx::{DisplayConnection, ImageFormat, Image, drawable };
use smol::{Executor, Timer, future::race};

// async entry point
async fn entry() -> breadx::Result<()> {
    const WIDTH: usize = 997;
    const HEIGHT: usize = 1009;
    const MEMORY: [u8; WIDTH * HEIGHT * 4] = [0; WIDTH * HEIGHT * 4];

    let mut conn = DisplayConnection::create_async(None, None).await?;
    let image = Image::new(
        &conn,
        None,
        24,
        ImageFormat::ZPixmap,
        0,
        &MEMORY[..],
        WIDTH,
        HEIGHT,
        32,
        None,
    ).unwrap();
    let root = conn.default_root();
    let gc = conn.create_gc(root, Default::default())?;
    let pixmap = drawable::create_pixmap(&mut conn, root, WIDTH as _, HEIGHT as _, 24)?;
    for _ in 0..10 {
        let put = async {
            drawable::put_image_async(
                &mut conn,
                pixmap,
                gc,
                &image,
                0,
                0,
                0,
                0,
                WIDTH as _,
                HEIGHT as _,
            ).await.unwrap();
            "PutImage"
        };
        let timeout = async {
            Timer::after(Duration::from_millis(5)).await;
            "timeout"
        };
        println!("{:?}", race(put, timeout).await);
    }
    Ok(())
}

fn main() -> breadx::Result<()> {
    //std::env::set_var("RUST_LOG", "breadx=trace");
    env_logger::init();
    let ex = Executor::new();
    async_io::block_on(ex.run(entry())).unwrap();
    Ok(())
}

Under xtrace (and built with --release) this shows symptoms of the problem I described above:

000:<:0002: 16: Request(53): CreatePixmap depth=0x18 pid=0x02000002 drawable=0x00000761 width=997 height=1009
000:<: Warning: buffer filled!
000:<:0003:259244: Request(72): PutImage format=ZPixmap(0x02) drawable=0x02000002 gc=0x02000001 width=997 height=65 dst-x=0 dst-y=0 left-pad=0x00 depth=0x18
000:<: Warning: buffer filled!
000:<:0004:259244: Request(72): PutImage format=ZPixmap(0x02) drawable=0x02000002 gc=0x02000001 width=997 height=65 dst-x=0 dst-y=65 left-pad=0x00 depth=0x18
000:<: Warning: buffer filled!
000:<:0005:259244: Request(72): PutImage format=ZPixmap(0x02) drawable=0x02000002 gc=0x02000001 width=997 height=65 dst-x=0 dst-y=130 left-pad=0x00 depth=0x18
000:<: Warning: buffer filled!
000:<:0006:259244: Request(72): PutImage format=ZPixmap(0x02) drawable=0x02000002 gc=0x02000001 width=997 height=65 dst-x=0 dst-y=195 left-pad=0x00 depth=0x18
000:<: Warning: buffer filled!
000:<:0007:259244: Request(72): PutImage format=ZPixmap(0x02) drawable=0x02000002 gc=0x02000001 width=997 height=65 dst-x=0 dst-y=260 left-pad=0x00 depth=0x18
000:<: Warning: buffer filled!
000:<:0008:259244: Request(72): PutImage format=ZPixmap(0x02) drawable=0x02000002 gc=0x02000001 width=997 height=65 dst-x=0 dst-y=325 left-pad=0x00 depth=0x18
000:<: Warning: buffer filled!
000:<:0009:259244: Request(72): PutImage format=ZPixmap(0x02) drawable=0x02000002 gc=0x02000001 width=997 height=65 dst-x=0 dst-y=390 left-pad=0x00 depth=0x18
000:<: Warning: buffer filled!
000:<:000a:259244: Request(72): PutImage format=ZPixmap(0x02) drawable=0x02000002 gc=0x02000001 width=997 height=65 dst-x=0 dst-y=455 left-pad=0x00 depth=0x18
"timeout"
000:<:000b:  0: Request(0): UNKNOWN   
000:<: Warning: buffer filled!
000:<:000c:  0: Request(0): UNKNOWN   
"timeout"
"timeout"

When changing the value of MEMORY from 0 to 42, xtrace suddenly sees lots and lots of SetInputFocus requests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant