How to debug Access Violation that it thrown from windows library ucrtbase?

589 views Asked by At

My app (java based) launches python for Windows, which, in turn, calls os.spawnv to launch another python.

From time to time I am having Access Violation exception.

00 005eedb0 763e68f3 ucrtbase!<lambda_7d9ee38b11181ddfdf5bd66394e53cb7>::operator()+0x1b
01 005eedfc 763e65d9 ucrtbase!construct_environment_block<char>+0xdb
02 005eee14 763e7aba ucrtbase!common_pack_argv_and_envp<char>+0x31
03 005eeebc 763e778a ucrtbase!execute_command<char>+0x62
04 005eeee8 763e8066 ucrtbase!common_spawnv<char>+0x13f
05 005eeef8 65a323d7 ucrtbase!_spawnve+0x16
06 005eef38 65a360c6 python35!os_spawnve_impl(int mode = 0n0, struct _object * path = 0x03adfde0, struct _object * argv = 0x03b258a0, struct _object * env = 0x03b25a80)+0x1a7 [c:\build\cpython\modules\posixmodule.c @ 5299]

I've set bp on c:\build\cpython\modules\posixmodule.c @ 5299 and here is what I see in python sources

Py_BEGIN_ALLOW_THREADS
spawnval = _spawnve(mode, path_char, argvlist, envlist);
Py_END_ALLOW_THREADS

I've checked all arguments twice: they are ok. mode is 0, path_char is path to my interpeter, argvlist and envlist are both char**: NULL-terminated arrays of NULL-teminated strings.

So, it is not python fault.

I know that _spawnve is not thread safe, but there is only one thread.

I do not have sources nor private symbols for MS ucrtbase. What is the right approach to investigate it?

--

What is the difference between ucrtbased.dll and ucrtbase.dll? Should I compile Python against ucrtbased.dll to find more symbols?

2

There are 2 answers

0
Philip Scott On

I have just encountered the same problem while trying to build SciPy; an access violation is thrown as part of setup.py trying to spawnve() a C compiler.

I haven't gotten to the bottom of it yet, but stepping through the disassembly, in my case at least. Here's what happens:

  • Calls get_environment_from_os() which gives you a pointer to the current process's environment variables.

  • Iterates through this list of null-terminated strings looking for environment variables whose name starts with an '='

  • Apparently this is Windows's way of expressing the set of current directories, e.g. there should be an environment variable '=c:' with a value like "c:\mystuff"

  • It never finds any, and trundling off into uninitialized memory in its futile quest.

  • Boom.

Inspecting the memory address returned by get_environment_from_os() shows me a pretty sane looking list of environment variables, but none whose key begins with an '=' character.

I'm still digging into exactly why and how things get into this state; it doesn't always seem to happen which makes me suspect threads, but like you, I can't find any evidence to back this up; though I don't have intimate knowledge about how distutils works.

0
Philip Scott On

Aha! Mystery solved.

See https://bugs.jython.org/issue29908 for details, but basically spawnve() is broken. It relies on these secret current directory environment variables that start with an =, and is likely to crash if the environment doesn't contain them.

cmd.exe and explorer.exe set them when launching processes, but if you launch a process yourself with a constrained environment that doesn't include them, then that process itself tries to call spawnve() you are heading to crash land.

The workaround is to set at least one environment variable that matches the pattern; e.g. =c:=pants and you are good.