loading...

Discussion on: Writing an Emacs module in Rust

Collapse
ssokolow profile image
Stephan Sokolow

I found that if I put that behind a function I suddenly get segfaults. I'm not sure why.

Probably because you're creating CStrings and not holding onto an owning binding to them. as_ptr is a bit of a footgun because raw pointers are exempt from ownership/borrow checking.

(as_ptr doesn't force the memory to remain live, so whether your code works or not depends entirely on whether your system allocator has unmapped that now-marked-as-unused portion of the heap by the time Emacs tries to dereference the pointer you returned.)

What you need to do is use CString::into_raw instead of as_ptr, which will transfer ownership to C by telling Rust to forget to clean up the memory backing the pointer.

Then, to prevent a memory leak, implement whatever API Emacs exposes for asking plugins to free memory they allocated and use CString::from_raw to reclaim ownership so Rust can free it when it falls out of scope.

Alternatively, for a constant string, include the terminal null in your string literal so you don't need CString to make a copy of it to add the null, and then you can call str::as_ptr to pass Emacs a pointer to a string literal that will live, unchanged, for the whole lifetime of the program because it's baked into the binary.

Collapse
rfaulhaber profile image
Ryan Faulhaber Author

Oooh that makes a lot of sense, thank you! In my eagerness to satisfy type checking I evidently didn't think to look at the CString documentation closer. I think I'll try this and update the code accordingly.

Collapse
ssokolow profile image
Stephan Sokolow

No problem. Clippy also has a lint (temporary_cstring_as_ptr) that's intended to catch that particular "create a CString, call as_ptr, drop the CString" mistake, though I'm not sure how reliably it does so.