The first six probes each proved a piece. merged.sh puts them together: the program's @main is renamed out of the way, a C main takes the main thread and runs it there, caml_startup happens on a thread beside it, and clang links the lot -- the emitted program object, flan_rt.c, flan_dev.c, flan_agent.c and the whole compiler as one -output-complete-obj. It runs, and the compiler inside it compiles the very source the program was built from. Nothing is wired up. The two halves share an address space and do not speak. That is the point: the question was whether they can, not what they would say. sig.sh and symbols.sh answer the two questions the first pass got wrong or skipped. The SIGSEGV reading in harness5.c was taken at the wrong moment -- OCaml 5 starts domains after caml_startup returns, so the disposition had to be read from inside the runtime, and against a plain ocamlopt executable as a control. symbols.sh is the hazard nobody looks for until the link fails: four .c files that are compiled into two different processes today, and the OCaml runtime, all landing in one link.
35 lines
1.4 KiB
OCaml
35 lines
1.4 KiB
OCaml
(* Step 5b: OCaml 5.2 installs its SIGSEGV handler per-domain, not once at
|
|
startup, so "read the disposition after caml_startup" is not the whole
|
|
question. This asks it at four moments, and then asks the thing that
|
|
actually matters: does Stack_overflow still get raised once the break loop
|
|
has taken SIGSEGV? *)
|
|
|
|
external show : string -> unit = "spike_show_segv"
|
|
external take_segv : unit -> unit = "spike_take_segv"
|
|
external chain_segv : unit -> unit = "spike_chain_segv"
|
|
external sweep : unit -> unit = "spike_sweep"
|
|
|
|
let rec deep n = if n <= 0 then 0 else 1 + deep (n - 1) + (if n < 0 then deep n else 0)
|
|
|
|
let overflow_result () =
|
|
try
|
|
let n = deep 100_000_000 in
|
|
Printf.sprintf "returned %d (no overflow)" n
|
|
with Stack_overflow -> "Stack_overflow raised"
|
|
|
|
let () =
|
|
show "at module init (main domain up)";
|
|
let d = Domain.spawn (fun () -> show "inside a spawned domain") in
|
|
Domain.join d;
|
|
show "after Domain.join";
|
|
print_endline "every signal the OCaml runtime is holding:";
|
|
sweep ();
|
|
Printf.sprintf "before touching SIGSEGV: %s" (overflow_result ()) |> print_endline;
|
|
take_segv ();
|
|
show "after the break loop takes SIGSEGV outright";
|
|
Printf.sprintf "with SIGSEGV taken outright: %s" (overflow_result ())
|
|
|> print_endline;
|
|
chain_segv ();
|
|
show "after the break loop chains to OCaml's handler";
|
|
Printf.sprintf "with SIGSEGV chained: %s" (overflow_result ()) |> print_endline
|