But only if run under a debug build *and* passing -O to Python:
*And* only if the .pyc/.pyo files reachable from Lib/ are deleted before running it.
The explosion is here: static int com_make_closure(struct compiling *c, PyCodeObject *co) { int i, free = PyTuple_GET_SIZE(co->co_freevars); co-> is almost entirely filled with 0xdddddddd at this point (and in particular, that's the value of co->co_freevars, which is why it blows up). That bit pattern is the MS "dead landfill" value: when the MS debug libraries free() an object, they overwrite the space with 0xdd bytes. Here's the call stack: com_make_closure(compiling * 0x0063f5c4, PyCodeObject * 0x00a1b5b0) line 2108 + 6 bytes com_test(compiling * 0x0063f5c4, _node * 0x008470d0) line 2164 + 13 bytes com_node(compiling * 0x0063f5c4, _node * 0x008470d0 line 3452 + 13 bytes com_argument(compiling * 0x0063f5c4, _node * 0x0084a900, _object * * 0x0063f3b8) line 1516 + 16 bytes com_call_function(compiling * 0x0063f5c4, _node * 0x00847124) line 1581 + 17 bytes com_apply_trailer(compiling * 0x0063f5c4, _node * 0x008471d4) line 1764 + 19 bytes com_power(compiling * 0x0063f5c4, _node * 0x008472b0) line 1792 + 24 bytes com_factor(compiling * 0x0063f5c4, _node * 0x008472f0) line 1813 + 16 bytes com_term(compiling * 0x0063f5c4, _node * 0x00847330) line 1823 + 16 bytes com_arith_expr(compiling * 0x0063f5c4, _node * 0x00847370) line 1852 + 16 bytes com_shift_expr(compiling * 0x0063f5c4, _node * 0x008473b0) line 1878 + 16 bytes com_and_expr(compiling * 0x0063f5c4, _node * 0x008473f0) line 1904 + 16 bytes com_xor_expr(compiling * 0x0063f5c4, _node * 0x00847430) line 1926 + 16 bytes com_expr(compiling * 0x0063f5c4, _node * 0x0084a480) line 1948 + 16 bytes com_comparison(compiling * 0x0063f5c4, _node * 0x008474b0) line 2002 + 16 bytes com_not_test(compiling * 0x0063f5c4, _node * 0x008474f0) line 2077 + 16 bytes com_and_test(compiling * 0x0063f5c4, _node * 0x008475e0) line 2094 + 24 bytes com_test(compiling * 0x0063f5c4, _node * 0x0084b124) line 2178 + 24 bytes com_node(compiling * 0x0063f5c4, _node * 0x0084b124) line 3452 + 13 bytes com_if_stmt(compiling * 0x0063f5c4, _node * 0x00847620) line 2817 + 13 bytes com_node(compiling * 0x0063f5c4, _node * 0x00847620) line 3431 + 13 bytes com_file_input(compiling * 0x0063f5c4, _node * 0x007d4cc0) line 3660 + 13 bytes compile_node(compiling * 0x0063f5c4, _node * 0x007d4cc0) line 3762 + 13 bytes jcompile(_node * 0x007d4cc0, char * 0x0063f84c, compiling * 0x00000000) line 3870 + 16 bytes PyNode_Compile(_node * 0x007d4cc0, char * 0x0063f84c) line 3813 + 15 bytes parse_source_module(char * 0x0063f84c, _iobuf * 0x10261888) line 611 + 13 bytes load_source_module(char * 0x0063f9a8, char * 0x0063f84c, _iobuf * 0x10261888) line 731 + 13 bytes load_module(char * 0x0063f9a8, _iobuf * 0x10261888, char * 0x0063f84c, int 0x00000001) line 1259 + 17 bytes import_submodule(_object * 0x1e1f6ca0 __Py_NoneStruct, char * 0x0063f9a8, char * 0x0063f9a8) line 1787 + 33 bytes load_next(_object * 0x1e1f6ca0 __Py_NoneStruct, _object * 0x1e1f6ca0 __Py_NoneStruct, char * * 0x0063fabc, char * 0x0063f9a8, int * 0x0063f9a4) line 1643 + 17 bytes import_module_ex(char * 0x00000000, _object * 0x00770d6c, _object * 0x00770d6c, _object * 0x1e1f6ca0 __Py_NoneStruct) line 1494 + 35 bytes PyImport_ImportModuleEx(char * 0x007ae58c, _object * 0x00770d6c, _object * 0x00770d6c, _object * 0x1e1f6ca0 __Py_NoneStruct) line 1535 + 21 bytes builtin___import__(_object * 0x00000000, _object * 0x007716ac) line 31 + 21 bytes call_cfunction(_object * 0x00760080, _object * 0x007716ac, _object * 0x00000000) line 2740 + 11 bytes call_object(_object * 0x00760080, _object * 0x007716ac, _object * 0x00000000) line 2703 + 17 bytes PyEval_CallObjectWithKeywords(_object * 0x00760080, _object * 0x007716ac, _object * 0x00000000) line 2673 + 17 bytes eval_code2(PyCodeObject * 0x007afe10, _object * 0x00770d6c, _object * 0x00770d6c, _object * * 0x00000000, int 0x00000000, _object * * 0x00000000, int 0x00000000, _object * * 0x00000000, int 0x00000000, _object * 0x00000000) line 1767 + 15 bytes PyEval_EvalCode(PyCodeObject * 0x007afe10, _object * 0x00770d6c, _object * 0x00770d6c) line 341 + 31 bytes run_node(_node * 0x007a8760, char * 0x00760dd0, _object * 0x00770d6c, _object * 0x00770d6c) line 935 + 17 bytes run_err_node(_node * 0x007a8760, char * 0x00760dd0, _object * 0x00770d6c, _object * 0x00770d6c) line 923 + 21 bytes PyRun_FileEx(_iobuf * 0x10261888, char * 0x00760dd0, int 0x00000101, _object * 0x00770d6c, _object * 0x00770d6c, int 0x00000001) line 915 + 21 bytes PyRun_SimpleFileEx(_iobuf * 0x10261888, char * 0x00760dd0, int 0x00000001) line 628 + 30 bytes PyRun_AnyFileEx(_iobuf * 0x10261888, char * 0x00760dd0, int 0x00000001) line 467 + 17 bytes Py_Main(int 0x00000003, char * * 0x00760d90) line 296 + 44 bytes main(int 0x00000003, char * * 0x00760d90) line 10 + 13 bytes mainCRTStartup() line 338 + 17 bytes Unsurprisingly, it's importing test_b2.py at this point. So this is enough to reproduce the problem: First, make sure test_b2.pyo doesn't exist. Then
python_d -O Adding parser accelerators ... Done. Python 2.1a2 (#10, Feb 23 2001, 14:19:33) [MSC 32 bit (Intel)] on win32 Type "copyright", "credits" or "license" for more information.
import sys sys.path.insert(0, "../lib/test") [5223 refs] import test_b2
Boom. Best guess is that I need a debug build to fail, because in the normal build it's still referencing free()d memory anyway, but the normal MS malloc/free don't overwrite free()d memory with trash (so the problem isn't noticed). No guess as to why -O is needed.