gh-152405: Do not expose the internal mapping when rich-comparing MappingProxyType objects - #152483
Conversation
|
Would it be worth optimizing the common case where an exact (any?)dict is ultimately being compared with another exact (any?)dict. Because if it's just going to go through the dict comparison operator then it should be safe? |
|
The other variation that I was thinking about (but is untested so I might have missed a detail), is to do exact (any?)dict <-> exact (any?)dict specifically*, and then return not implemented for anything else. I think the result of that is that it would then fall back to the other classes' comparison operator, which would presumably be able to use the mapping interface of the proxy type to do the comparison. [*] possibly also with a a check for the comparison operator because the collections.OrderDict just uses the dict comparison operator |
This comment was marked as outdated.
This comment was marked as outdated.
That does suggest it might be get you a huge amount of benefit. Ah well... |
|
On more comment (then I stop thinking about this): if you're only concerned about the crash and not the leak then the only case you're really worried about is |
|
@da-woods thanks a lot for your help and ideas! I am not sure that |
I think it's just "not the dict comparison operator". I've put an alternative (draft) proposal in #152489 mostly to see if it works and passes everything. It intentionally isn't complete though and is just a quick C code suggestion right now. |
This comment was marked as outdated.
This comment was marked as outdated.
|
@da-woods please, check my new approach :) |
|
Yes - I believe that will work. It may be worth special casing not making the copy when you know the right-hand side is another exact anydict. But that's a minor implementation detail. If I was starting from scratch with no existing tests or behaviour then I think I'd prefer my approach. But obviously Python is very much not starting from scratch. So yeah - I'd agree that this fixes the important problem in the least modifying way. |
vstinner
left a comment
There was a problem hiding this comment.
Would you mind to add tests on frozendict?
|
I wonder whether we really need a copy. It will undoubtly make the comparisons slower for a case that is honestly not realistic. I don't know how often people use I'm more concerned with the behavior change. Is it still a behavior change? Because that behavior change may still break code that was previously not crashing (albeit incorrect). If I were to compare two mappings like that it's hard to decide whether the |
I think that I confused you with the older outdated description.
I will only make things noticably slower for cases where we compare |
|
I don't think "Fix crash" is accurate. This PR only reduces one case where the underlying dict leaks. Python is a very dynamic language, and it does not guarantee that users cannot access the built-in type dict. Being able to access the underlying dict is not a bug, nor is it a cause of crashes. What we should consider is whether we can safely make changes to the built-in type dict, and if not, whether we should reduce Python's dynamic nature a bit and make it a frozendict. |
How would you rephrase it? :)
Sounds like a good idea! But, it is clearly out of scope of this PR. |
MappingProxyType objectsMappingProxyType objects
|
I changed the wording to be not about the crash :)
I will soon merge the PR if there's no other feedback to address. |
|
Thanks @sobolevn for the PR 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14, 3.15. |
|
Sorry, @sobolevn, I could not cleanly backport this to |
|
GH-153670 is a backport of this pull request to the 3.15 branch. |
|
Sorry, @sobolevn, I could not cleanly backport this to |
|
#136204 was not backported to 3.13 and 3.14, so I propose not to backport this as well. |
|
Making a full copy in the comparison operator? I do not think it is worth to do. What the problem does it fix? Note that intentionally written malicious code is not the problem which we should fix. |
A comparison operator can modify the mappingproxy internal mapping which is supposed to be impossible.
What do you suggest? Reverting the change? |
A comparison operator is supposed to not modify its operands.
If nothing changed since making the previous decision (#88004), then reverting the change. Or wider discussion to re-evaluate it. |
@sobolevn: What do you think? Can you consider to revert the change? I'm not sure on what to do. In general, we try to avoid cases where "regular Python code" can crash Python. And the initial reproducer leads to a crash: #152405 (comment). Or do you need a discussion on discuss.python.org on how to deal with the increasing number of bug reports about "evil code" triggering crashes? |
This is an alternative to #152449
Now I send a copy of the
dictif it is under a mapping, so it can't be mutated.Credit for this idea goes to @da-woods in this comment