-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cleanup StringBuilder
methods
#211
Conversation
…tringBuilder::with_capacity`
use `StringBuilder::reserve` to avoid code duplication in `StringBuilder::push_bytes`. The null check and call to malloc was removed as `libc::realloc` already handles the null case properly. The extra capacity check was removed as `StringBuilder::reserve` only allocates if needed.
The builder would allocate extra capacity even though it is not possible to change the length of the buffer after initialization. This makes it so only the space needed gets allocated.
`StringBuilder::reserve` and `StringBuilder::reserve_exact` already handle the needed space for the null byte.
Fixed things locally, will push the latest version with new tests added and existing ones passing. |
While mainly a fix for previous commits, this adds a few safety checks and optimizations. In cases of inserting even 0 bytes an allocation would be created with a single null byte. This makes it so an allocation is only made if bytes are actually being inserted. NULL checks have been added for realloc as it may return a NULL pointer if it is unable to allocate. Instead of UB it will now panic.
this should be reverted once a more sophisticated string mechanism in place until then this at least decreases the amount that is leaked
We already call `StringBuilder::reserve_exact` so we already know the allocation cannot be shrinked further. This avoids an extra trip to the allocator in `String::from_bytes`.
Added a few safety checks to avoid UB in edge cases. Passes the existing tests and the new ones. The refactor makes it so Lastly, a Should be ready for a review :) Edit: In case the LOC is too much I can split this into multiple parts, though I think it would be pretty annoying to deal with as most of the changes are connected. |
avoids extra computation and checks
no UB, but caused allocations when cap would fit in remaining
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good after comments are addressed and tests pass. Thanks!
Note that a couple of tests are segfaulting. |
Yeah, not really sure why. Weird as nothing seems wrong in the String tests. Looking into it. |
Looked into the neovim source. Down the call chains the string is copied with Not sure if it was intentional but Many of the functions work without an issue but to be safe its likely best to always allocate. For example the failing function relies on the null byte while some of them check the length, in order to even find the null byte the null pointer gets read and causes a segfault or the null pointer is used in a memcpy with mostly the same outcome. I originally though that it could be an issue, but Not really sure what to do from here. Should I refactor the code to always allocate? or just leave this PR for the time being? |
Having to allocate even for empty strings kinda sucks, but it's an upstream issue. I think, at least for the time being, we should just add a comment explaining why we allocate even when not necessary.
I'd have to look into it, but why does Neovim even need strings to be null-terminated when they have a |
Not really sure tbh. I will look into the neovim source code again if I'm misunderstanding something or if there is an underlying bug somewhere. Regardless I am pretty sure that null pointers are a no-no. In case you want to try it out, set the minimum argument to After reading the implementation of nvim_create_user_command I decided to test if A few notes in case someone is trying to fix things:
|
I'll do some more investigation to better understand strings' usage in Neovim. As far as this PR is concerned, I say we just remove or comment out the |
Even though we have a `max_width` of 79, rustfmt doesn't enforce it in comments. I do.
Thanks! |
I haven't added the necessary tests yet so marking this as draft.
Many of
StringBuilder
's methods had logic that really should have been their own function with safe wrappers.This PR moves some logic to their own methods and allows public calls to allocate space without pushing bytes.
This should also reduce the effect of the memory leaks from
String
asString::from_bytes
will now only allocate the minimal amount needed. This shouldn't change performance in any call site as the capacity is not stored, meaning no length changes are possible once aString
is constructed. This only helps to reduce the allocated size where arguments require aString
and a user callsString::from_bytes
.As part of the cleanup a redundant null check was removed from
StringBuilder::push_bytes
aslibc::realloc
already handles the null case.I have made the commit messages to make things are easy to follow.
Will mark this ready for review once I have added some tests.