Skip to content

Commit 5a63016

Browse files
committed
C stub bugfix in spawn_unix.
Avoid traversing OCaml data structures when the runtime lock is not held. Signed-off-by: Nick Roberts <[email protected]>
1 parent d46419e commit 5a63016

File tree

2 files changed

+56
-30
lines changed

2 files changed

+56
-30
lines changed

src/spawn.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ external spawn_unix
9898
-> stderr:Unix.file_descr
9999
-> use_vfork:bool
100100
-> setpgid:int option
101-
-> sigprocmask:(Unix.sigprocmask_command * int list) option
101+
-> sigprocmask:(Unix.sigprocmask_command * int array) option
102102
-> int
103103
= "spawn_unix_byte" "spawn_unix"
104104

@@ -179,6 +179,11 @@ let spawn
179179
| Vfork -> true
180180
| Fork -> false
181181
in
182+
let sigprocmask =
183+
match sigprocmask with
184+
| Some (mask, signals) -> Some (mask, Array.of_list signals)
185+
| None -> None
186+
in
182187
backend ~env ~cwd ~prog ~argv ~stdin ~stdout ~stderr ~use_vfork ~setpgid ~sigprocmask
183188
;;
184189

src/spawn_stubs.c

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ CAMLprim value spawn_unix(value v_env,
399399
value v_sigprocmask)
400400
{
401401
CAMLparam4(v_env, v_cwd, v_prog, v_argv);
402+
CAMLlocal2(v_sigprocmask_command, v_sigprocmask_signals);
402403
pid_t ret;
403404
struct spawn_info info;
404405
int result_pipe[2];
@@ -446,6 +447,30 @@ CAMLprim value spawn_unix(value v_env,
446447
Is_block(v_setpgid) ?
447448
Long_val(Field(v_setpgid, 0)) : 0;
448449

450+
enum caml_unix_sigprocmask_command sigprocmask_command;
451+
int* sigprocmask_signals; /* array */
452+
mlsize_t sigprocmask_signals_length;
453+
454+
if (!Is_block(v_sigprocmask)) {
455+
sigprocmask_command = CAML_SIG_SETMASK;
456+
sigprocmask_signals = NULL;
457+
sigprocmask_signals_length = 0;
458+
} else {
459+
v_sigprocmask = Field(v_sigprocmask, 0);
460+
461+
v_sigprocmask_command = Field(v_sigprocmask, 0);
462+
v_sigprocmask_signals = Field(v_sigprocmask, 1);
463+
464+
sigprocmask_command = Long_val(v_sigprocmask_command);
465+
sigprocmask_signals_length = Wosize_val(v_sigprocmask_signals);
466+
sigprocmask_signals = (int*)malloc(sizeof(int) * sigprocmask_signals_length);
467+
468+
for (mlsize_t i = 0; i < sigprocmask_signals_length; i++) {
469+
sigprocmask_signals[i] =
470+
caml_convert_signal_number(Long_val(Field(v_sigprocmask_signals, i)));
471+
}
472+
}
473+
449474
caml_enter_blocking_section();
450475
enter_safe_pipe_section();
451476

@@ -455,6 +480,9 @@ CAMLprim value spawn_unix(value v_env,
455480
leave_safe_pipe_section();
456481
caml_leave_blocking_section();
457482
free_spawn_info(&info);
483+
if (sigprocmask_signals != NULL) {
484+
free(sigprocmask_signals);
485+
}
458486
unix_error(error, "pipe", Nothing);
459487
}
460488

@@ -478,44 +506,34 @@ CAMLprim value spawn_unix(value v_env,
478506
sigfillset(&sigset);
479507
pthread_sigmask(SIG_SETMASK, &sigset, &saved_procmask);
480508

481-
if (v_sigprocmask == Val_long(0)) {
482-
sigemptyset(&info.child_sigmask);
483-
} else {
484-
v_sigprocmask = Field(v_sigprocmask, 0);
485-
value v_sigprocmask_command = Field(v_sigprocmask, 0);
486-
enum caml_unix_sigprocmask_command sigprocmask_command = Long_val(v_sigprocmask_command);
509+
switch (sigprocmask_command) {
510+
case CAML_SIG_SETMASK:
511+
sigemptyset(&info.child_sigmask);
512+
break;
513+
514+
case CAML_SIG_BLOCK:
515+
case CAML_SIG_UNBLOCK:
516+
info.child_sigmask = saved_procmask;
517+
break;
487518

519+
default:
520+
caml_failwith("Unknown sigprocmask action");
521+
}
522+
523+
for (mlsize_t i = 0; i < sigprocmask_signals_length; i++) {
524+
int signal = sigprocmask_signals[i];
488525
switch (sigprocmask_command) {
489526
case CAML_SIG_SETMASK:
490-
sigemptyset(&info.child_sigmask);
527+
case CAML_SIG_BLOCK:
528+
sigaddset(&info.child_sigmask, signal);
491529
break;
492530

493-
case CAML_SIG_BLOCK:
494531
case CAML_SIG_UNBLOCK:
495-
info.child_sigmask = saved_procmask;
532+
sigdelset(&info.child_sigmask, signal);
496533
break;
497534

498535
default:
499-
caml_failwith("Unknown sigprocmask action");
500-
}
501-
502-
value v_signals_list = Field(v_sigprocmask, 1);
503-
for (; v_signals_list != Val_emptylist;
504-
v_signals_list = Field(v_signals_list, 1)) {
505-
int signal = caml_convert_signal_number(Long_val(Field(v_signals_list, 0)));
506-
switch (sigprocmask_command) {
507-
case CAML_SIG_SETMASK:
508-
case CAML_SIG_BLOCK:
509-
sigaddset(&info.child_sigmask, signal);
510-
break;
511-
512-
case CAML_SIG_UNBLOCK:
513-
sigdelset(&info.child_sigmask, signal);
514-
break;
515-
516-
default:
517-
assert(0);
518-
}
536+
assert(0);
519537
}
520538
}
521539

@@ -529,6 +547,9 @@ CAMLprim value spawn_unix(value v_env,
529547

530548
leave_safe_pipe_section();
531549
free_spawn_info(&info);
550+
if (sigprocmask_signals != NULL) {
551+
free(sigprocmask_signals);
552+
}
532553
close(result_pipe[1]);
533554

534555
got_error = 0;

0 commit comments

Comments
 (0)