# Dealing with external libraries that don't restore old signal handlers

**URL:** <https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343>\
**Category:** Internals & Design\
**Created:** [July 17, 2022, 2:27am UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343 "2022-07-17T02:27:19Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![sobhan](https://avatars.discourse-cdn.com/v4/letter/s/258eb7/32.png) [@sobhan](https://discourse.julialang.org/u/sobhan)\
**Post date:** [July 17, 2022, 2:27am UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343/1 "2022-07-17T02:27:19Z")

</div>

## TLDR:

if the code is segfaulting outside Ccalls AFTER Ccalls in threaded GC, it might be that the C library has loaded a custom signal handler and is competing with [julia’s handler](https://github.com/JuliaLang/julia/blob/7261c65d5250a849332ba8ac1813004df91e224f/src/signals-unix.c#L618=).

The solution is something like

```julia
"""
sigsegv_handler(new=C_NULL, old=zeros(UInt8, 256); signal) -> typeof(new)

new is the new signal handler to set for the signal and old is the structure where the backup will be made. setting each to `C_NULL` will ignore them. i.e. by default it will just backup the handler. The arguments need to be able to hold a `struct sigaction`.
"""
function sigsegv_handler(new=C_NULL, old=zeros(UInt8, 256); signal)
    @ccall sigaction(
        signal::Cint,
        new::Ptr{Cvoid},
        old::Ptr{Cvoid})::Cint
    return old
end

handler = sigsegv_hanlder(; signal=11)
@ccall C code ...
sigsegv_hanlder(handler, C_NULL; signal=11)

```

## Long version

One of my go to options for blackbox optimization is [nomad](https://github.com/bbopt/nomad). The biggest issue with nomad is the julia interface is [this issue](https://github.com/bbopt/NOMAD.jl/issues/39). Long story short the interface works fine in single thread but using any sort of threads after or while using nomad makes the problem segfault. After some talk mostly with @mkitti, @Sukera, and @jpsamaroo this was the cause and building on mkitti’s idea, the solution.

The first guess was that the call back was being run from another thread. This cannot be as NOMAD\_jll is compiled w/o openmp support and it would not explain why it segfaults AFTER using nomad. After some debugging with gdb i came to the conlusion that it must be the signal hanlders that have been messed with. Lo and behold it was indeed [true](https://github.com/bbopt/nomad/blob/f3a9c173792e556de44c668a7be2f9078bf70ae6/src/Algos/Algorithm.cpp#L104). Nomad loads signal handlers but never releases them.

that’s when mkitti had the brilliant idea to just back it up on julia’s side with [sigaction](https://www.man7.org/linux/man-pages/man2/sigaction.2.html). The solution was indeed using it back up the state and restoring before calling the user function and when going out of `NOMAD.jl`. The only remaining problem right now is having a robust estimate of the struct size, 256 Bytes seems like a good estimate as it’s 159 Bytes on x86\_64.

```C
#include <signal.h>
#include <stdio.h>

int main() {
    printf("%ld", sizeof(struct sigaction));
    return 0;
}

```

or the more questionable version

```julia-auto
function get_sigsegv_handler()
    v = zeros(UInt8, 1024)
    @ccall sigaction(
        11::Cint,
        C_NULL::Ptr{Cvoid},
        v::Ptr{Cvoid}
    )::Cint
    return v
end
findlast(x -> x != 0, get_sigsegv_handler())

```

can be used to calculate the size needed for storing the struct.

Whether `@ccall`/`@cfunction` should automagically restore the hanlder is another question and i hope someone with more understand can chip in.

PS.

i think it’s bad design from the part of bbopt/nomad to not restore the handlers. but even if they did restore it, it wouldn’t have solved half of the problems.

## MWE

> ****
>
> ```julia
> using Base.Threads, NOMAD
> n = 5
> @assert nthreads() > 1
> function main()
> function f(x)
> @threads for i in 1:nthreads() * 3
> for j in 1:100
> g = rand(j, j)
> end
> GC.gc()    
> end
> (true, true, x[1])
> end
> pb = NomadProblem(n,
> 1,
> ["OBJ"],
> f;
> upper_bound=[100.0 for _ in 1:n],
> lower_bound=[0.0 for _ in 1:n])
> 
> pb.options.max_bb_eval = 1000
> pb.options.max_time = 20
> result = @time NOMAD.solve(pb, rand(n))
> end
> main()
> 
> @threads for i in 1:100
> for j in 1:100
> g = rand(j, j)
> end
> GC.gc()    
> end
> 
> ```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [July 17, 2022, 2:54am UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343/2 "2022-07-17T02:54:16Z")

</div>

By running some C code we can compute the `sizeof(struct sigaction)` and currently that is 152 bytes on Linux.

I suspect that we can obtain this directly by parsing the C header signals.h or more specifically bits/sigaction.h.

Nonetheless, the above approach will probably work. One might want to leave a buffer in case `sigaction` has additional fields that are just zero valued.

> [@How do I obtain \`sizeof(struct sigaction)\`? Clang.jl?](https://discourse.julialang.org/t/how-do-i-obtain-sizeof-struct-sigaction-clang-jl/84344):
>
> I would like to figure out the value printed by this C program in Julia. #include \<signal.h\> #include \<stdio.h\> int main() { printf("%ld", sizeof(struct sigaction)); return 0; } On my system, this prints 152 bytes. My /usr/include/x86\_64-linux-gnu/bits/sigaction.h has this definition: [https://sourceware.org/git/?p=glibc.git;a=blob;f=bits/sigaction.h;h=cef879f40aae8e14b2e998daeded26ebe5cfad9d;hb=HEAD#l32](https://sourceware.org/git/?p=glibc.git;a=blob;f=bits/sigaction.h;h=cef879f40aae8e14b2e998daeded26ebe5cfad9d;hb=HEAD#l32) Other than building the C code above, is there a way to obtain the size …

---

<div class="post-metadata">

**Author:** ![Gnimuc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gnimuc/32/2194_2.png) [@Gnimuc](https://discourse.julialang.org/u/Gnimuc)\
**Post date:** [July 17, 2022, 6:16am UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343/3 "2022-07-17T06:16:13Z")

</div>

> [@mkitti](#):
>
> I suspect that we can obtain this directly by parsing the C header signals.h or more specifically bits/sigaction.h.

Yes, you can. But the size depends on the system headers you use.

---

<div class="post-metadata">

**Author:** ![sobhan](https://avatars.discourse-cdn.com/v4/letter/s/258eb7/32.png) [@sobhan](https://discourse.julialang.org/u/sobhan)\
**Post date:** [July 17, 2022, 6:17am UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343/4 "2022-07-17T06:17:27Z")

</div>

but which version will julia call? it should be constant depending on the target os, rigth?

---

<div class="post-metadata">

**Author:** ![Gnimuc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gnimuc/32/2194_2.png) [@Gnimuc](https://discourse.julialang.org/u/Gnimuc)\
**Post date:** [July 17, 2022, 10:24am UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343/5 "2022-07-17T10:24:13Z")

</div>

the version is used when compiling julia

if the C library is compiled using BB, then those system headers should be matched.

---

<div class="post-metadata">

**Author:** ![Gnimuc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gnimuc/32/2194_2.png) [@Gnimuc](https://discourse.julialang.org/u/Gnimuc)\
**Post date:** [July 17, 2022, 10:27am UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343/6 "2022-07-17T10:27:22Z")

</div>

> [@sobhan](#):
>
> it should be constant depending on the target os, rigth?

it depends on triplets(e.g. `Sys.MACHINE`).

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [July 17, 2022, 5:05pm UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343/7 "2022-07-17T17:05:16Z")

</div>

I will have to sit down and think about how to pull that specific struct out the Clang `parse`.

If I just have Clang.jl parse the the following

```nohighlight
#include <signal.h>

const long sizeof_struct_sigaction = sizeof(struct sigaction);

```

I’m starting to think the easiest path would be to compile a small shared library for now and perhaps integrate a facility into Julia later.

[https://github.com/JuliaLang/julia/issues/46076](https://github.com/JuliaLang/julia/issues/46076)

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [July 17, 2022, 5:54pm UTC](https://discourse.julialang.org/t/dealing-with-external-libraries-that-dont-restore-old-signal-handlers/84343/8 "2022-07-17T17:54:03Z")

</div>

Thanks @Gnimuc , I figured it out!

```julia
julia> temp_header = tempname()*".h"
"/tmp/jl_Cvhf3N.h"

julia> open(temp_header, "w") do f
           write(f,
           """
           #include <stddef.h>
           #include <signal.h>
           
           const size_t sizeof_struct_sigaction = sizeof(struct sigaction);
           """
           )
       end
106

julia> cursor = Clang.getTranslationUnitCursor(trans)
CLCursor (CLTranslationUnit) /tmp/jl_6DBaOh.h

julia> sigaction = Clang.search(children(cursor), c->Clang.name(c) == "sigaction")[1]
CLCursor (CLStructDecl) sigaction

julia> Clang.getCursorType(sigaction) |> Clang.getSizeOf
152

```
