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