Skip to content

Conversation

@Rua
Copy link
Contributor

@Rua Rua commented Nov 7, 2025

I opted to store the final strings as Vec<u8> rather than as CString, because the latter does not have a way to get a mutable pointer/reference without leaking it. This is because of the nul termination invariant that CString must uphold.

@Rua Rua force-pushed the main-leak branch 3 times, most recently from e309b65 to e10b712 Compare November 8, 2025 08:53
Copy link
Contributor

@kkysen kkysen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a snapshot test for this, too?

@Rua Rua force-pushed the main-leak branch 2 times, most recently from 326ac44 to ba0f652 Compare November 11, 2025 09:04
Copy link
Contributor

@kkysen kkysen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, can you also do the thing where the snapshot test is added first before the fix, then updated along with the fix? Thanks!

@kkysen kkysen self-requested a review November 16, 2025 01:19
Comment on lines +22 to +28
let mut args_strings: Vec<Vec<u8>> = ::std::env::args()
.map(|arg| {
::std::ffi::CString::new(arg)
.expect("Failed to convert argument into CString.")
.into_bytes_with_nul()
})
.collect();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to store a Vec<CString> here. It's clearer what it's supposed to represent that way, and we can call CString::raw on it (c_string.into_raw().cast::<c_char>()).

Copy link
Contributor Author

@Rua Rua Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that would reintroduce the leak. I used Vec<u8> because it lets you get a mutable reference without leaking, which CString does not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How exactly? I might've not been clear enough. I'm suggesting we store args_strings: Vec<CString> and args_ptrs: Vec<*mut c_char>. CString is owning just like Vec<u8> is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But how do you get from CString to *mut c_char?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry, .into_raw() is wrong since it takes self. But you can use .as_ptr() from CStr that takes &self.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That gives you an immutable pointer, and casting that to mutable could introduce UB if the user code writes to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generated wrapper main leaks memory of args

2 participants