Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugger hangs and process left unterminated when forking inside subprocess.run #264

Closed
Flamefire opened this issue May 25, 2020 · 4 comments
Labels
bug Something isn't working

Comments

@Flamefire
Copy link

Environment data

  • VS Code version: 1.45.1
  • Extension version (available under the Extensions sidebar): 2020.5.80290
  • OS and version: Linux Mint 18
  • Python version (& distribution if applicable, e.g. Anaconda): 3.7.4
  • Type of virtual environment used (N/A | venv | virtualenv | conda | ...): pyenv

Expected behaviour

Spawned process terminate successfully (exit with 0) and debugging continues finally terminating the parent process

Actual behaviour

When capturing stdout (stdout=subprocess.PIPE) the parent process hangs indefintely waiting for the child process. When not capturing stdout the forked child process hangs and is never terminated.

Steps to reproduce:

This happened in a complex scenario which went like this: Python script starts another python script, which invokes an external tool (compiler via distutils)

I reduces this to the following code by checking what is happening:

import os
import sys
import subprocess

if len(sys.argv) == 1:
    out = subprocess.run([sys.executable, __file__, '--foo'],
            stdout=subprocess.PIPE
            )
else:
    pid = os.fork()
    print(pid)
  • Save this and try to debug with the default "Python: Current file" template
  1. Observe that the debugger hangs indefinitely
  2. Comment out the stdout=subprocess.PIPE line and observe that the subprocesses-child-pid (return value of fork) is printed but the child never runs (which should print a zero) and although debugging will end in this case the child process is never terminated (check ps -aux | grep python)

Note that usually the parent process of the fork waits for the child which means that again the debugged process never returns/continues.

@karthiknadig karthiknadig transferred this issue from microsoft/vscode-python May 26, 2020
@int19h int19h added the bug Something isn't working label Jun 16, 2020
@fabioz
Copy link
Collaborator

fabioz commented Jul 24, 2020

I'll start to investigate this.

@fabioz
Copy link
Collaborator

fabioz commented Oct 15, 2020

I wasn't able to investigate this properly last time, so, I'll start tackling this again.

@fabioz
Copy link
Collaborator

fabioz commented Oct 15, 2020

Attaching related logs.

Changed the program to give a bit more info:

import os
import sys
import subprocess

if len(sys.argv) == 1:
    out = subprocess.run([sys.executable, __file__, '--foo'],
            stdout=subprocess.PIPE
            )
    print('\n\nin pid %s, output from subprocess.run:\n%s' % (os.getpid(), out.stdout.decode('utf-8')))
else:
    pid = os.fork()
    print('currently in pid: %s, ppid: %s' % (os.getpid(), os.getppid()))
    print('os.fork returned', pid)

debugger.vscode_79413804-5bb5-48f7-b650-fb10716ff2a1.log <- initial launch (receives debugpyAttach to 19300)
debugger.vscode_1f8559a4-5667-4dae-b231-7e59a328ff7a.log <- does the attach connection to 19300

debugpy.adapter-19269.log <-- it's possible to see that it receives the connection from pydevd in Accepted incoming Server connection from 127.0.0.1:55456. and then it sends the pydevdAuthorize... pydevd logs that it received it and sent a response, it, but it never seems to be handled or arrive in the adapter in this case (this is probably the point where things go awry).

debugpy.launcher-19279.log
debugpy.server-19285.log

debugpy.pydevd.19285.log initial process
debugpy.pydevd.19300.log shows in output (through CMD_WRITE_TO_CONSOLE):

"currently in pid: 19300, ppid: 19285\n"
"os.fork returned 19311\n"

debugpy.pydevd.19311.log shows connection done, but initialize is not received.

The logs on the pydevd side seem to show that a connection was done, but the initialize event isn't really sent after that (I also tested in plain pydevd and it seems to work properly there, so, it's probably something related to the connection management on the debugpy/vscode side).

@fabioz
Copy link
Collaborator

fabioz commented Oct 16, 2020

Actually, the problem was on the pydevd side. It wasn't properly keeping the protocol after a fork after a subprocess.

This happened because debugpy set the default protocol in memory, but that in-memory default was lost if it first created a subprocess and then a fork after that subprocess and the logging doesn't really show which protocol it was using (the message just didn't arrive in the other side because there was no new-line sent) -- took me a while to actually find this one (and as all hard to debug things it's a really small fix: https://github.com/microsoft/debugpy/pull/438/files#diff-942a2e05c676f6fb0f7a70883d2f885bcb47c1af4feb1a3a48f57fd77c17d5b5R685).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants