-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
buffer: fix writes into out-of-memory buffers #5232
Conversation
/rebuild |
Sorry @ethomson, an error occurred while trying to requeue the build. |
Apparently you can't rebuild until the build finishes completely. I cancelled & requeued manually. |
Thanks! I tried to read the macOS log that was failing, but it really is completely unreadable due to spam caused by leak checks. :/ |
271f2c6
to
80be48e
Compare
Oops, there was a memory leak in core::buffer::avoid_printing_into_oom_buffer. |
tests/core/buffer.c
Outdated
git_buf buf = GIT_BUF_INIT; | ||
|
||
cl_git_pass(git_buf_puts(&buf, "foobar")); | ||
cl_git_fail(git_buf_try_grow(&buf, SIZE_MAX, true)); |
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.
It looks like macOS isn't behaving the way you want. I think that you're relying on allocation semantics here and that you may need to substitute an intentionally failing allocator here that asserts that it ends up with SIZE_MAX
and fails appropriately.
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.
Yeah, I expected this to happen but hoped it wouldn't, so I just gave it a try. I've fixed the tests to not rely on allocation semantics
df3f334
to
f3c9b51
Compare
If growing a buffer fails, we set its pointer to the static `git_buf__oom` structure. While we correctly free the old pointer if `git__malloc` returned an error, we do not free it if there was an integer overflow while calculating the new allocation size. Fix this issue by freeing the pointer to plug the memory leak.
When growing buffers, we repeatedly multiply the currently allocated number of bytes by 1.5 until it exceeds the requested number of bytes. This has two major problems: 1. If the current number of bytes is tiny and one wishes to resize to a comparatively huge number of bytes, then we may need to loop thousands of times. 2. If resizing to a value close to `SIZE_MAX` (which would fail anyway), then we probably hit an infinite loop as multiplying the current amount of bytes will repeatedly result in integer overflows. When reallocating buffers, one typically chooses values close to 1.5 to enable re-use of resulting memory holes in later reallocations. But because of this, it really only makes sense to use a factor of 1.5 _once_, but not looping until we finally are able to fit it. Thus, we can completely avoid the loop and just opt for the much simpler algorithm of multiplying with 1.5 once and, if the result doesn't fit, just use the target size. This avoids both problems of looping extensively and hitting overflows. This commit also adds a test that would've previously resulted in an infinite loop.
Before printing into a `git_buf` structure, we always call `ENSURE_SIZE` first. This macro will reallocate the buffer as-needed depending on whether the current amount of allocated bytes is sufficient or not. If `asize` is big enough, then it will just do nothing, otherwise it will call out to `git_buf_try_grow`. But in fact, it is insufficient to only check `asize`. When we fail to allocate any more bytes e.g. via `git_buf_try_grow`, then we set the buffer's pointer to `git_buf__oom`. Note that we touch neither `asize` nor `size`. So if we just check `asize > targetsize`, then we will happily let the caller of `ENSURE_SIZE` proceed with an out-of-memory buffer. As a result, we will print all bytes into the out-of-memory buffer instead, resulting in an out-of-bounds write. Fix the issue by having `ENSURE_SIZE` verify that the buffer is not marked as OOM. Add a test to verify that we're not writing into the OOM buffer.
f3c9b51
to
174b7a3
Compare
Finally green with another memory leak fix in the OOM case. |
This fixes two issues with
git_buf
:SIZE_MAX
. While obviously a bogus scenario, I still think the fix is worthwhile.git_buf__oom
buffer.Found while investigating #5199 once again. This is probably not the cause for the observed crashes, though, as the stack traces point somewhere else.