Skip to content

Commit 3aac8ff

Browse files
committed
Remove functions that are not async-signal-safe from signal handler.
Fixes #3034
1 parent ebe8f21 commit 3aac8ff

File tree

1 file changed

+38
-11
lines changed

1 file changed

+38
-11
lines changed

judge/runguard.cc

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ pid_t child_pid = -1;
156156

157157
static volatile sig_atomic_t received_SIGCHLD = 0;
158158
static volatile sig_atomic_t received_signal = -1;
159+
static volatile sig_atomic_t error_in_signalhandler = 0;
159160

160161
int child_pipefd[3][2];
161162
int child_redirfd[3];
@@ -192,7 +193,7 @@ struct option const long_opts[] = {
192193
void warning( const char *, ...) __attribute__((format (printf, 1, 2)));
193194
void verbose( const char *, ...) __attribute__((format (printf, 1, 2)));
194195
void error(int, const char *, ...) __attribute__((format (printf, 2, 3)));
195-
void write_meta(const char*, const char *, ...) __attribute__((format (printf, 2, 3)));
196+
void write_meta(const char *, const char *, ...) __attribute__((format (printf, 2, 3)));
196197

197198
void warning(const char *format, ...)
198199
{
@@ -226,6 +227,25 @@ void verbose(const char *format, ...)
226227
va_end(ap);
227228
}
228229

230+
// These functions are called from signal handlers, so they
231+
// must only call async-signal-safe functions.
232+
// write() is async-signal-safe, printf and variants are not.
233+
void verbose_from_signalhandler(const char* msg)
234+
{
235+
if (!be_quiet && be_verbose) {
236+
write(STDERR_FILENO, msg, strlen(msg));
237+
}
238+
}
239+
240+
void warning_from_signalhandler(const char* msg)
241+
{
242+
if (!be_quiet) {
243+
// Do not include timing here, as it wouldn't be safe from a signalhandler.
244+
// TODO: Consider rewriting using clock_gettime in the future.
245+
write(STDERR_FILENO, msg, strlen(msg));
246+
}
247+
}
248+
229249
void error(int errnum, const char *format, ...)
230250
{
231251
// Silently ignore errors that happen while handling other errors.
@@ -674,43 +694,47 @@ void terminate(int sig)
674694
sigact.sa_handler = SIG_DFL;
675695
sigact.sa_flags = 0;
676696
if ( sigemptyset(&sigact.sa_mask)!=0 ) {
677-
warning("could not initialize signal mask");
697+
warning_from_signalhandler("could not initialize signal mask");
678698
}
679699
if ( sigaction(SIGTERM,&sigact,nullptr)!=0 ) {
680-
warning("could not restore signal handler");
700+
warning_from_signalhandler("could not restore signal handler");
681701
}
682702
if ( sigaction(SIGALRM,&sigact,nullptr)!=0 ) {
683-
warning("could not restore signal handler");
703+
warning_from_signalhandler("could not restore signal handler");
684704
}
685705

686706
if ( sig==SIGALRM ) {
687707
if (runpipe_pid > 0) {
688-
warning("sending SIGUSR1 to runpipe with pid %d", runpipe_pid);
708+
warning_from_signalhandler("sending SIGUSR1 to runpipe");
689709
kill(runpipe_pid, SIGUSR1);
690710
}
691711

692712
walllimit_reached |= hard_timelimit;
693-
warning("timelimit exceeded (hard wall time): aborting command");
713+
warning_from_signalhandler("timelimit exceeded (hard wall time): aborting command");
694714
} else {
695-
warning("received signal %d: aborting command",sig);
715+
warning_from_signalhandler("received signal: aborting command");
696716
}
697717

698718
received_signal = sig;
699719

700720
/* First try to kill graciously, then hard.
701721
Don't report an already exited process as error. */
702-
verbose("sending SIGTERM");
722+
verbose_from_signalhandler("sending SIGTERM");
703723
if ( kill(-child_pid,SIGTERM)!=0 && errno!=ESRCH ) {
704-
error(errno,"sending SIGTERM to command");
724+
warning_from_signalhandler("error sending SIGTERM to command");
725+
error_in_signalhandler = 1;
726+
return;
705727
}
706728

707729
/* Prefer nanosleep over sleep because of higher resolution and
708730
it does not interfere with signals. */
709731
nanosleep(&killdelay,nullptr);
710732

711-
verbose("sending SIGKILL");
733+
verbose_from_signalhandler("sending SIGKILL");
712734
if ( kill(-child_pid,SIGKILL)!=0 && errno!=ESRCH ) {
713-
error(errno,"sending SIGKILL to command");
735+
warning_from_signalhandler("error sending SIGKILL to command");
736+
error_in_signalhandler = 1;
737+
return;
714738
}
715739

716740
/* Wait another while to make sure the process is killed by now. */
@@ -1465,6 +1489,9 @@ int main(int argc, char **argv)
14651489

14661490
int r = pselect(nfds+1, &readfds, nullptr, NULL, NULL, &emptymask);
14671491
if ( r==-1 && errno!=EINTR ) error(errno,"waiting for child data");
1492+
if (error_in_signalhandler) {
1493+
error(errno, "error in signal handler, exiting");
1494+
}
14681495

14691496
if ( received_SIGCHLD || received_signal == SIGALRM ) {
14701497
pid_t pid;

0 commit comments

Comments
 (0)