2byte array causes stack overflow any ideas?

I try to implement a socks5 server using my own traits and the following code overflows the stack for some reason trying to read just 2 bytes

    pub async fn handshake<T>(mut rw: T) -> Result<(SocketAddr, UnamePasswd), SocksError>
    where
        T: SimpleAsyncWrite + SimpleAsyncRead + Unpin + Sync + Send,
    {
        Self::check_auth_methods(&mut rw).await?;
        let (uname, passwd) = Self::uname_passwd(&mut rw).await?;
        let addr = Self::get_connection_addr(&mut rw).await?;
        Ok((addr, UnamePasswd { uname, passwd }))
    }
    async fn check_auth_methods<T>(mut rw: T) -> Result<(), SocksError>
    where
        T: SimpleAsyncWrite + SimpleAsyncRead + Unpin,
    {
        //{{{
        let mut ver_nmethods = [0u8; 2];
        dbg!("here") //prints
        rw.read(&mut ver_nmethods).await?;//overflows
        if ver_nmethods[0] != 0x05 {
            return Err(SocksError::InvalidVersion(ver_nmethods[0]));
        }
        let mut methods = vec![0; ver_nmethods[1].into()];
        rw.read(&mut methods).await?;
        methods
            .iter()
            .find(|m| **m == 0x02) //uname password auth 0x02
            .ok_or(SocksError::NoUnamePass)?;
        rw.write(&[0x05, 0x02]).await?;
        Ok(())
    } //}}}

#[async_trait]
pub trait SimpleAsyncRead {
    async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>;
}
#[async_trait]
pub trait SimpleAsyncWrite {
    async fn write(&mut self, buf: &[u8]) -> io::Result<()>;
}

#[async_trait]
impl<T: SimpleAsyncRead + Sync + Send> SimpleAsyncRead for &mut T {
    async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        SimpleAsyncRead::read(self, buf).await
    }
}
#[async_trait]
impl<T: SimpleAsyncWrite + Sync + Send> SimpleAsyncWrite for &mut T {
    async fn write(&mut self, buf: &[u8]) -> io::Result<()> {
        SimpleAsyncWrite::write(self, buf).await
    }
}

#[async_trait]
impl SimpleAsyncWrite for TcpStream {
    async fn write(&mut self, buf: &[u8]) -> io::Result<()> {
        self.write_all(buf).await
    }
}
#[async_trait]
impl SimpleAsyncRead for TcpStream {
    async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.read_exact(buf).await
    }
}

This seems like an infinite recursive loop.

#[async_trait]
impl<T: SimpleAsyncRead + Sync + Send> SimpleAsyncRead for &mut T {
    async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        SimpleAsyncRead::read(self, buf).await
    }
}
1 Like

how can I communicate to the borrowchecker that both T and &mut T must be AsyncRead/Write? so it will be at compile time guaranteed bt the implementer?

Give this a try:

#[async_trait]
impl<T: SimpleAsyncRead + Sync + Send> SimpleAsyncRead for &mut T {
    async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        SimpleAsyncRead::read(&mut **self, buf).await
    }
}

The expression &mut **T should convert from &mut &mut T to &mut T.

1 Like

Just writing *self should work, too.

just *self also does the trick but in this case dont I create an extra copy of the thing to which updates will be commited instead of the original &mut self?

No, that's not what's happening. It will produce a &mut T to the same T as the &mut &mut T pointed at.

No, unless there’s a Copy bound on the type T, there’s no chance of accidentally copying anything. The only thing that will happen is that you’ll get a short-lived mutable reference to the same target of type T that the original double-indirection pointed to. When including lifetimes, such a dereference will turn &'a mut &'b mut T into &'a mut T where 'a is shorter-lived than 'b.

wheres the &mut &mut coming from I just get a &mut self?

If your self type is &mut T, then &mut self is a &mut &mut T.

1 Like

oh that makes sense thank you both @steffahn @alice

You can call T::read(self, buf) to make sure you're using the right implementation, or more explicitly <T as SimpleAsyncRead>::read(self, buf). Then self will auto-deref to the right thing, but you can also be explicit about that if you like.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.