Debugging of native extensions on windows

Hello! I am dropping this mail to bring up an issue which cost me three good evenings of time. Now that i figured it out i believe it is quite a serious usability problem. Gist of the problem: i have some C++ code wrapped with SWIG, so a native extension. As with all software - there was a bug. However, no matter what i did - i could not debug it in a native debugger. I ran ".venv/Scripts/python.exe script.py" in a native debugger and breakpoints would not be hit, application would crash eventually. This was especially confusing, because exact same setup worked just fine on linux. I eventually stumbled on to process list showing ".venv/Scripts/python.exe" having spawned a subprocess... Which led me to "PC/launcher.c" which is what ".venv/Scripts/python.exe" really is. I cant find much information about this behavior in documentation even after the fact. All in all, this was quite confusing. So now every time i want to debug a native extension i have to start a program and then attach a debugger to it, instead of just hitting "Debug" button in IDE. It gets worse if crash happens immediately, which means i have to resort to things like adding a message box somewhere to block execution and give me enough time to attach the debugger. It works in the end, but user experience is really not great. But whats worse - this is such a non-obvious behavior that many more people may trip on it and waste their time. Documenting this behavior would be of little help too, as there is no clear path from the issue to the documentation on the matter... So there it is. I am sure it is the way it is for a good reason. However, this is a very error-prone process which is likely to waste people's time. So maybe this behavior could be reconsidered? Or maybe there is a solution already, which escaped me? -- -- Rokas Kupstys

Hi Rokas The typical solution (which I myself use frequently) is to enable your debugger to attach to child processes automatically. It can make things a bit noisier, but it's generally manageable, especially if you've got breakpoints set in your own code. Another option is to not use the virtual environment, but set PYTHONPATH to your environment's Lib\site-packages directory and then run the base interpreter directly. Most of the time, this will be identical, but it avoids the extra process. Unfortunately, for a variety of reasons, we can't get away from the redirector process as long as virtual environments keep their current design. As changing the design would be just as disruptive, we've not done anything yet, nor do we have any plans to change anything. Finally, most discussion about Python occurs at https://discuss.python.org/ these days. You'll likely find more help and discussion over there. Cheers, Steve On 3/13/2023 3:25 PM, Rokas Kupstys wrote:

Is it easier to simply run python outside a virtualenv? They are great, but maybe when debugging an extension module, it's not so hard to just not use it :-) You also might want to give conda environments a try -- they include Python, so probably won't have the same issue. -CHB On Mon, Mar 13, 2023 at 4:58 PM Steve Dower <steve.dower@python.org> wrote:
-- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

As Steve suggested i think most friction-less path is to run python interpreter directly while specifying site-packages of virtualenv in PYTHONPATH. I already specify additional paths there anyway, since extensions are built with cmake and i wanted to achieve fast iteration times, being able to use extensions directly built by cmake, without going through installation problem. Still, i think there can be an improvement in this area, and it would likely be quite cheap. The biggest problem is people being unaware what is going on. IsDebuggerPresent()/CheckRemoteDebuggerPresent() could be used for checking debugger presence and when debugging state of main process and child process do not match, launcher could print some link to documentation describing what is going on and how situation could be solved. I am just not sure about any possible race conditions (no idea how fast debuggers attack to child processes). -- Rokas Kupstys On 2023-03-14 08:35, Christopher Barker wrote:

On 3/14/2023 7:13 AM, Rokas Kupstys wrote:
Detecting when a debugger is attached and printing a debug message on exit from the launcher might be a neat idea. Care to submit a bug at https://github.com/python/cpython? The change would likely have to go into PC\launcher.c (for venvs) as well as PC\launcher2.c right now (for py.exe). Native debuggers usually hook process creation, so they should attach immediately with no risk of missing anything. Cheers, Steve

On 3/13/23, Rokas Kupstys <rokupstys@gmail.com> wrote:
For a standard Python installation, you can create a virtual environment with the --symlinks option instead of the default configuration that uses the venv launcher. Note, however, that using symlinks doesn't work with the store app distribution of Python. If your system doesn't have developer mode enabled, creating symlinks requires "SeCreateSymbolicLinkPrivilege". By default this privilege is only granted to administrators. However, an administrator can use the management console "secpol.msc" snap-in to grant the symlink privilege directly to a user account, or to one of the account's default enabled groups such as "Authenticated Users". Add the user or group to the "Create symbolic links" policy in "Security Settings" -> "Local Policies" -> "User Rights Assignment". You'll have to log off and back on again to get a new access token that has the symlink privilege. Unfortunately, the shell API -- e.g. os.startfile() -- resolves the final path of an executable before running it. This allows using filesystem symlinks as if they're shortcuts (LNK files), but it prevents using a symlink to change the name or path of an executable to get different expected behavior, such as a Python virtual environment that uses symlinks.

Hi Rokas The typical solution (which I myself use frequently) is to enable your debugger to attach to child processes automatically. It can make things a bit noisier, but it's generally manageable, especially if you've got breakpoints set in your own code. Another option is to not use the virtual environment, but set PYTHONPATH to your environment's Lib\site-packages directory and then run the base interpreter directly. Most of the time, this will be identical, but it avoids the extra process. Unfortunately, for a variety of reasons, we can't get away from the redirector process as long as virtual environments keep their current design. As changing the design would be just as disruptive, we've not done anything yet, nor do we have any plans to change anything. Finally, most discussion about Python occurs at https://discuss.python.org/ these days. You'll likely find more help and discussion over there. Cheers, Steve On 3/13/2023 3:25 PM, Rokas Kupstys wrote:

Is it easier to simply run python outside a virtualenv? They are great, but maybe when debugging an extension module, it's not so hard to just not use it :-) You also might want to give conda environments a try -- they include Python, so probably won't have the same issue. -CHB On Mon, Mar 13, 2023 at 4:58 PM Steve Dower <steve.dower@python.org> wrote:
-- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

As Steve suggested i think most friction-less path is to run python interpreter directly while specifying site-packages of virtualenv in PYTHONPATH. I already specify additional paths there anyway, since extensions are built with cmake and i wanted to achieve fast iteration times, being able to use extensions directly built by cmake, without going through installation problem. Still, i think there can be an improvement in this area, and it would likely be quite cheap. The biggest problem is people being unaware what is going on. IsDebuggerPresent()/CheckRemoteDebuggerPresent() could be used for checking debugger presence and when debugging state of main process and child process do not match, launcher could print some link to documentation describing what is going on and how situation could be solved. I am just not sure about any possible race conditions (no idea how fast debuggers attack to child processes). -- Rokas Kupstys On 2023-03-14 08:35, Christopher Barker wrote:

On 3/14/2023 7:13 AM, Rokas Kupstys wrote:
Detecting when a debugger is attached and printing a debug message on exit from the launcher might be a neat idea. Care to submit a bug at https://github.com/python/cpython? The change would likely have to go into PC\launcher.c (for venvs) as well as PC\launcher2.c right now (for py.exe). Native debuggers usually hook process creation, so they should attach immediately with no risk of missing anything. Cheers, Steve

On 3/13/23, Rokas Kupstys <rokupstys@gmail.com> wrote:
For a standard Python installation, you can create a virtual environment with the --symlinks option instead of the default configuration that uses the venv launcher. Note, however, that using symlinks doesn't work with the store app distribution of Python. If your system doesn't have developer mode enabled, creating symlinks requires "SeCreateSymbolicLinkPrivilege". By default this privilege is only granted to administrators. However, an administrator can use the management console "secpol.msc" snap-in to grant the symlink privilege directly to a user account, or to one of the account's default enabled groups such as "Authenticated Users". Add the user or group to the "Create symbolic links" policy in "Security Settings" -> "Local Policies" -> "User Rights Assignment". You'll have to log off and back on again to get a new access token that has the symlink privilege. Unfortunately, the shell API -- e.g. os.startfile() -- resolves the final path of an executable before running it. This allows using filesystem symlinks as if they're shortcuts (LNK files), but it prevents using a symlink to change the name or path of an executable to get different expected behavior, such as a Python virtual environment that uses symlinks.
participants (4)
-
Christopher Barker
-
Eryk Sun
-
Rokas Kupstys
-
Steve Dower