475 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			475 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Check decoding of select/_newselect syscalls.
 | |
|  *
 | |
|  * Copyright (c) 2015-2018 Dmitry V. Levin <ldv@altlinux.org>
 | |
|  * Copyright (c) 2015-2017 The strace developers.
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  * 3. The name of the author may not be used to endorse or promote products
 | |
|  *    derived from this software without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | |
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Based on test by Dr. David Alan Gilbert <dave@treblig.org>
 | |
|  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <limits.h>
 | |
| #include <stdint.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/select.h>
 | |
| 
 | |
| static const char *errstr;
 | |
| 
 | |
| static long
 | |
| xselect(const kernel_ulong_t nfds,
 | |
| 	const kernel_ulong_t rs,
 | |
| 	const kernel_ulong_t ws,
 | |
| 	const kernel_ulong_t es,
 | |
| 	const kernel_ulong_t tv)
 | |
| #ifndef xselect
 | |
| {
 | |
| 	long rc = syscall(TEST_SYSCALL_NR,
 | |
| 			  F8ILL_KULONG_MASK | nfds, rs, ws, es, tv);
 | |
| 	errstr = sprintrc(rc);
 | |
| 	return rc;
 | |
| }
 | |
| #else
 | |
| 	;
 | |
| #endif
 | |
| 
 | |
| #define XSELECT(expected_, ...)						\
 | |
| 	do {								\
 | |
| 		long rc = xselect(__VA_ARGS__);				\
 | |
| 		if (rc != (expected_))					\
 | |
| 			perror_msg_and_fail(TEST_SYSCALL_STR		\
 | |
| 					    ": expected %d"		\
 | |
| 					    ", returned %ld",		\
 | |
| 					    (expected_), rc);		\
 | |
| 	} while (0)							\
 | |
| /* End of XSELECT definition. */
 | |
| 
 | |
| int
 | |
| main(void)
 | |
| {
 | |
| #ifdef PATH_TRACING_FD
 | |
| 	skip_if_unavailable("/proc/self/fd/");
 | |
| #endif
 | |
| 
 | |
| 	for (int i = 3; i < FD_SETSIZE; ++i) {
 | |
| #ifdef PATH_TRACING_FD
 | |
| 		if (i == PATH_TRACING_FD)
 | |
| 			continue;
 | |
| #endif
 | |
| 		(void) close(i);
 | |
| 	}
 | |
| 
 | |
| 	int fds[2];
 | |
| 	if (pipe(fds))
 | |
| 		perror_msg_and_fail("pipe");
 | |
| 
 | |
| 	static const int smallset_size = sizeof(kernel_ulong_t) * 8;
 | |
| 	const int nfds = fds[1] + 1;
 | |
| 	if (nfds > smallset_size)
 | |
| 		error_msg_and_fail("nfds[%d] > smallset_size[%d]\n",
 | |
| 				   nfds, smallset_size);
 | |
| 
 | |
| 	struct timeval tv_in = { 0, 123 };
 | |
| 	struct timeval *const tv = tail_memdup(&tv_in, sizeof(tv_in));
 | |
| 	const uintptr_t a_tv = (uintptr_t) tv;
 | |
| 
 | |
| 	TAIL_ALLOC_OBJECT_VAR_PTR(kernel_ulong_t, l_rs);
 | |
| 	fd_set *const rs = (void *) l_rs;
 | |
| 	const uintptr_t a_rs = (uintptr_t) rs;
 | |
| 
 | |
| 	TAIL_ALLOC_OBJECT_VAR_PTR(kernel_ulong_t, l_ws);
 | |
| 	fd_set *const ws = (void *) l_ws;
 | |
| 	const uintptr_t a_ws = (uintptr_t) ws;
 | |
| 
 | |
| 	TAIL_ALLOC_OBJECT_VAR_PTR(kernel_ulong_t, l_es);
 | |
| 	fd_set *const es = (void *) l_es;
 | |
| 	const uintptr_t a_es = (uintptr_t) es;
 | |
| 
 | |
| 	long rc;
 | |
| 
 | |
| 	/*
 | |
| 	 * An equivalent of nanosleep.
 | |
| 	 */
 | |
| 	if (xselect(0, 0, 0, 0, a_tv)) {
 | |
| 		if (errno == ENOSYS)
 | |
| 			perror_msg_and_skip(TEST_SYSCALL_STR);
 | |
| 		else
 | |
| 			perror_msg_and_fail(TEST_SYSCALL_STR);
 | |
| 	}
 | |
| #ifndef PATH_TRACING_FD
 | |
| 	printf("%s(0, NULL, NULL, NULL, {tv_sec=%lld, tv_usec=%llu})"
 | |
| 	       " = 0 (Timeout)\n",
 | |
| 	       TEST_SYSCALL_STR, (long long) tv_in.tv_sec,
 | |
| 	       zero_extend_signed_to_ull(tv_in.tv_usec));
 | |
| #endif
 | |
| 
 | |
| 	/* EFAULT on tv argument */
 | |
| 	XSELECT(-1, 0, 0, 0, 0, a_tv + 1);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 	printf("%s(0, NULL, NULL, NULL, %#lx) = %s\n",
 | |
| 	       TEST_SYSCALL_STR, (unsigned long) a_tv + 1, errstr);
 | |
| #endif
 | |
| 
 | |
| 	/*
 | |
| 	 * Start with a nice simple select with the same set.
 | |
| 	 */
 | |
| 	for (int i = nfds; i <= smallset_size; ++i) {
 | |
| 		*l_rs = (1UL << fds[0]) | (1UL << fds[1]);
 | |
| 		XSELECT(1, i, a_rs, a_rs, a_rs, 0);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, [%d %d], [%d %d], [%d %d], NULL) = 1 ()\n",
 | |
| 		       TEST_SYSCALL_STR, i, fds[0], fds[1],
 | |
| 		       fds[0], fds[1], fds[0], fds[1]);
 | |
| #else
 | |
| 		*l_rs = (1UL << fds[0]) | (1UL << fds[1]) |
 | |
| 			(1UL << PATH_TRACING_FD);
 | |
| 		XSELECT(i > PATH_TRACING_FD ? 3 : 1, i, a_rs, a_rs, a_rs, 0);
 | |
| 		if (i > PATH_TRACING_FD) {
 | |
| 			printf("%s(%d, [%d %d %d], [%d %d %d], [%d %d %d]"
 | |
| 			       ", NULL) = 3 ()\n",
 | |
| 			       TEST_SYSCALL_STR, i,
 | |
| 			       fds[0], fds[1], PATH_TRACING_FD,
 | |
| 			       fds[0], fds[1], PATH_TRACING_FD,
 | |
| 			       fds[0], fds[1], PATH_TRACING_FD);
 | |
| 		}
 | |
| #endif
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Odd timeout.
 | |
| 	 */
 | |
| 	*l_rs = (1UL << fds[0]) | (1UL << fds[1]);
 | |
| 	tv_in.tv_sec = 0xdeadbeefU;
 | |
| 	tv_in.tv_usec = 0xfacefeedU;
 | |
| 	memcpy(tv, &tv_in, sizeof(tv_in));
 | |
| 	rc = xselect(nfds, a_rs, a_rs, a_rs, a_tv);
 | |
| 	if (rc < 0) {
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, [%d %d], [%d %d], [%d %d]"
 | |
| 		       ", {tv_sec=%lld, tv_usec=%llu}) = %s\n",
 | |
| 		       TEST_SYSCALL_STR, nfds, fds[0], fds[1],
 | |
| 		       fds[0], fds[1], fds[0], fds[1],
 | |
| 		       (long long) tv_in.tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv_in.tv_usec),
 | |
| 		       errstr);
 | |
| #endif /* !PATH_TRACING_FD */
 | |
| 	} else {
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, [%d %d], [%d %d], [%d %d]"
 | |
| 		       ", {tv_sec=%lld, tv_usec=%llu}) = %ld"
 | |
| 		       " (left {tv_sec=%lld, tv_usec=%llu})\n",
 | |
| 		       TEST_SYSCALL_STR, nfds, fds[0], fds[1],
 | |
| 		       fds[0], fds[1], fds[0], fds[1],
 | |
| 		       (long long) tv_in.tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv_in.tv_usec),
 | |
| 		       rc, (long long) tv->tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv->tv_usec));
 | |
| #endif /* !PATH_TRACING_FD */
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Very odd timeout.
 | |
| 	 */
 | |
| 	*l_rs = (1UL << fds[0]) | (1UL << fds[1]);
 | |
| 	tv_in.tv_sec = (time_t) 0xcafef00ddeadbeefLL;
 | |
| 	tv_in.tv_usec = (suseconds_t) 0xbadc0dedfacefeedLL;
 | |
| 	memcpy(tv, &tv_in, sizeof(tv_in));
 | |
| 	rc = xselect(nfds, a_rs, a_rs, a_rs, a_tv);
 | |
| 	if (rc < 0) {
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, [%d %d], [%d %d], [%d %d]"
 | |
| 		       ", {tv_sec=%lld, tv_usec=%llu}) = %s\n",
 | |
| 		       TEST_SYSCALL_STR, nfds, fds[0], fds[1],
 | |
| 		       fds[0], fds[1], fds[0], fds[1],
 | |
| 		       (long long) tv_in.tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv_in.tv_usec),
 | |
| 		       errstr);
 | |
| #endif /* PATH_TRACING_FD */
 | |
| 	} else {
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, [%d %d], [%d %d], [%d %d]"
 | |
| 		       ", {tv_sec=%lld, tv_usec=%llu}) = %ld"
 | |
| 		       " (left {tv_sec=%lld, tv_usec=%llu})\n",
 | |
| 		       TEST_SYSCALL_STR, nfds, fds[0], fds[1],
 | |
| 		       fds[0], fds[1], fds[0], fds[1],
 | |
| 		       (long long) tv_in.tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv_in.tv_usec),
 | |
| 		       rc, (long long) tv->tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv->tv_usec));
 | |
| #endif /* PATH_TRACING_FD */
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Another simple one, with a timeout.
 | |
| 	 */
 | |
| 	for (int i = nfds; i <= smallset_size; ++i) {
 | |
| 		*l_rs = (1UL << fds[0]) | (1UL << fds[1]);
 | |
| 		*l_ws = (1UL << 1) | (1UL << 2) |
 | |
| 			(1UL << fds[0]) | (1UL << fds[1]);
 | |
| 		*l_es = 0;
 | |
| 		tv_in.tv_sec = 0xc0de1;
 | |
| 		tv_in.tv_usec = 0xc0de2;
 | |
| 		memcpy(tv, &tv_in, sizeof(tv_in));
 | |
| 		XSELECT(3, i, a_rs, a_ws, a_es, a_tv);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, [%d %d], [%d %d %d %d], []"
 | |
| 		       ", {tv_sec=%lld, tv_usec=%llu}) = 3 (out [1 2 %d]"
 | |
| 		       ", left {tv_sec=%lld, tv_usec=%llu})\n",
 | |
| 		       TEST_SYSCALL_STR, i, fds[0], fds[1],
 | |
| 		       1, 2, fds[0], fds[1],
 | |
| 		       (long long) tv_in.tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv_in.tv_usec),
 | |
| 		       fds[1],
 | |
| 		       (long long) tv->tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv->tv_usec));
 | |
| #else
 | |
| 		*l_rs = (1UL << fds[0]) | (1UL << fds[1]) |
 | |
| 			(1UL << PATH_TRACING_FD);
 | |
| 		*l_ws = (1UL << 1) | (1UL << 2) |
 | |
| 			(1UL << fds[0]) | (1UL << fds[1]);
 | |
| 		tv_in.tv_sec = 0xc0de1;
 | |
| 		tv_in.tv_usec = 0xc0de2;
 | |
| 		memcpy(tv, &tv_in, sizeof(tv_in));
 | |
| 		XSELECT(3 + (i > PATH_TRACING_FD), i, a_rs, a_ws, a_es, a_tv);
 | |
| 		if (i > PATH_TRACING_FD) {
 | |
| 			printf("%s(%d, [%d %d %d], [%d %d %d %d], []"
 | |
| 			       ", {tv_sec=%lld, tv_usec=%llu})"
 | |
| 			       " = 4 (in [%d], out [1 2 %d]"
 | |
| 			       ", left {tv_sec=%lld, tv_usec=%llu})\n",
 | |
| 			       TEST_SYSCALL_STR, i,
 | |
| 			       fds[0], fds[1], PATH_TRACING_FD,
 | |
| 			       1, 2, fds[0], fds[1],
 | |
| 			       (long long) tv_in.tv_sec,
 | |
| 			       zero_extend_signed_to_ull(tv_in.tv_usec),
 | |
| 			       PATH_TRACING_FD, fds[1],
 | |
| 			       (long long) tv->tv_sec,
 | |
| 			       zero_extend_signed_to_ull(tv->tv_usec));
 | |
| 		}
 | |
| 
 | |
| 		*l_rs = (1UL << fds[0]) | (1UL << fds[1]);
 | |
| 		*l_ws = (1UL << 1) | (1UL << 2) |
 | |
| 			(1UL << fds[0]) | (1UL << fds[1]) |
 | |
| 			(1UL << PATH_TRACING_FD);
 | |
| 		tv_in.tv_sec = 0xc0de1;
 | |
| 		tv_in.tv_usec = 0xc0de2;
 | |
| 		memcpy(tv, &tv_in, sizeof(tv_in));
 | |
| 		XSELECT(3 + (i > PATH_TRACING_FD), i, a_rs, a_ws, a_es, a_tv);
 | |
| 		if (i > PATH_TRACING_FD) {
 | |
| 			printf("%s(%d, [%d %d], [%d %d %d %d %d], []"
 | |
| 			       ", {tv_sec=%lld, tv_usec=%llu})"
 | |
| 			       " = 4 (out [1 2 %d %d]"
 | |
| 			       ", left {tv_sec=%lld, tv_usec=%llu})\n",
 | |
| 			       TEST_SYSCALL_STR, i,
 | |
| 			       fds[0], fds[1],
 | |
| 			       1, 2, fds[0], fds[1], PATH_TRACING_FD,
 | |
| 			       (long long) tv_in.tv_sec,
 | |
| 			       zero_extend_signed_to_ull(tv_in.tv_usec),
 | |
| 			       fds[1], PATH_TRACING_FD,
 | |
| 			       (long long) tv->tv_sec,
 | |
| 			       zero_extend_signed_to_ull(tv->tv_usec));
 | |
| 		}
 | |
| 
 | |
| 		*l_rs = (1UL << fds[0]) | (1UL << fds[1]);
 | |
| 		*l_ws = (1UL << 1) | (1UL << 2) |
 | |
| 			(1UL << fds[0]) | (1UL << fds[1]);
 | |
| 		*l_es = (1UL << PATH_TRACING_FD);
 | |
| 		tv_in.tv_sec = 0xc0de1;
 | |
| 		tv_in.tv_usec = 0xc0de2;
 | |
| 		memcpy(tv, &tv_in, sizeof(tv_in));
 | |
| 		XSELECT(3, i, a_rs, a_ws, a_es, a_tv);
 | |
| 		if (i > PATH_TRACING_FD) {
 | |
| 		printf("%s(%d, [%d %d], [%d %d %d %d], [%d]"
 | |
| 		       ", {tv_sec=%lld, tv_usec=%llu}) = 3 (out [1 2 %d]"
 | |
| 		       ", left {tv_sec=%lld, tv_usec=%llu})\n",
 | |
| 		       TEST_SYSCALL_STR, i,
 | |
| 		       fds[0], fds[1],
 | |
| 		       1, 2, fds[0], fds[1], PATH_TRACING_FD,
 | |
| 		       (long long) tv_in.tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv_in.tv_usec),
 | |
| 		       fds[1],
 | |
| 		       (long long) tv->tv_sec,
 | |
| 		       zero_extend_signed_to_ull(tv->tv_usec));
 | |
| 		}
 | |
| 
 | |
| #endif /* PATH_TRACING_FD */
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Now the crash case that trinity found, negative nfds
 | |
| 	 * but with a pointer to a large chunk of valid memory.
 | |
| 	 */
 | |
| 	static fd_set set[0x1000000 / sizeof(fd_set)];
 | |
| 	FD_SET(fds[1], set);
 | |
| 	XSELECT(-1, -1U, 0, (uintptr_t) set, 0, 0);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 	printf("%s(-1, NULL, %p, NULL, NULL) = %s\n",
 | |
| 	       TEST_SYSCALL_STR, set, errstr);
 | |
| #endif
 | |
| 
 | |
| 	/*
 | |
| 	 * Big sets, nfds exceeds FD_SETSIZE limit.
 | |
| 	 */
 | |
| 	const size_t big_size = sizeof(fd_set) + sizeof(long);
 | |
| 	fd_set *const big_rs = tail_alloc(big_size);
 | |
| 	const uintptr_t a_big_rs = (uintptr_t) big_rs;
 | |
| 
 | |
| 	fd_set *const big_ws = tail_alloc(big_size);
 | |
| 	const uintptr_t a_big_ws = (uintptr_t) big_ws;
 | |
| 
 | |
| 	for (unsigned int i = FD_SETSIZE; i <= big_size * 8; ++i) {
 | |
| 		memset(big_rs, 0, big_size);
 | |
| 		memset(big_ws, 0, big_size);
 | |
| 		FD_SET(fds[0], big_rs);
 | |
| 		tv->tv_sec = 0;
 | |
| 		tv->tv_usec = 10 + (i - FD_SETSIZE);
 | |
| 		XSELECT(0, i, a_big_rs, a_big_ws, 0, a_tv);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, [%d], [], NULL, {tv_sec=0, tv_usec=%d})"
 | |
| 		       " = 0 (Timeout)\n",
 | |
| 		       TEST_SYSCALL_STR, i, fds[0], 10 + (i - FD_SETSIZE));
 | |
| #else
 | |
| 		FD_SET(fds[0], big_rs);
 | |
| 		FD_SET(PATH_TRACING_FD, big_rs);
 | |
| 		tv->tv_sec = 0;
 | |
| 		tv->tv_usec = 10 + (i - FD_SETSIZE);
 | |
| 		XSELECT(1, i, a_big_rs, a_big_ws, 0, a_tv);
 | |
| 		printf("%s(%d, [%d %d], [], NULL, {tv_sec=0, tv_usec=%d})"
 | |
| 		       " = 1 (in [%d], left {tv_sec=0, tv_usec=%llu})\n",
 | |
| 		       TEST_SYSCALL_STR, i, fds[0], PATH_TRACING_FD,
 | |
| 		       10 + (i - FD_SETSIZE), PATH_TRACING_FD,
 | |
| 		       zero_extend_signed_to_ull(tv->tv_usec));
 | |
| #endif /* PATH_TRACING_FD */
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Huge sets, nfds equals to INT_MAX.
 | |
| 	 */
 | |
| 	FD_SET(fds[0], set);
 | |
| 	FD_SET(fds[1], set);
 | |
| 	tv->tv_sec = 0;
 | |
| 	tv->tv_usec = 123;
 | |
| 	XSELECT(0, INT_MAX, (uintptr_t) set, (uintptr_t) &set[1],
 | |
| 		(uintptr_t) &set[2], a_tv);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 	printf("%s(%d, [%d %d], [], [], {tv_sec=0, tv_usec=123})"
 | |
| 	       " = 0 (Timeout)\n",
 | |
| 	       TEST_SYSCALL_STR, INT_MAX, fds[0], fds[1]);
 | |
| #else
 | |
| 	FD_SET(fds[0], set);
 | |
| 	FD_SET(fds[1], set);
 | |
| 	FD_SET(PATH_TRACING_FD, set);
 | |
| 	tv->tv_sec = 0;
 | |
| 	tv->tv_usec = 123;
 | |
| 	XSELECT(1, INT_MAX, (uintptr_t) set, (uintptr_t) &set[1],
 | |
| 		(uintptr_t) &set[2], a_tv);
 | |
| 	printf("%s(%d, [%d %d %d], [], [], {tv_sec=0, tv_usec=123})"
 | |
| 	       " = 1 (in [%d], left {tv_sec=0, tv_usec=%llu})\n",
 | |
| 	       TEST_SYSCALL_STR, INT_MAX, fds[0], fds[1], PATH_TRACING_FD,
 | |
| 	       PATH_TRACING_FD, zero_extend_signed_to_ull(tv->tv_usec));
 | |
| #endif /* PATH_TRACING_FD */
 | |
| 
 | |
| 	/*
 | |
| 	 * Small sets, nfds exceeds FD_SETSIZE limit.
 | |
| 	 * The kernel seems to be fine with it but strace cannot follow.
 | |
| 	 */
 | |
| 	*l_rs = (1UL << fds[0]) | (1UL << fds[1])
 | |
| #ifdef PATH_TRACING_FD
 | |
| 		| (1UL << PATH_TRACING_FD)
 | |
| #endif
 | |
| 		;
 | |
| 	*l_ws = (1UL << fds[0]);
 | |
| 	*l_es = (1UL << fds[0]) | (1UL << fds[1])
 | |
| #ifdef PATH_TRACING_FD
 | |
| 		| (1UL << PATH_TRACING_FD)
 | |
| #endif
 | |
| 		;
 | |
| 	tv->tv_sec = 0;
 | |
| 	tv->tv_usec = 123;
 | |
| 	rc = xselect(FD_SETSIZE + 1, a_rs, a_ws, a_es, a_tv);
 | |
| 	if (rc < 0) {
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, %p, %p, %p, {tv_sec=0, tv_usec=123}) = %s\n",
 | |
| 		       TEST_SYSCALL_STR, FD_SETSIZE + 1, rs, ws, es, errstr);
 | |
| #endif
 | |
| 	} else {
 | |
| #ifndef PATH_TRACING_FD
 | |
| 		printf("%s(%d, %p, %p, %p, {tv_sec=0, tv_usec=123})"
 | |
| 		       " = 0 (Timeout)\n",
 | |
| 		       TEST_SYSCALL_STR, FD_SETSIZE + 1, rs, ws, es);
 | |
| #endif
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Small sets, one of allocated descriptors exceeds smallset_size.
 | |
| 	 */
 | |
| 	if (dup2(fds[1], smallset_size) != smallset_size)
 | |
| 		perror_msg_and_fail("dup2");
 | |
| #ifdef PATH_TRACING_FD
 | |
| 	FD_SET(PATH_TRACING_FD, rs);
 | |
| 	FD_SET(PATH_TRACING_FD, ws);
 | |
| 	FD_SET(PATH_TRACING_FD, es);
 | |
| #endif
 | |
| 	XSELECT(-1, smallset_size + 1, a_rs, a_ws, a_es, 0);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 	printf("%s(%d, %p, %p, %p, NULL) = %s\n",
 | |
| 	       TEST_SYSCALL_STR, smallset_size + 1, rs, ws, es, errstr);
 | |
| #endif
 | |
| 
 | |
| 	/*
 | |
| 	 * Small and big sets,
 | |
| 	 * one of allocated descriptors exceeds smallset_size.
 | |
| 	 */
 | |
| 	memset(big_rs, 0, big_size);
 | |
| 	FD_SET(fds[0], big_rs);
 | |
| 	FD_SET(smallset_size, big_rs);
 | |
| 	memset(big_ws, 0, big_size);
 | |
| 	FD_SET(fds[1], big_ws);
 | |
| 	FD_SET(smallset_size, big_ws);
 | |
| 	XSELECT(-1, smallset_size + 1, a_big_rs, a_big_ws, a_es, 0);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 	printf("%s(%d, [%d %d], [%d %d], %p, NULL) = %s\n",
 | |
| 	       TEST_SYSCALL_STR, smallset_size + 1,
 | |
| 	       fds[0], smallset_size,
 | |
| 	       fds[1], smallset_size,
 | |
| 	       es, errstr);
 | |
| #endif /* !PATH_TRACING_FD */
 | |
| 	XSELECT(-1, smallset_size + 1, a_es, a_big_ws, a_big_rs, 0);
 | |
| #ifndef PATH_TRACING_FD
 | |
| 	printf("%s(%d, %p, [%d %d], [%d %d], NULL) = %s\n",
 | |
| 	       TEST_SYSCALL_STR, smallset_size + 1,
 | |
| 	       es,
 | |
| 	       fds[1], smallset_size,
 | |
| 	       fds[0], smallset_size,
 | |
| 	       errstr);
 | |
| #endif /* !PATH_TRACING_FD */
 | |
| 
 | |
| 	puts("+++ exited with 0 +++");
 | |
| 	return 0;
 | |
| }
 |