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

Correct overflow check in PyTuple_New() #14838

Merged
merged 2 commits into from Sep 9, 2019

Conversation

sir-sigurd
Copy link
Contributor

Currently this overflow check overestimates tuple size. It's introduced in this form in 3ce5d92#diff-cde4fb3109c243b2c2badb10eeab7fcdR63.

Copy link
Contributor

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Nice catch! I am curious how you discovered this. 🙂

From the linked commit, I definitely agree that a sign seems to have gone wrong in the algebra there, and this fixes the logic to work like it did before.

Unpeeling a couple of layers to see the allocation, I also agree that this is a correct fix! So I'm in favor of merge.

@gnprice
Copy link
Contributor

gnprice commented Aug 1, 2019

I feel like there's an opportunity for a more complete fix as a followup to this.

My next question on reading this is, OK, how can we write this so it's hard to get wrong? That commit you linked to, with the algebra mistake, is a few weeks shy of 11 years old. 😉

I think the point is that PyObject_GC_NewVar really has a precondition, that the nitems it's passed (size in this caller) not be so big that the allocation will overflow. Specifically _PyObject_VAR_SIZE(tp, nitems) needs to not overflow. All the trickiness in this overflow check is basically an algebraic rearrangement of what _PyObject_VAR_SIZE(&PyTuple_Type, size) would say, plus substituting in the values actually found at &PyTuple_Type.

So, a sort of minimal fix would be to make something with a name like PyObject_GC_NewVar_WouldOverflow that encodes that. Maybe that in turn would just be a macro to delegate to a _PyObject_VAR_SIZE_WOULD_OVERFLOW, so that each layer only has to know what it actually knows.

I think that immediately raises a next question, though, which is: are other call sites of PyObject_GC_NewVar checking properly for overflow? At a quick grep, I see some that don't appear to be checking.

And: why should they have to? It seems like the best place for this check is immediately before the possibly-overflowing computation; or if not there, then the closer to it the better. So ideally _PyObject_VAR_SIZE itself would be augmented to first do this check, and only if it won't overflow then go and actually multiply.

There are only a handful of call sites of _PyObject_VAR_SIZE, so it wouldn't even be much of a migration to then take care of each of them.

@Yhg1s
Copy link
Member

Yhg1s commented Sep 9, 2019

Let's merge this fix, and move the discussion on a better way to express this to a bug. (Please open that bug if you still want to have that discussion.)

@Yhg1s Yhg1s merged commit 755d4ef into python:master Sep 9, 2019
@sir-sigurd sir-sigurd deleted the tuple-overflow-check branch September 10, 2019 00:40
@gnprice
Copy link
Contributor

gnprice commented Sep 10, 2019

Thanks @Yhg1s for merging this (and @sir-sigurd for the PR)!

Filed bpo-38079 for the followup I suggested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants