|
5 | 5 | #include <fcntl.h>
|
6 | 6 | #include <limits.h>
|
7 | 7 | #include <linux/types.h>
|
| 8 | +#include <poll.h> |
8 | 9 | #include <sched.h>
|
9 | 10 | #include <signal.h>
|
10 | 11 | #include <stdio.h>
|
@@ -129,6 +130,7 @@ FIXTURE(child)
|
129 | 130 | * When it is closed, the child will exit.
|
130 | 131 | */
|
131 | 132 | int sk;
|
| 133 | + bool ignore_child_result; |
132 | 134 | };
|
133 | 135 |
|
134 | 136 | FIXTURE_SETUP(child)
|
@@ -165,10 +167,14 @@ FIXTURE_SETUP(child)
|
165 | 167 |
|
166 | 168 | FIXTURE_TEARDOWN(child)
|
167 | 169 | {
|
| 170 | + int ret; |
| 171 | + |
168 | 172 | EXPECT_EQ(0, close(self->pidfd));
|
169 | 173 | EXPECT_EQ(0, close(self->sk));
|
170 | 174 |
|
171 |
| - EXPECT_EQ(0, wait_for_pid(self->pid)); |
| 175 | + ret = wait_for_pid(self->pid); |
| 176 | + if (!self->ignore_child_result) |
| 177 | + EXPECT_EQ(0, ret); |
172 | 178 | }
|
173 | 179 |
|
174 | 180 | TEST_F(child, disable_ptrace)
|
@@ -235,6 +241,29 @@ TEST(flags_set)
|
235 | 241 | EXPECT_EQ(errno, EINVAL);
|
236 | 242 | }
|
237 | 243 |
|
| 244 | +TEST_F(child, no_strange_EBADF) |
| 245 | +{ |
| 246 | + struct pollfd fds; |
| 247 | + |
| 248 | + self->ignore_child_result = true; |
| 249 | + |
| 250 | + fds.fd = self->pidfd; |
| 251 | + fds.events = POLLIN; |
| 252 | + |
| 253 | + ASSERT_EQ(kill(self->pid, SIGKILL), 0); |
| 254 | + ASSERT_EQ(poll(&fds, 1, 5000), 1); |
| 255 | + |
| 256 | + /* |
| 257 | + * It used to be that pidfd_getfd() could race with the exiting thread |
| 258 | + * between exit_files() and release_task(), and get a non-null task |
| 259 | + * with a NULL files struct, and you'd get EBADF, which was slightly |
| 260 | + * confusing. |
| 261 | + */ |
| 262 | + errno = 0; |
| 263 | + EXPECT_EQ(sys_pidfd_getfd(self->pidfd, self->remote_fd, 0), -1); |
| 264 | + EXPECT_EQ(errno, ESRCH); |
| 265 | +} |
| 266 | + |
238 | 267 | #if __NR_pidfd_getfd == -1
|
239 | 268 | int main(void)
|
240 | 269 | {
|
|
0 commit comments