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