Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid traversing ocaml objects when not holding the runtime lock in spawn_unix #63

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

ncik-roberts
Copy link

@ncik-roberts ncik-roberts commented Jul 2, 2024

Copy sigprocmask into C data structures before releasing the runtime lock in spawn_unix.

This fixes a possible bad interaction with the GC. When the runtime lock isn't held by the current thread, another OCaml thread could run the GC and thus move around OCaml heap objects.

The PR takes the approach described in the C FFI section of the OCaml manual:

After caml_release_runtime_system() was called and until caml_acquire_runtime_system() is called, the C code must not access any OCaml data, nor call any function of the run-time system, nor call back into OCaml code. Consequently, arguments provided by OCaml to the C primitive must be copied into C data structures before calling caml_release_runtime_system(), and results to be returned to OCaml must be encoded as OCaml values after caml_acquire_runtime_system() returns.

("entering a blocking section" is the same thing as "releasing the runtime system".)

This helps ensure the stability of existing behavior in light of the
upcoming bugfix to `spawn_unix`.

Signed-off-by: Nick Roberts <[email protected]>
Avoid traversing OCaml data structures when the runtime lock is not
held.

Signed-off-by: Nick Roberts <[email protected]>
@ncik-roberts ncik-roberts force-pushed the avoid-traversing-ocaml-objects-in-blocking-section branch from ed49046 to 5a63016 Compare July 2, 2024 21:57

sigprocmask_command = Long_val(v_sigprocmask_command);
sigprocmask_signals_length = Wosize_val(v_sigprocmask_signals);
sigprocmask_signals = (int*)malloc(sizeof(int) * sigprocmask_signals_length);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to check return value from malloc


default:
caml_failwith("Unknown sigprocmask action");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't call caml_failwith in this context -- need caml_leave_blocking_section (etc) first. See the cleanup when safe_pipe fails above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, it's as if I've never read the patch. This makes me convinced that we should split the file in two files:

  • the part with bindings that runs with OCaml lock held
  • the part with thread-safe code that doesn't even include any of the OCaml headers

I'll prepare a feature that does that.

Copy link
Author

@ncik-roberts ncik-roberts Jul 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Don’t be too hard on yourself — the failwith was there before. GitHub is just doing a bad job showing changed code, thus revealing bugs nearby.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants