From d7310bd20974381d6e2ce54dba2fffc71e47da7c Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 12 Sep 2022 12:40:10 +0300 Subject: [PATCH 1/3] gh-94808: Cover `LOAD_GLOBAL` for custom dict subtypes --- Lib/test/test_builtin.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 8c9c1e506752ea..a21acb8a8f5f6e 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -768,6 +768,32 @@ def __setitem__(self, key, value): self.assertRaises(frozendict_error, exec, code, namespace) + # custom `globals` or `builtins` can raise errors on item access + class setonlyerror(Exception): + pass + + class setonlydict(dict): + def __getitem__(self, key): + raise setonlyerror + + class customdict(dict): # this one should not do anything fancy + pass + + # globals' `__getitem__` raises + code = compile("print(globalname)", "test", "exec") + self.assertRaises(setonlyerror, + exec, code, setonlydict({'globalname': 1})) + + # builtins' `__getitem__` raises + code = compile("print(superglobal)", "test", "exec") + self.assertRaises(setonlyerror, exec, code, + {'__builtins__': setonlydict({'superglobal': 1})}) + + # custom builtins dict subclass is missing key + code = compile("print(superglobal)", "test", "exec") + self.assertRaises(NameError, exec, code, + {'__builtins__': customdict()}) + def test_exec_redirected(self): savestdout = sys.stdout sys.stdout = None # Whatever that cannot flush() From 51412c2703ecd01df0c6d3886f552b20b0d053ae Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 12 Sep 2022 21:56:07 +0300 Subject: [PATCH 2/3] Add regex to the last test --- Lib/test/test_builtin.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index a21acb8a8f5f6e..d9fdf034ee9e07 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -780,19 +780,19 @@ class customdict(dict): # this one should not do anything fancy pass # globals' `__getitem__` raises - code = compile("print(globalname)", "test", "exec") + code = compile("globalname", "test", "exec") self.assertRaises(setonlyerror, exec, code, setonlydict({'globalname': 1})) # builtins' `__getitem__` raises - code = compile("print(superglobal)", "test", "exec") + code = compile("superglobal", "test", "exec") self.assertRaises(setonlyerror, exec, code, {'__builtins__': setonlydict({'superglobal': 1})}) # custom builtins dict subclass is missing key - code = compile("print(superglobal)", "test", "exec") - self.assertRaises(NameError, exec, code, - {'__builtins__': customdict()}) + code = compile("superglobal", "test", "exec") + self.assertRaisesRegex(NameError, "name 'superglobal' is not defined", + exec, code, {'__builtins__': customdict()}) def test_exec_redirected(self): savestdout = sys.stdout From 911bca163b54b76afa5366d6f9838a9dbadac115 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 4 Nov 2022 12:30:40 +0300 Subject: [PATCH 3/3] Address review --- Lib/test/test_builtin.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index d9fdf034ee9e07..8758fe4de9be90 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -737,6 +737,7 @@ def test_exec_globals(self): self.assertRaises(TypeError, exec, code, {'__builtins__': 123}) + def test_exec_globals_frozen(self): class frozendict_error(Exception): pass @@ -768,6 +769,7 @@ def __setitem__(self, key, value): self.assertRaises(frozendict_error, exec, code, namespace) + def test_exec_globals_error_on_get(self): # custom `globals` or `builtins` can raise errors on item access class setonlyerror(Exception): pass @@ -776,9 +778,6 @@ class setonlydict(dict): def __getitem__(self, key): raise setonlyerror - class customdict(dict): # this one should not do anything fancy - pass - # globals' `__getitem__` raises code = compile("globalname", "test", "exec") self.assertRaises(setonlyerror, @@ -789,8 +788,14 @@ class customdict(dict): # this one should not do anything fancy self.assertRaises(setonlyerror, exec, code, {'__builtins__': setonlydict({'superglobal': 1})}) - # custom builtins dict subclass is missing key + def test_exec_globals_dict_subclass(self): + class customdict(dict): # this one should not do anything fancy + pass + code = compile("superglobal", "test", "exec") + # works correctly + exec(code, {'__builtins__': customdict({'superglobal': 1})}) + # custom builtins dict subclass is missing key self.assertRaisesRegex(NameError, "name 'superglobal' is not defined", exec, code, {'__builtins__': customdict()})