fail_clearing_run_switches.py 1.2 KB

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