On Tue, 2021-01-19 at 16:22 +0000, Mark Shannon wrote: > > > On 19/01/2021 3:43 pm, Sebastian Berg wrote: > > On Tue, 2021-01-19 at 13:31 +0000, Mark Shannon wrote: > > > Hi everyone, > > > > > > It's time for yet another PEP :) > > > > > > Fortunately, this one is a small one that doesn't change much. > > > It's aim is to make the VM more robust. > > > > > > Abstract > > > ======== > > > > > > This PEP proposes that machine stack overflow is treated > > > differently > > > from runaway recursion. This would allow programs to set the > > > maximum > > > recursion depth to fit their needs and provide additional safety > > > guarantees. > > > > > > The following program will run safely to completion: > > > > > > sys.setrecursionlimit(1_000_000) > > > > > > def f(n): > > > if n: > > > f(n-1) > > > > > > f(500_000) > > > > > > The following program will raise a StackOverflow, without causing > > > a > > > VM > > > crash: > > > > > > sys.setrecursionlimit(1_000_000) > > > > > > class X: > > > def __add__(self, other): > > > return self + other > > > > > > X() + 1 > > > > > > > > > This is appreciated! I recently spend quite a bit of time trying to > > solve a StackOverflow like this in NumPy (and was unable to fully > > resolve it). Of course the code triggering it was bordering on > > malicious, but it would be nice if it was clear how to not > > segfault. > > > > Just some questions/notes: > > > > * We currently mostly use `Py_EnterRecursiveCall()` in situations > > where > > we need to safe-guard against "almost python" recursions. For > > example > > an attribute lookup that returns `self`, or a list containing > > itself. > > In those cases the python recursion limit seems a bit nicer (lower > > and > > easier to understand). > > I am not sure it actually matters much, but my question is: Are we > > sure > > we want to replace all (or even many) C recursion checks? > > Would it help if you had the ability to increase and decrease the > recursion depth, as `Py_EnterRecursiveCall()` currently does? > > I'm reluctant to expose it, as it might encourage C code authors to > use > it, rather than `Py_CheckStackDepth()` resulting in crashes. > > To be robust, C code must make a call to `Py_CheckStackDepth()`. > To check the recursion limit as well would be extra overhead. > > > > > * Assuming we swap `Py_EnterRecursiveCall()` logic, I am wondering > > if a > > new `StackOverflow` exception name is useful. It may create two > > names > > for almost identical Python code: If you unpack a list containing > > itself compared to a mapping implementing `__getitem__` in Python > > you > > would get different exceptions. > > True, but they are different. One is a soft limit that can be > increased, > the other is a hard limit that cannot (at least not easily).
Right. I think my confusion completely resolves around your proposed
change of `Py_EnterRecursiveCall()`.
A simple example (written in C):
def depth(obj, current=0):
Py_EnterRecursiveCall()
if isinstance(obj, sequence): # has the sequence slots
return depth(obj[0], current+1)
return current
will never hit the "depth" limit for a self containing list or even
sequence (as long as `GetItem` can use the C-level slot).
But `obj[0]` could nevertheless return a non-trivial object (one with
`__del__`, definitely a container with unrelated objects that could use
deleting).
As the author of the function, I have no knowledge over how much stack
space cleaning those up may require?
And say someone adds a check for `Py_CheckStackDepth()` inside a
dealloc, then this might have to cause a fatal error?
Maybe it should even be a fatal error by default in some cases?
Also, if the code is slow, the previous recursion may guard against
hanging (arguably, if that is the case I probably add an interrupt
check, I admit).
Long story short, I will trust you guys on it of course, but I am not
yet convinced that replacing the check will actually do any good (as
opposed to adding and/or providing the additional check) or even be a
service to users (since I assume that the vast majority do not crank up
the recursion limit to huge values).
Cheers,
Sebastian
>
> >
> > * `Py_CheckStackDepthWithHeadRoom()` is usually not necessary,
> > because
> > `Py_CheckStackDepth()` would leave plenty of headroom for typical
> > clean-up?
>
> What is "typical" clean up? I would hope that typical cleanup is to
> return immediately.
>
> > Can we assume that DECREF's (i.e. list, tuple), will never check
> > the
> > depth, so head-room is usually not necessary? This is all good,
> > but I
> > am not immediately sure when `Py_CheckStackDepthWithHeadRoom()`
> > would
> > be necessary (There are probably many cases where it clearly is,
> > but is
> > it ever for fairly simple code?).
>
> Ideally, Dealloc should call `Py_CheckStackDepth()`, but it will need
> to be very cheap for that to be practical.
>
> If C code is consuming the stack, its responsibility is to not
> overflow.
> We can't make you call `Py_CheckStackDepth()`, but we can provide it,
> so
> you that will have no excuse for blowing the stack :)
>
> > What happens if the maximum stack depth is reached while a
> > `StackOverflow` exception is already set? Will the current
> > "watermark"
> > mechanism remain, or could there be a simple rule that an uncleared
> > `StackOverflow` exception ensures some additional head-room?
>
> When an exception is "set", the C code should be unwinding stack,
> so those states shouldn't be possible.
>
> We can't give you extra headroom. The C stack is a fixed size.
> That's why `Py_CheckStackDepthWithHeadRoom()` is provided, if
> `Py_CheckStackDepth()` fails then it is too late to do much.
>
> Cheers,
> Mark.
>
> >
> > Cheers,
> >
> > Sebastian
> >
> >
> >
> > > -----------
> > >
> > > The full PEP can be found here:
> > > https://www.python.org/dev/peps/pep-0651
> > >
> > > As always, comments are welcome.
> > >
> > > Cheers,
> > > Mark.
> > > _______________________________________________
> > > Python-Dev mailing list -- [email protected]
> > > To unsubscribe send an email to [email protected]
> > > https://mail.python.org/mailman3/lists/python-dev.python.org/
> > > Message archived at
> > > https://mail.python.org/archives/list/[email protected]/message/ZY32N43YZJM3WYXSVD7OCGVNDGPR6DUM/
> > > Code of Conduct: http://python.org/psf/codeofconduct/
> > >
> >
> >
> > _______________________________________________
> > Python-Dev mailing list -- [email protected]
> > To unsubscribe send an email to [email protected]
> > https://mail.python.org/mailman3/lists/python-dev.python.org/
> > Message archived at
> > https://mail.python.org/archives/list/[email protected]/message/N456CVKWZ3E3VKPOE2DZMFLVSMOK5BSF/
> > Code of Conduct: http://python.org/psf/codeofconduct/
> >
> _______________________________________________
> Python-Dev mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/[email protected]/message/GSR6DCTXK4WWP2U5X65A3HBVY4UWQUPR/
> Code of Conduct: http://python.org/psf/codeofconduct/
signature.asc
Description: This is a digitally signed message part
_______________________________________________ Python-Dev mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/[email protected]/message/QJICZO4IZ6EYLQS4WVPU7ON6DOO4IXN6/ Code of Conduct: http://python.org/psf/codeofconduct/
