This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: LOAD_NAME and LOAD_GLOBAL, STORE_GLOBAL handle dict subclasses for globals() differently
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: duplicate
Dependencies: Superseder:
Assigned To: Nosy List: Kevin Shweh, pablogsal, pfalcon, ppperry, serhiy.storchaka, vstinner
Priority: normal Keywords:

Created on 2019-03-07 03:41 by Kevin Shweh, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 18033 closed pfalcon, 2020-01-16 20:45
Messages (6)
msg337356 - (view) Author: Kevin Shweh (Kevin Shweh) Date: 2019-03-07 03:41
LOAD_NAME and LOAD_GLOBAL don't treat dict subclasses for globals() the same way. If globals() is a dict subclass, LOAD_GLOBAL will respect overridden __getitem__, but LOAD_NAME will use PyDict_GetItem. This causes global lookup to behave differently in class statements; for example, in the following code, the final exec is the only one where print(y) causes a NameError:

class Foo(dict):
    def __getitem__(self, index):
        return 5 if index == 'y' else super().__getitem__(index)
 
exec('print(y)', Foo())
exec('global y; print(y)', Foo())
exec('''
class UsesLOAD_NAME:
    global y
    print(y)''', Foo())
exec('''
class UsesLOAD_NAME:
    print(y)''', Foo())


STORE_GLOBAL and DELETE_GLOBAL also go straight for PyDict_SetItem and PyDict_DelItem; I don't know whether those should be considered bugs as well, but the inconsistency between LOAD_NAME and LOAD_GLOBAL definitely seems wrong.

(For reference, the change that introduced the inconsistency was made for issue #14385, which was intended to support non-dict __builtins__.)
msg337388 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-03-07 11:45
I wrote bpo-14385 when I was working on my PEP 410. The PEP has been rejected, I'm not sure anymore that it was a good idea to modify ceval.c :-( But I never tried to measure the overhead of the additional "if (PyDict_CheckExact(...))".
msg337389 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-03-07 11:45
Oops sorry, it was the PEP 416: Add a frozendict builtin type. I wanted to write a sandbox for Python.
msg359046 - (view) Author: Paul Sokolovsky (pfalcon) * Date: 2019-12-30 16:18
> I wanted to write a sandbox for Python.

Sandbox indeed, it is.

class NS(dict):

    def __setitem__(self, k, v):
        if not isinstance(v, type(lambda: 0)):
            raise RuntimeError("Global variables considered harmful")

globals = NS()

exec("foo = 1", globals)

But then:

exec("""
global foo
foo = "watch me escaping your sandboxes"
""", globals)

This is due to STORE_GLOBAL not handling dict subclasses, unlike STORE_NAME.


While @Kevin Shweh's issue with LOAD_NAME, and @vstinner's concerns of adding yet another branch to LOAD_NAME implementation may be one matter, issue with STORE_GLOBAL is both related and somewhat different. STORE_GLOBAL's should be relatively infrequent, so adding another branch to it unlikely will be quantifiable in performance. But lack of its support disallows to write to tools which police/constrain Python's overdynamicity, which is useful in the age.

Anyway, I decided to not open a separate ticket for this, but add here. Fairly speaking, as long as work to support dict subclasses as globals/locals started, the only reasonable way forward seems to implement it completely.
msg359052 - (view) Author: (ppperry) Date: 2019-12-30 18:51
Duplicate of issue32615
msg359053 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2019-12-30 19:20
Closed as duplicate of issue32615.
History
Date User Action Args
2022-04-11 14:59:12adminsetgithub: 80401
2020-01-16 20:45:40pfalconsetpull_requests: + pull_request17429
2019-12-30 19:20:24pablogsalsetstatus: open -> closed

nosy: + pablogsal
messages: + msg359053

resolution: duplicate
stage: resolved
2019-12-30 18:51:08ppperrysetnosy: + ppperry
messages: + msg359052
2019-12-30 16:18:36pfalconsetmessages: + msg359046
2019-12-30 16:02:29pfalconsetnosy: + pfalcon

title: LOAD_NAME and LOAD_GLOBAL handle dict subclasses for globals() differently -> LOAD_NAME and LOAD_GLOBAL, STORE_GLOBAL handle dict subclasses for globals() differently
2019-03-07 11:45:36vstinnersetmessages: + msg337389
2019-03-07 11:45:06vstinnersetmessages: + msg337388
2019-03-07 03:48:18serhiy.storchakasetnosy: + vstinner, serhiy.storchaka
2019-03-07 03:41:26Kevin Shwehcreate