Skip to content

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

Merged
vstinner merged 4 commits into
python:masterfrom
ariccio:fix-parsetok-realloc-leak
Mar 30, 2020
Merged

bpo-40020: fix realloc leak on failure in growable_comment_array_add#19083
vstinner merged 4 commits into
python:masterfrom
ariccio:fix-parsetok-realloc-leak

Conversation

@ariccio

@ariccio ariccio commented Mar 20, 2020

Copy link
Copy Markdown
Contributor

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

ariccio commented Mar 20, 2020

Copy link
Copy Markdown
Contributor Author

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

@corona10 corona10 left a comment

Copy link
Copy Markdown
Member

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
Copy Markdown
Member

@vstinner Please take a look :)

Comment thread Parser/parsetok.c Outdated
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

ariccio commented Mar 25, 2020

Copy link
Copy Markdown
Contributor Author

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

ariccio commented Mar 30, 2020

Copy link
Copy Markdown
Contributor Author

Ok, how does this look?

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

Copy link
Copy Markdown
Member

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

@ariccio

ariccio commented Mar 31, 2020

Copy link
Copy Markdown
Contributor Author

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