Author ncoghlan
Recipients ncoghlan
Date 2021-07-10.06:55:39
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1625900140.09.0.950032205736.issue44596@roundup.psfhosted.org>
In-reply-to
Content
The fast locals proxy implementation for PEP 558 used the existing MappingProxyType implementation as a starting point.

This meant I noticed the following code in the mapping proxy comparison implementation:

======
static PyObject *
mappingproxy_richcompare(mappingproxyobject *v, PyObject *w, int op)
{
    return PyObject_RichCompare(v->mapping, w, op);
}
======

Seeing that code lead to trying the following experiment:

==========
>>> from types import MappingProxyType
>>> d = {}
>>> proxy = MappingProxyType(d)
>>> class Sneaky:
...     def __eq__(self, other):
...         if other is d:
...             raise RuntimeError("Broke encapsulation")
... 
>>> proxy == Sneaky()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __eq__
RuntimeError: Broke encapsulation
==========

The new `__or__` implementation has a corresponding loophole:

========
>>> class SneakyOr:
...     def __or__(self, other):
...         if other is d:
...             raise RuntimeError("Broke encapsulation")
...     def __ror__(self, other):
...         return self.__or__(other)
... 
>>> proxy | SneakyOr()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __ror__
  File "<stdin>", line 4, in __or__
RuntimeError: Broke encapsulation
========

Delegating these operations to the underlying mapping via the abstract operation layer means that the underlying mapping gets exposed to the operand coercion machinery and can hence be accessed by the other operand.
History
Date User Action Args
2021-07-10 06:55:40ncoghlansetrecipients: + ncoghlan
2021-07-10 06:55:40ncoghlansetmessageid: <1625900140.09.0.950032205736.issue44596@roundup.psfhosted.org>
2021-07-10 06:55:40ncoghlanlinkissue44596 messages
2021-07-10 06:55:39ncoghlancreate