|
From: Nicholas N. <nj...@ca...> - 2004-02-14 15:56:11
|
Hi,
Here is PRE(select):
PRE(select)
{
/* struct sel_arg_struct {
unsigned long n;
fd_set *inp, *outp, *exp;
struct timeval *tvp;
};
int old_select(struct sel_arg_struct *arg);
*/
SYSCALL_TRACK( pre_mem_read, tid, "select(args)", arg1, 5*sizeof(UInt)
);
{
UInt* arg_struct = (UInt*)arg1;
UInt a1, a2, a3, a4, a5;
a1 = arg_struct[0];
a2 = arg_struct[1];
a3 = arg_struct[2];
a4 = arg_struct[3];
a5 = arg_struct[4];
MAYBE_PRINTF("select ( %d, %p, %p, %p, %p )\n",
a1,a2,a3,a4,a5);
if (a2 != (Addr)NULL)
SYSCALL_TRACK( pre_mem_read, tid, "select(readfds)", a2,
a1/8 /* __FD_SETSIZE/8 */ );
if (a3 != (Addr)NULL)
SYSCALL_TRACK( pre_mem_read, tid, "select(writefds)", a3,
arg1/8 /* __FD_SETSIZE/8 */ );
if (a4 != (Addr)NULL)
SYSCALL_TRACK( pre_mem_read, tid, "select(exceptfds)", a4,
a1/8 /* __FD_SETSIZE/8 */ );
if (a5 != (Addr)NULL)
SYSCALL_TRACK( pre_mem_read, tid, "select(timeout)", a5,
sizeof(struct timeval) );
}
}
First of all, a3's pre_mem_read has arg1/8 in it, instead of a1/8, like
the other two, which looks totally wrong. I think this hasn't raised its
head because select is rarely used, because _newselect is used instead.B
Secondly, and a bigger problem: the a1/8 looks wrong anyway, which
affects both PRE(select) and PRE(_newselect).
AIUI, the fdsets are bit arrays, with 1024 bits, each bit representing an
fd; if bit N is set in an array, select will watch fd N appropriately.
The first arg, n, is the highest N for which a bit is set, plus one.
Therefore, select() will read at least n bits in each array. Thus, the
a1/8 is close, but not quite right; it's not rounding up to allow for any
unused bits at the end of the read bytes. For example, most of the time n
will be less than 8, in which case the length passed to pre_mem_read will
be zero! I think it needs to be (a1+7)/8.
Does this seem right? I'll fix it if people agree.
Thanks.
N
|