Fix a call to null pointer: in some cases, the unmonitor_fd can be called

from another fd's callback. That could lead to still have callback pending
after unmonitoring the fd resulting in a call to null pointer.
This is fixed by making unmonitor_fd now clear the pending fd_set too.
Bug was introduced by my commit in 2008-12-23.
This commit is contained in:
tteras 2009-06-24 11:28:48 +00:00
parent c33a588610
commit a8d702d9b1
1 changed files with 26 additions and 20 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: session.c,v 1.25 2009/04/21 18:38:32 tteras Exp $ */ /* $NetBSD: session.c,v 1.26 2009/06/24 11:28:48 tteras Exp $ */
/* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */ /* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */
@ -113,7 +113,7 @@ static void check_sigreq __P((void));
static void check_flushsa __P((void)); static void check_flushsa __P((void));
static int close_sockets __P((void)); static int close_sockets __P((void));
static fd_set mask; static fd_set preset_mask, active_mask;
static struct fd_monitor fd_monitors[FD_SETSIZE]; static struct fd_monitor fd_monitors[FD_SETSIZE];
static int nfds = 0; static int nfds = 0;
@ -128,7 +128,7 @@ monitor_fd(int fd, int (*callback)(void *, int), void *ctx)
exit(1); exit(1);
} }
FD_SET(fd, &mask); FD_SET(fd, &preset_mask);
if (fd > nfds) if (fd > nfds)
nfds = fd; nfds = fd;
@ -144,7 +144,8 @@ unmonitor_fd(int fd)
exit(1); exit(1);
} }
FD_CLR(fd, &mask); FD_CLR(fd, &preset_mask);
FD_CLR(fd, &active_mask);
fd_monitors[fd].callback = NULL; fd_monitors[fd].callback = NULL;
fd_monitors[fd].ctx = NULL; fd_monitors[fd].ctx = NULL;
} }
@ -152,7 +153,6 @@ unmonitor_fd(int fd)
int int
session(void) session(void)
{ {
fd_set rfds;
struct timeval *timeout; struct timeval *timeout;
int error; int error;
char pid_file[MAXPATHLEN]; char pid_file[MAXPATHLEN];
@ -161,7 +161,7 @@ session(void)
int i; int i;
nfds = 0; nfds = 0;
FD_ZERO(&mask); FD_ZERO(&preset_mask);
/* initialize schedular */ /* initialize schedular */
sched_init(); sched_init();
@ -274,9 +274,9 @@ session(void)
/* schedular can change select() mask, so we reset /* schedular can change select() mask, so we reset
* the working copy here */ * the working copy here */
rfds = mask; active_mask = preset_mask;
error = select(nfds + 1, &rfds, NULL, NULL, timeout); error = select(nfds + 1, &active_mask, NULL, NULL, timeout);
if (error < 0) { if (error < 0) {
switch (errno) { switch (errno) {
case EINTR: case EINTR:
@ -291,8 +291,14 @@ session(void)
} }
for (i = 0; i <= nfds; i++) { for (i = 0; i <= nfds; i++) {
if (FD_ISSET(i, &rfds)) if (!FD_ISSET(i, &active_mask))
continue;
if (fd_monitors[i].callback != NULL)
fd_monitors[i].callback(fd_monitors[i].ctx, i); fd_monitors[i].callback(fd_monitors[i].ctx, i);
else
plog(LLV_ERROR, LOCATION, NULL,
"fd %d set, but no active callback\n", i);
} }
} }
} }