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;
 | 
						|
}
 |