Skip to content

bpo-40020: fix realloc leak on failure in growable_comment_array_add #19083

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

Merged
merged 4 commits into from
Mar 30, 2020

Conversation

ariccio
Copy link
Contributor

@ariccio ariccio commented Mar 20, 2020

Fixes bpo-40020. I have signed the CLA, but I don't know if it's active yet.

I don't have make installed on this machine, but I'm setting it up right now to get the patchcheck run. Will update.

realloc returns a null pointer on failure, and then growable_comment_array_deallocate crashes later when it dereferences it.

https://bugs.python.org/issue40020

Realloc returns a null pointer on failure, and then growable_comment_array_deallocate crashes later when it dereferences it.
@ariccio
Copy link
Contributor Author

ariccio commented Mar 20, 2020

are the workflow tests the same thing as the patchcheck tests?

Copy link
Member

@corona10 corona10 left a comment

Choose a reason for hiding this comment

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

I am LGTM with this change
The realloc(3) says that

If realloc() fails the original block is left untouched; it is not freed or moved

Please ignore the test failure, it's the known issue.

@corona10
Copy link
Member

@vstinner Please take a look :)

@@ -38,10 +38,11 @@ static int
growable_comment_array_add(growable_comment_array *arr, int lineno, char *comment) {
if (arr->num_items >= arr->size) {
arr->size *= 2;
arr->items = realloc(arr->items, arr->size * sizeof(*arr->items));
if (!arr->items) {
void *const new_items_array = realloc(arr->items, arr->size * sizeof(*arr->items));
Copy link
Member

Choose a reason for hiding this comment

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

I don't see the purpose of "const" here. I suggest to remove it. realloc() return type is void *.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I mean, hey, if you guys don't like const correctness, I can do that. Thankfully, I have enough control over my OCD that it works for me :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, while I'm here, should I also not double the array size on the failure path?

And should I squash the multiple commits?

Copy link
Member

Choose a reason for hiding this comment

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

"hey, if you guys": please use a more inclusive expressions, see https://heyguys.cc/ ;-)

"don't like const correctness": it's assigned to arr->items 3 lines below but growable_comment_array.items isn't constant. I don't see the value of using const here.

You should read https://theartofmachinery.com/2019/08/12/c_const_isnt_for_performance.html "Why const Doesn't Make C Code Faster" :-)

Copy link
Member

Choose a reason for hiding this comment

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

should I also not double the array size on the failure path?

Right, arr->size should only be modified on success. Replace maybe realloc(arr->items, arr->size * sizeof(*arr->items)) with realloc(arr->items, (arr->size * 2) * sizeof(*arr->items)).

And should I squash the multiple commits?

That's harmful for reviewers. I prefer to see new commits.

We always squash all commits of a PR when it's merged.

Copy link
Member

Choose a reason for hiding this comment

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

Let me explain differently: your usage of const is correct. But IMHO it's not worth it, and I see it more as an annoyance for readers.

@vstinner
Copy link
Member

Once this change will be merged, I would be interested to see a second change to replace realloc() and free() with PyMem_RawRealloc() and PyMem_RawFree(), to benefit of Python builtin memory debugger. Like detecting buffer underflow and overflow in debug mode: https://docs.python.org/dev/c-api/memory.html#c.PyMem_SetupDebugHooks See PYTHONMALLOC=debug.

tracemalloc may also benefit of that, but mostly to measure the peak memory usage. I expect that the parser memory is released before the user gets back control on the program.

@ariccio
Copy link
Contributor Author

ariccio commented Mar 25, 2020

Once this change will be merged, I would be interested to see a second change to replace realloc() and free() with PyMem_RawRealloc() and PyMem_RawFree(), to benefit of Python builtin memory debugger.

As an interesting side note, I think code analysis only found this because the code used raw realloc and free, since PyMem_RawRealloc and PyMem_RawFree aren't annotated.

@ariccio
Copy link
Contributor Author

ariccio commented Mar 30, 2020

Ok, how does this look?

@vstinner vstinner merged commit 51e3e45 into python:master Mar 30, 2020
@vstinner
Copy link
Member

I merged your PR, thanks. I don't think that it's worth it to backport the fix.

@ariccio
Copy link
Contributor Author

ariccio commented Mar 31, 2020

Backport? Nah, no need.

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.

5 participants