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