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.
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.
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.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Probably because you're creating
CString
s 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.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.
No problem. Clippy also has a lint (temporary_cstring_as_ptr) that's intended to catch that particular "create a
CString
, callas_ptr
, drop theCString
" mistake, though I'm not sure how reliably it does so.