Oracle Bug 14961740 - SUNBT4136406 dtgreet runs wild and error messages fill /var/dt/Xerrors Oracle Bug 15072668 - SUNBT4482749 Xt spins forever when select() returns EBADF Changed handling of select() error to not retry indefinitely. Description of 14961740: When select() returns EINVAL, investigate whether this condition is caused by an invalid timeout value, or whether one of the fds in the fd_set is invalid. If the problem is caused by the timeout value, then the problem can be cured by adjusting these. If the problem arises because of the fd_set, then Xt can do little better than to terminate the application, since it has no direct way of curing the condition. Description of 15072668: _XtWaitForSomething did not explicity check for EBADF. This caused the function to continuously call select for the bad file descriptor leading to an infinite loop. Added in an error handler for this particular error. In the event of an EBADF, the Xt removes all Input Procedures that monitor the offending file descriptor. This prevents it from repeating checks which are going to fail. Additionally, an XtWarning is issued to the user. An XtError is too much as it will dump the user out of the program. Finally, the error handler returns -1 from _XtWaitForSomething(). Need to evaluate for submission upstream. --- a/configure.ac 2022-11-07 19:20:45.189568737 -0800 +++ b/configure.ac 2022-11-07 19:21:07.279113999 -0800 @@ -80,6 +80,7 @@ # Map function checks to old Imake #defines case $host_os in + solaris*) ;; # our changes to NextEvent.c break if poll() is used # darwin through Snow Leopard has poll() but can't be used to poll character devices. darwin@<:@789@:>@*|darwin10*) ;; darwin*) --- a/src/NextEvent.c 2022-11-07 19:21:23.489203221 -0800 +++ b/src/NextEvent.c 2022-11-07 19:29:41.331516786 -0800 @@ -367,6 +367,53 @@ } } +static void CheckAndTrimTimes(XtAppContext app, wait_times_ptr_t wt) +{ + struct timeval tv; + String pptrs[8]; + Cardinal nbr_parms; + + pptrs[0] = (String)zero_time.tv_sec; + pptrs[1] = (String)zero_time.tv_usec; + pptrs[2] = (String)wt->wait_time.tv_sec; + pptrs[3] = (String)wt->wait_time.tv_usec; + pptrs[4] = (String)wt->max_wait_time.tv_sec; + pptrs[5] = (String)wt->max_wait_time.tv_usec; + pptrs[6] = (String)wt->cur_time.tv_sec; + pptrs[7] = (String)wt->cur_time.tv_usec; + nbr_parms = 8; + XtAppErrorMsg(app, "communicationError", "select", + XtCXtToolkitError, "Resetting timer values: zero_time=%lu:%lu, " + "wait_time=%lu:%lu, max_wait_time=%lu:%lu, cur_time=%lu:%lu", + pptrs, &nbr_parms); + + memset(&zero_time, 0, sizeof(zero_time)); /* Ensure the integrity of */ + /* zero_time. */ + if (wt->max_wait_time.tv_sec > 99999999) /* Bring max_wait_time back into */ + { /* acceptable range if nec. */ + wt->max_wait_time.tv_sec &= 0xFFFFF; + wt->max_wait_time.tv_usec = 0; /* (Fractions of a sec are in- */ + /* significant at this level.) */ + } + if (app->timerQueue != NULL) /* Do the same for the head of */ + { /* the timer queue if necessary. */ + TIMEDELTA(tv, app->timerQueue->te_timer_value, wt->cur_time); + if (tv.tv_sec > 99999999) + { + pptrs[0] = (String)app->timerQueue->te_timer_value.tv_sec; + pptrs[1] = (String)app->timerQueue->te_timer_value.tv_usec; + nbr_parms = 2; + XtAppErrorMsg(app, "selectError", "timerQueue", + XtCXtToolkitError, "timerQueue value %lu:%lu is invalid", + pptrs, &nbr_parms); + tv.tv_sec &= 0xFFFFF; + tv.tv_usec = 0; + ADD_TIME(app->timerQueue->te_timer_value, wt->cur_time, tv); + } + } +} + + static int IoWait(wait_times_ptr_t wt, wait_fds_ptr_t wf) { @@ -717,17 +799,32 @@ nfds = 0; } } - else { - char Errno[12]; - String param = Errno; - Cardinal param_count = 1; + else if (errno == EINVAL) { + struct timeval tv={0}; - sprintf(Errno, "%d", errno); - XtAppWarningMsg(app, "communicationError", "select", - XtCXtToolkitError, - "Select failed; error code %s", ¶m, - ¶m_count); - continue; + nfds = Select(wf.nfds, &wf.rmask, &wf.wmask, &wf.emask, &tv); + /* Do a non-blocking select to */ + /* eliminate any timeout errors.*/ + if (nfds == -1) { /* Now try to sort out the good */ + if (errno == EINVAL) { /* and the bad from the ugly. */ + char Errno[12]; /* (This is ugly). */ + String param = Errno; + Cardinal param_count = 1; + + sprintf(Errno, "%d", errno); + XtAppErrorMsg(app, "communicationError", "select", + XtCXtToolkitError, "Select failed; error code %s", + ¶m, ¶m_count); + XtAppError(app, "EINVAL error in select() call"); + } else { /* If the new error is not about */ + /* an invalid select() parameter,*/ + continue; /* then simply try again. */ + } + } else { /* (Else the error appears to be */ + /* in the timeout parameter.) */ + CheckAndTrimTimes(app, &wt); + continue; + } } } /* timed out or input available */ break; --- a/src/NextEvent.c 2024-08-23 17:16:20.202048925 -0700 +++ b/src/NextEvent.c 2024-08-23 17:19:37.616146755 -0700 @@ -696,13 +696,48 @@ /* * interrupt occurred recalculate time value and wait again. */ - if (errno == EINTR || errno == EAGAIN) { - if (errno == EAGAIN) { + if (errno == EAGAIN) { errno = 0; /* errno is not self resetting */ continue; - } - errno = 0; /* errno is not self resetting */ + } else if (errno == EBADF) { + /* Bug 4482749 - If we have a bad FD stop monitoring it */ + int i; + struct timeval tv={0}; + for (i = 0; i < wf.nfds; i++) { + if (FD_ISSET(i, &wf.rmask) || FD_ISSET(i, &wf.wmask) || + FD_ISSET(i, &wf.emask)) { + if (select(i + 1, &wf.rmask, &wf.wmask, &wf.emask, &tv) + == -1) { + char bad_fd[55]; + String param = bad_fd; + Cardinal param_count = 1; + /* + * Get rid of any input procedures on the bad FD + * and regenerate the list of FDs we listen to. + */ + while (app->input_list[i] != NULL) { + XtRemoveInput((XtInputId)app->input_list[i]); + } + InitFds (app, ignoreEvents, ignoreInputs, &wf); + sprintf(bad_fd, "%d", errno); + XtAppWarningMsg(app, "communicationError", "select", + XtCXtToolkitError, + "Select failed; error code %s", + ¶m, ¶m_count); + + sprintf(bad_fd, "EBADF error in select() call for file descriptor %d", i); + XtAppWarning(app, param); + + } + } + } + + return -1; + + } else if (errno == EINTR) { + errno = 0; /* errno is not self reseting */ + /* was it interrupted by a signal that we care about? */ if (!ignoreSignals && app->signalQueue != NULL) { SignalEventRec *se_ptr = app->signalQueue; @@ -710,7 +745,7 @@ while (se_ptr != NULL) { if (se_ptr->se_notice) { if (block && howlong != NULL) - AdjustHowLong(howlong, &wt.start_time); + AdjustHowLong (howlong, &wt.start_time); #ifdef USE_POLL XtStackFree((XtPointer) wf.fdlist, fdlist); #endif