-2

I needed to call Rust code from my Go code. Then I used C as my interface. I did this:

I've created a Rust library that takes a CStr as a parameter, and returns a new processed string back as CStr. This code is statically compiled to a static C library my_lib.a.
Then, this library is statically linked with my Go code, that then calls the library API using CGo (Go's representation to C String, just like Rusts's Cstr).

The final Go binary is sitting inside a docker container in my kubernetes. Now, my problem is that is some cases where the library's API is called, my pod (container) is crashing. Due to the nature of using CStr and his friends, I must use unsafe scopes in some places, and I highly suspect a segfault that is caused by one of the ptrs used in my code, but I have no way of communicating the error back to the Go code that could be then printed OR alternatively get some sort of a core dump from Rust/C so I can point out the problematic code. The pod just crashes with no info whatsoever, at least to my knowledge..

So my question is, how can I:

  1. Recover from panic/crashes that happen inside an unsafe code? or maybe wrap it with a recoverable safe scope?
  2. Override the SIG handlers so I can at least "catch" the errors and not crash? So I can debug it.
  3. Perhaps communicate a signal interruption that was caused in my c-lib that was generated off Rust back to the caller?

I realize that once Rust is compiled to a c-library, it is a matter of C, but I have no idea how to tackle this one.

Thanks!

Magmus
  • 207
  • 2
  • 11
  • Why not use a debugger to debug instead of overriding signal handlers? – PiRocks Mar 15 '22 at 14:30
  • 1
    A segfault is not the kind of error you communicate back to code. A segfault means your program is over. – PiRocks Mar 15 '22 at 14:32
  • @PiRocks do you mean installing and running the binary in gdb (for example)? What I meant by communicating back to the code, is for example the stack trace at the moment the segfault happened. I'm just currently "blind" to where is the issue. Trying to get a hint on it. – Magmus Mar 15 '22 at 14:36
  • yeah by debugger I mean just run it gdb, gdb will pause on segfault and you can get stacktrace, examine variable values etc... – PiRocks Mar 15 '22 at 18:02

1 Answers1

2

I've created a Rust library that takes a CStr as a parameter, and returns a new processed string back as CStr.

Neither operation seems OK:

  • the CStr documentation specifically notes that CStr is not repr(C)
  • CStr is a borrowed string, a "new processed string" would have to be owned (so a CString, which also isn't repr(C)).

Due to the nature of using CStr and his friends, I must use unsafe scopes in some places, and I highly suspect a segfault that is caused by one of the ptrs used in my code, but I have no way of communicating the error back to the Go code that could be then printed OR alternatively get some sort of a core dump from Rust/C so I can point out the problematic code. [...] Recover from panic/crashes that happen inside an unsafe code? or maybe wrap it with a recoverable safe scope?

If you're segfaulting there's no panic or crash which Rust can catch or manipulate in any way. A segfault means the OS itself makes your program go away. However you should have a core dump the usual way, this might be a configuration issue with your container thing.

Override the SIG handlers so I can at least "catch" the errors and not crash? So I can debug it.

You can certainly try to handle SIGSEGV, but after a SIGSEGV I'd expect the program state to be completely hosed, this is not an innocuous signal.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • Thanks for the detailed answer. By saying "a new processed string" I meant a rust String that is then converted to CStr and returned from the program - just to match the in and out parameter type. I don't mind owning it or pass ownership in that matter. A question if I may: In my case, what variable types should I use then if I want to be able to pass a real c string (aka char*) and return one? Because to my understanding, Rust offers CStr exactly for that purpose. – Magmus Mar 15 '22 at 14:55
  • About the segfault - I'm still assuming this is an acutal segfault, as I suspect a null deref or something in that area of my pointers mess. But a core dump surely can shed some light. I'll see what my container offers in regards to it. – Magmus Mar 15 '22 at 14:56
  • 1
    "a rust String that is then converted to CStr and returned from the program" - and freed at the end of its scope, so the pointer inside the `CStr` is now dangling. – Cerberus Mar 16 '22 at 04:18
  • @Magmus as @cerberus says that is very much not OK, `CStr` is an `&str`-like wrapper, so you get a reference, convert it to a `CStr`, then the string is released and your `CStr` is dangling. And then the return value is corrupt because `CStr` is not C-safe. If your understanding is that's what `CStr` is I fear your understanding is deeply lacking indeed, as the `CStr` documentation quite clearly says it's not. – Masklinn Mar 16 '22 at 06:35
  • 1
    The types of C strings are `*const c_char` and `*mut c_char`. `CStr` and `CString` are *rust-side helpers* for manipulating these, and converting to and from actual rust strings. [The correct way to *return* a string *to* C](http://jakegoulding.com/rust-ffi-omnibus/string_return/) is to use `CString::into_raw()` in order to get a pointer, then deallocate by sending the string back to Rust, reviving it using `CString::from_raw`, and dropping that. – Masklinn Mar 16 '22 at 06:38
  • Thanks for the detailed explanation guys. I have re-read the API docs, and I think I better understand it now. I do actually use `CString::into_raw()` while returning the manipulated string, but I certainly never counter it with a `CString::from_raw` as I should, which will definitely result in a mem leak. I also didn't check for null when I converted my input `const c_char*` to a rust `String`, which can for sure cause a segfault. If I'll have additional questions about moving between Rust and C I'll just search/ask on another thread. Cheers! – Magmus Mar 16 '22 at 10:33