Skip to content
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

Fix realloc memory leak #1458

Open
wants to merge 2 commits into
base: production
Choose a base branch
from

Conversation

lazydroid
Copy link
Collaborator

realloc() may return NULL, so when we do:

foobar = realloc( foobar );

we risk leaking memory, better implementation would be:

maybe_good = realloc( foobar )
foobar = maybe_good != NULL ? maybe_good : foobar
....
free( foobar )

@lazydroid
Copy link
Collaborator Author

the change did not seem to break anything important

image

@lazydroid lazydroid marked this pull request as ready for review October 28, 2024 11:04
Copy link
Collaborator

@rschlaikjer rschlaikjer left a comment

Choose a reason for hiding this comment

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

Seems fine. Should it attempt to still log however many bytes were written to the buffer before it failed to realloc to try and eke out potentially useful logs in an OOM situation? If realloc actually returns nullptr all bets are off though. Overcommit means that it's unlikely to ever actually happen (allocation will succeed, program will just trap on access).

@lazydroid
Copy link
Collaborator Author

log however many bytes were written to the buffer before it failed

I'm not sure there's anything guaranteed to be written if there's not enough space: "A negative number is returned on failure, including when the resulting string to be written to ws would be longer than n characters."

@rschlaikjer
Copy link
Collaborator

Nothing is guaranteed, but the implementation in glibc writes directly to the buffer as it goes, so you will likely have some large fraction of wslen bytes holding valid formatted data (assuming this is not the first call to realloc, in which case the valid data is in the stacked buffer, but same idea). Sticking a \0 on the end of the buffer in the failure case and returning wslen bytes written would attempt to print as much as it could, with some amount of junk on the end.

This is mostly an idle thought - I think we are unlikely to hit this codepath regardless.

wchar_t* wsnext = (wchar_t*)realloc(wsallocated, wslen*sizeof(wchar_t)); \
/* realloc() can return NULL, need to remember previous allocation to avoid memory leaks */ \
if (wsnext != NULL) { \
wsallocated = wsnext; \
Copy link
Owner

Choose a reason for hiding this comment

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

I'm confused here. Don't you have to change wslen back to the original value? Otherwise vswprintf will happily write beyond the buffer, and now we have memory corruption.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

When we get a NULL, wr becomes -1 and we get straight to this part (skipping printing):

        if (wsallocated != NULL) { \
            free(wsallocated); \
            wsallocated = NULL; \
        } \

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.

3 participants