[Python-Dev] Re: Another test_compiler mystery
Tim Peters
tim.peters at gmail.com
Tue Aug 10 08:48:15 CEST 2004
Well, this gets nasty.
In a debug build, and starting the loop at 0, I can't get off the
gound in the MS 7.1 debugger. It dies quickly with an access
violation in the bowels of ntdll.dll, and I don't have source for
that.
PyOS_CheckStack on Windows does this to detect stack overflow (it
catches an MS exception if the C runtime can't allocate enough room on
the stack):
alloca(PYOS_STACK_MARGIN * sizeof(void*));
It's trying to see whether there's still room for 2K pointers on the
stack. If I multiply that by 2, or by 3, nothing changes. But if I
multiply it by 4, everything changes. Then the "oops! we're gonna
blow the stack!" exit from PyOS_CheckStack is taken. It returns 1 to
_Py_CheckRecursiveCall, which sets a "stack overflow" MemoryError and
returns -1 to its caller.
That's
if (Py_EnterRecursiveCall(" in cmp"))
return NULL;
in PyObject_RichCompare. That's just trying to compare two ints.
So NULL gets returned to PyObject_RichCompareBool, which in turn
returns -1 to lookdict. AAAARGHGH! lookdict "isn't allowed" to raise
exceptions, so it does a PyErr_Clear(), goes on to futilely chase the
entire dict looking for another match on the hash code, and we've
effectively turned a MemoryError into a KeyError. I expect that
explains a lot about what we see in the release-build runs.
If I multiply the stack check by 20, I can finally get some results
out of the debug build:
0 exceptions.KeyError 299
1 exceptions.MemoryError Stack overflow
2 exceptions.MemoryError Stack overflow
3 exceptions.MemoryError Stack overflow
4 exceptions.KeyError 295
5 exceptions.MemoryError Stack overflow
6 exceptions.KeyError 294
7 exceptions.MemoryError Stack overflow
8 exceptions.MemoryError Stack overflow
9 exceptions.MemoryError Stack overflow
10 exceptions.MemoryError Stack overflow
11 exceptions.MemoryError Stack overflow
12 exceptions.MemoryError Stack overflow
13 exceptions.MemoryError Stack overflow
14 exceptions.KeyError 309
15 exceptions.KeyError 296
...
So we're blowing the C stack left and right in this test case, and
sometimes dict lookup turns that into a KeyError.
The question is what we did since 2.3.4 that apparently increases our
stack demands, and grossly increases them in a debug build(!). Could
be that the compile package is more heavily recursive now too (no
idea). test_parser.py in 2,3.4 contained the same deeply nested
tuples, so that's not what changed.
Back in a release build, and restoring the original Windows
stack-check code, but leaving the driver loop starting at 0, I have to
sys.setrecursionlimit(16) to avoid getting any KeyErrors.
sys.setrecursionlimit(878) is the minimum that allows at least one
"ok" to show up:
0 ok
1 exceptions.RuntimeError maximum recursion depth exceeded
2 exceptions.RuntimeError maximum recursion depth exceeded
3 exceptions.RuntimeError maximum recursion depth exceeded
4 exceptions.KeyError 307
5 exceptions.RuntimeError maximum recursion depth exceeded
6 exceptions.KeyError 306
7 exceptions.RuntimeError maximum recursion depth exceeded
8 exceptions.KeyError 305
...
Misc/find_recursionlimit.py in CVS manages to print
Limit of 1000 is fine
before it craps out in a release build; in a debug build, it doesn't
produce *any* output. If I change the limit it starts with to 100, it
manages to get to
Limit of 400 is fine
in a debug build before stopping without a clue.
Hmm! But over in 2.3.4 build, a release build also stopped with 1000,
and a debug build also exited mysteriously. But after reducing its
starting point to 100, it got to
Limit of 700 is fine
before crapping out.
BTW, in 2.3.4 and CVS, when a debug run craps out mysteriously like
this, it has an exit code of 128. That's scary:
http://support.microsoft.com/support/kb/articles/q184/8/02.asp
More information about the Python-Dev
mailing list