codekingpro/portable-devtools
114k
1# -*- coding: utf-8 -*-
2"""
3If we have a run callable passed to the constructor or set as an
4attribute, but we don't actually use that (because ``__getattribute__``
5or the like interferes), then when we clear callable before beginning
6to run, there's an opportunity for Python code to run.
7
8"""
9import greenlet
10
11g = None
12main = greenlet.getcurrent()
13
14results = []
15
16class RunCallable:
17
18 def __del__(self):
19 results.append(('RunCallable', '__del__'))
20 main.switch('from RunCallable')
21
22
23class G(greenlet.greenlet):
24
25 def __getattribute__(self, name):
26 if name == 'run':
27 results.append(('G.__getattribute__', 'run'))
28 return run_func
29 return object.__getattribute__(self, name)
30
31
32def run_func():
33 results.append(('run_func', 'enter'))
34
35
36g = G(RunCallable())
37# Try to start G. It will get to the point where it deletes
38# its run callable C++ variable in inner_bootstrap. That triggers
39# the __del__ method, which switches back to main before g
40# actually even starts running.
41x = g.switch()
42results.append(('main: g.switch()', x))
43# In the C++ code, this results in g->g_switch() appearing to return, even though
44# it has yet to run.
45print('In main with', x, flush=True)
46g.switch()
47print('RESULTS', results)
48 