From 7e04c1a53ddada7a848753d151e18f9469788b98 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 23 Feb 2014 18:14:12 -0800 Subject: 32427: avoid busy loop on closed descriptors for "zle -F" handlers Also assure the handlers are called on error conditions and document the extra argument that is passed in the error case. --- Src/Zle/zle_main.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index b0010fc33..442c31995 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -525,7 +525,8 @@ raw_getbyte(long do_keytmout, char *cptr) #endif #ifndef HAVE_POLL # ifdef HAVE_SELECT - fd_set foofd; + fd_set foofd, errfd; + FD_ZERO(&errfd); # endif #endif @@ -613,11 +614,14 @@ raw_getbyte(long do_keytmout, char *cptr) if (!errtry) { for (i = 0; i < nwatch; i++) { int fd = watch_fds[i].fd; + if (FD_ISSET(fd, &errfd)) + continue; FD_SET(fd, &foofd); if (fd > fdmax) fdmax = fd; } } + FD_ZERO(&errfd); if (tmout.tp != ZTM_NONE) { expire_tv.tv_sec = tmout.exp100ths / 100; @@ -732,9 +736,10 @@ raw_getbyte(long do_keytmout, char *cptr) Watch_fd lwatch_fd = lwatch_fds + i; if ( # ifdef HAVE_POLL - (fds[i+1].revents & POLLIN) + (fds[i+1].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) # else - FD_ISSET(lwatch_fd->fd, &foofd) + FD_ISSET(lwatch_fd->fd, &foofd) || + FD_ISSET(lwatch_fd->fd, &errfd) # endif ) { /* Handle the fd. */ @@ -765,6 +770,9 @@ raw_getbyte(long do_keytmout, char *cptr) if (fds[i+1].revents & POLLNVAL) zaddlinknode(funcargs, ztrdup("nval")); # endif +# else + if (FD_ISSET(lwatch_fd->fd, &errfd)) + zaddlinknode(funcargs, ztrdup("err")); # endif callhookfunc(lwatch_fd->func, funcargs, 0, NULL); freelinklist(funcargs, freestr); @@ -786,6 +794,31 @@ raw_getbyte(long do_keytmout, char *cptr) for (i = 0; i < lnwatch; i++) zsfree(lwatch_fds[i].func); zfree(lwatch_fds, lnwatch*sizeof(struct watch_fd)); + +# ifdef HAVE_POLL + /* Function may have added or removed handlers */ + nfds = 1 + nwatch; + if (nfds > 1) { + fds = zrealloc(fds, sizeof(struct pollfd) * nfds); + for (i = 0; i < nwatch; i++) { + /* + * This is imperfect because it assumes fds[] and + * watch_fds[] remain in sync, which may be false + * if handlers are shuffled. However, it should + * be harmless (e.g., produce one extra pass of + * the loop) in the event they fall out of sync. + */ + if (fds[i+1].fd == watch_fds[i].fd && + (fds[i+1].revents & (POLLERR|POLLHUP|POLLNVAL))) { + fds[i+1].events = 0; /* Don't poll this */ + } else { + fds[i+1].fd = watch_fds[i].fd; + fds[i+1].events = POLLIN; + } + fds[i+1].revents = 0; + } + } +# endif } } # ifdef HAVE_POLL -- cgit 1.4.1