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:
parent
c33a588610
commit
a8d702d9b1
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue