1 #![warn(rust_2018_idioms)]
2 #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi does not support panic recovery
3 #![cfg(panic = "unwind")]
4 
5 use std::task::{Context, Poll};
6 use std::{error::Error, pin::Pin};
7 use tokio::io::{self, split, AsyncRead, AsyncWrite, ReadBuf};
8 
9 mod support {
10     pub mod panic;
11 }
12 use support::panic::test_panic;
13 
14 struct RW;
15 
16 impl AsyncRead for RW {
poll_read( self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>17     fn poll_read(
18         self: Pin<&mut Self>,
19         _cx: &mut Context<'_>,
20         buf: &mut ReadBuf<'_>,
21     ) -> Poll<io::Result<()>> {
22         buf.put_slice(&[b'z']);
23         Poll::Ready(Ok(()))
24     }
25 }
26 
27 impl AsyncWrite for RW {
poll_write( self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &[u8], ) -> Poll<Result<usize, io::Error>>28     fn poll_write(
29         self: Pin<&mut Self>,
30         _cx: &mut Context<'_>,
31         _buf: &[u8],
32     ) -> Poll<Result<usize, io::Error>> {
33         Poll::Ready(Ok(1))
34     }
35 
poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>36     fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
37         Poll::Ready(Ok(()))
38     }
39 
poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>40     fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
41         Poll::Ready(Ok(()))
42     }
43 }
44 
45 #[cfg(unix)]
46 mod unix {
47     use std::os::unix::prelude::{AsRawFd, RawFd};
48 
49     pub struct MockFd;
50 
51     impl AsRawFd for MockFd {
as_raw_fd(&self) -> RawFd52         fn as_raw_fd(&self) -> RawFd {
53             0
54         }
55     }
56 }
57 
58 #[test]
read_buf_initialize_unfilled_to_panic_caller() -> Result<(), Box<dyn Error>>59 fn read_buf_initialize_unfilled_to_panic_caller() -> Result<(), Box<dyn Error>> {
60     let panic_location_file = test_panic(|| {
61         let mut buffer = Vec::<u8>::new();
62         let mut read_buf = ReadBuf::new(&mut buffer);
63 
64         read_buf.initialize_unfilled_to(2);
65     });
66 
67     // The panic location should be in this file
68     assert_eq!(&panic_location_file.unwrap(), file!());
69 
70     Ok(())
71 }
72 
73 #[test]
read_buf_advance_panic_caller() -> Result<(), Box<dyn Error>>74 fn read_buf_advance_panic_caller() -> Result<(), Box<dyn Error>> {
75     let panic_location_file = test_panic(|| {
76         let mut buffer = Vec::<u8>::new();
77         let mut read_buf = ReadBuf::new(&mut buffer);
78 
79         read_buf.advance(2);
80     });
81 
82     // The panic location should be in this file
83     assert_eq!(&panic_location_file.unwrap(), file!());
84 
85     Ok(())
86 }
87 
88 #[test]
read_buf_set_filled_panic_caller() -> Result<(), Box<dyn Error>>89 fn read_buf_set_filled_panic_caller() -> Result<(), Box<dyn Error>> {
90     let panic_location_file = test_panic(|| {
91         let mut buffer = Vec::<u8>::new();
92         let mut read_buf = ReadBuf::new(&mut buffer);
93 
94         read_buf.set_filled(2);
95     });
96 
97     // The panic location should be in this file
98     assert_eq!(&panic_location_file.unwrap(), file!());
99 
100     Ok(())
101 }
102 
103 #[test]
read_buf_put_slice_panic_caller() -> Result<(), Box<dyn Error>>104 fn read_buf_put_slice_panic_caller() -> Result<(), Box<dyn Error>> {
105     let panic_location_file = test_panic(|| {
106         let mut buffer = Vec::<u8>::new();
107         let mut read_buf = ReadBuf::new(&mut buffer);
108 
109         let new_slice = [0x40_u8, 0x41_u8];
110 
111         read_buf.put_slice(&new_slice);
112     });
113 
114     // The panic location should be in this file
115     assert_eq!(&panic_location_file.unwrap(), file!());
116 
117     Ok(())
118 }
119 
120 #[test]
unsplit_panic_caller() -> Result<(), Box<dyn Error>>121 fn unsplit_panic_caller() -> Result<(), Box<dyn Error>> {
122     let panic_location_file = test_panic(|| {
123         let (r1, _w1) = split(RW);
124         let (_r2, w2) = split(RW);
125         r1.unsplit(w2);
126     });
127 
128     // The panic location should be in this file
129     assert_eq!(&panic_location_file.unwrap(), file!());
130 
131     Ok(())
132 }
133 
134 #[test]
135 #[cfg(unix)]
async_fd_new_panic_caller() -> Result<(), Box<dyn Error>>136 fn async_fd_new_panic_caller() -> Result<(), Box<dyn Error>> {
137     use tokio::io::unix::AsyncFd;
138     use tokio::runtime::Builder;
139 
140     let panic_location_file = test_panic(|| {
141         // Runtime without `enable_io` so it has no IO driver set.
142         let rt = Builder::new_current_thread().build().unwrap();
143         rt.block_on(async {
144             let fd = unix::MockFd;
145 
146             let _ = AsyncFd::new(fd);
147         });
148     });
149 
150     // The panic location should be in this file
151     assert_eq!(&panic_location_file.unwrap(), file!());
152 
153     Ok(())
154 }
155 
156 #[test]
157 #[cfg(unix)]
async_fd_with_interest_panic_caller() -> Result<(), Box<dyn Error>>158 fn async_fd_with_interest_panic_caller() -> Result<(), Box<dyn Error>> {
159     use tokio::io::unix::AsyncFd;
160     use tokio::io::Interest;
161     use tokio::runtime::Builder;
162 
163     let panic_location_file = test_panic(|| {
164         // Runtime without `enable_io` so it has no IO driver set.
165         let rt = Builder::new_current_thread().build().unwrap();
166         rt.block_on(async {
167             let fd = unix::MockFd;
168 
169             let _ = AsyncFd::with_interest(fd, Interest::READABLE);
170         });
171     });
172 
173     // The panic location should be in this file
174     assert_eq!(&panic_location_file.unwrap(), file!());
175 
176     Ok(())
177 }
178 
179 #[test]
180 #[cfg(unix)]
async_fd_try_new_panic_caller() -> Result<(), Box<dyn Error>>181 fn async_fd_try_new_panic_caller() -> Result<(), Box<dyn Error>> {
182     use tokio::io::unix::AsyncFd;
183     use tokio::runtime::Builder;
184 
185     let panic_location_file = test_panic(|| {
186         // Runtime without `enable_io` so it has no IO driver set.
187         let rt = Builder::new_current_thread().build().unwrap();
188         rt.block_on(async {
189             let fd = unix::MockFd;
190 
191             let _ = AsyncFd::try_new(fd);
192         });
193     });
194 
195     // The panic location should be in this file
196     assert_eq!(&panic_location_file.unwrap(), file!());
197 
198     Ok(())
199 }
200 
201 #[test]
202 #[cfg(unix)]
async_fd_try_with_interest_panic_caller() -> Result<(), Box<dyn Error>>203 fn async_fd_try_with_interest_panic_caller() -> Result<(), Box<dyn Error>> {
204     use tokio::io::unix::AsyncFd;
205     use tokio::io::Interest;
206     use tokio::runtime::Builder;
207 
208     let panic_location_file = test_panic(|| {
209         // Runtime without `enable_io` so it has no IO driver set.
210         let rt = Builder::new_current_thread().build().unwrap();
211         rt.block_on(async {
212             let fd = unix::MockFd;
213 
214             let _ = AsyncFd::try_with_interest(fd, Interest::READABLE);
215         });
216     });
217 
218     // The panic location should be in this file
219     assert_eq!(&panic_location_file.unwrap(), file!());
220 
221     Ok(())
222 }
223