How to debug memory issues when working with an external C library

Has anyone here experience in interfacing Julia to a C++ library via library-provided C bindings, specifically in debugging memory issues?
I am trying to recreate (or at least mimic) the C++ interface in Julia by writing wrappers around the C interface. My idea was to create mutable Julia structs mutable struct X ... end that call the C library’s X_Create function in the constructor X() while also registering a finalizer to the corresponding X_Destroy function. The struct X holds a Ptr{Cvoid} to the data allocated by the C library and passes it to other C functions where necessary.

However, I am experiencing several memory issues of the second worst kind (the worst kind being non-deterministic and/or non-reproducible errors): Errors that disappear when I try to debug them using println. My error looks like this:

signal (11): Segmentation fault
in expression starting at none:1
sig_match_fast at /buildworker/worker/package_linux64/build/src/gf.c:2250 [inlined]
jl_lookup_generic_ at /buildworker/worker/package_linux64/build/src/gf.c:2333 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2394
println at ./coreio.jl:4
example_ckks_basics at /home/mschlott/gdrive/work/code/SEAL.jl/examples/4_ckks_basics.jl:51
unknown function (ip: 0x7f42224ed57c)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2231 [inlined]
...

but when I add a random println("wololo!") somewhere in my Julia code, the error goes away. Not only does this point to some serious memory issues (I know this behavior from writing C/C++ code), but it also makes it virtually impossible to track the error down.
Any idea/hints/pointers to literature on how to track down these memory issues when working with an external C library?

EDIT: Please note that these errors occur even though I have turned off garbage collection by calling GC.enable(false) at the beginning of the function with the offending code.

I have run into these and I don’t have a magic bullet to solve them. I fix them by inspecting my code and re-reading the C API documentation (and sometimes source code) to make sure I know:

  • Who the owner is of each bit of memory that get’s passed back and forth over the API.
  • I have the data types (sizes) correct for EACH of the arguments in the C calls.
  • Re-reading the Julia documentation for the various unsafe calls I’m making and cconvert calls (or heck the entire “Calling C from Julia” section) to ensure I’m using Julia correctly.

Some thing that have also helped is printing log messages in finalizes so I know when Julia is freeing an object that might be used by the C API. Running the API calls in the debugger so I can inspect the memory that should have been initialized by the C function to ensure it’s being set correctly. Then running the calls where I pass that memory back to the C library in the debugger to ensure that the memory is still set correctly.

If you know which function you “just” started using when you started to get the crashes that should help narrow down what you need to look at. It does help if you use a source control system and have checked in “stable” points as you’ve developed. That helps you go back to something that “worked” and see what you have changed since then that might be causing the issue.

Really debugging these situations is a slog, sorry.