Menu

#691 win32ui "ImportError: DLL load failed: Invalid access to memory location."

v1.0 (example)
open
nobody
None
5
2015-05-06
2015-05-06
Catalin P
No

If the Python garbage collector happens to run while win32ui is loading, this can cause a crash which manifests as:


Traceback (most recent call last):
File "import.py", line 5, in <module>
import win32ui
ImportError: DLL load failed: Invalid access to memory location.

This normally happens very rarely, but if the code executed prior to the win32ui import generates precisely the correct amount of garbage, this happens consistently for a given program.

This is reproducible on both Python 2.6 pywin32-214 and
Python 2.7 pywin32-218 using the following script:


import gc
gc.set_debug(gc.DEBUG_STATS)
gc.set_threshold(1)
import win32process
import win32ui

This results in frequent GC at global construction time, eventually causing a
crash:

[...]
gc: collecting generation 0...
gc: objects in each generation: 4 0 3898
gc: done, 0.0000s elapsed.
gc: collecting generation 0...
gc: objects in each generation: 0 3 3898
gc: done, 0.0000s elapsed.
gc: collecting generation 0...
gc: objects in each generation: 2 3 3898
Traceback (most recent call last):
File "import.py", line 5, in <module>
import win32ui
ImportError: DLL load failed: Invalid access to memory location.

The stack points to allocation of some other, unrelated object:

python27!visit_decref(struct _object * op = 0x1e322000, void * data = 0x0...
python27!tupletraverse(struct PyTupleObject * o = 0x00b6e850, <function> ...
python27!subtract_refs(union _gc_head * containers = 0x00b6e860)+0x1a
python27!collect(int generation = 0n505416936)+0x120
python27!collect_generations(void)+0x53
python27!_PyObject_GC_Malloc(unsigned int basicsize = 0x14)+0x73
python27!_PyObject_GC_NewVar(struct _typeobject * tp = 0x1e227be8, int ni...
python27!PyTuple_New(int size = 0n2)+0xdd
python27!do_mktuple(char p_format = 0x0021f078, char p_va = 0x0021f...
python27!va_build_value(char * format = 0x00000000 "", char * va = 0x0021...
python27!Py_BuildValue(char * format = 0x1e2e83d4 "OO")+0x11
win32ui!MakeResourceFromDlgList+0x972f
win32ui!MakeResourceFromDlgList+0x1e67
win32ui!MakeResourceFromDlgList+0x202f
win32ui!MakeResourceFromDlgList+0x20fc
ntdll!LdrpCallInitRoutine+0x14
ntdll!LdrpRunInitializeRoutines+0x344
ntdll!LdrpLoadDll+0x3e5
ntdll!LdrLoadDll+0x230
kernel32!LoadLibraryExW+0x18e
kernel32!LoadLibraryExA+0x1f
python27!_PyImport_GetDynLoadFunc(char * fqname = 0x00b2ac80 "win32ui", ...

op is win32ui!PyCWnd::type, which is not yet constructed:

0:000> ln esi
Exact matches:
win32ui!PyCWnd::type (<no parameter="" info="">)
0:000> dd esi
1e322000 00000001 00000000 00000000 00000000
1e322010 00000000 00000000 00000000 00000000
1e322020 00000000 00000000 00000000 00000000
[...]

visit_decref tries to determine whether the object should be considered for GC,
but crashes on op->ob_type->tp_flags because op->ob_type is NULL.

Theoretical sequence of events:
- win32ui is loaded, CRT begins executing global constructors.
(PyCWnd::type has not been constructed yet at this point.)
- Some global constructor makes the GC aware of PyCWnd::type. This part is
unclear. Perhaps this happens when a subclass type object is created, or
perhaps someone instantiates a PyCWnd. tupletraverse in the call stack above
suggests PyCWnd::type is placed into a tuple using Py_BuildValue (a previous
Py_BuildValue to the one requesting an allocation above).
- Some other global constructor allocates memory for an unrelated object (this
is the stack above), triggers the GC, which seeks to visit PyCWnd::type,
which being partially constructed, causes visit_decref to crash.

Workaround: disable GC while loading win32ui, and re-enable afterwards:

import gc

threshold0, , _ = gc.get_threshold()
gc.set_threshold(0)

import win32process
import win32ui
# other pywin32 imports

gc.set_threshold(_threshold0)

I believe the correct fix is to not access any Py* functions from global constructors, or to avoid global->global object references since global construction order is indeterminate in C++.

Discussion

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.