mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 17:20:55 +07:00
PY-33148 Fix debugger hang when exec or spawn are called with bytes args
GitOrigin-RevId: 4aaa502a6745033c61e74fd1f32b25a18ef55fe7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4b6648679c
commit
3ed0ece29c
@@ -57,6 +57,15 @@ def _is_already_patched(args):
|
||||
return False
|
||||
|
||||
|
||||
def _is_py3_and_has_bytes_args(args):
|
||||
if not isinstance('', type(u'')):
|
||||
return False
|
||||
for arg in args:
|
||||
if isinstance(arg, bytes):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _on_forked_process():
|
||||
import pydevd
|
||||
pydevd.threadingCurrentThread().__pydevd_main_thread = True
|
||||
@@ -72,7 +81,7 @@ def _on_set_trace_for_new_thread(global_debugger):
|
||||
# Things related to monkey-patching
|
||||
#===============================================================================
|
||||
def is_python_args(args):
|
||||
return len(args) > 0 and is_python(args[0])
|
||||
return not _is_py3_and_has_bytes_args(args) and len(args) > 0 and is_python(args[0])
|
||||
|
||||
|
||||
def is_executable(path):
|
||||
@@ -153,6 +162,11 @@ def get_c_option_index(args):
|
||||
def patch_args(args):
|
||||
try:
|
||||
log_debug("Patching args: %s"% str(args))
|
||||
|
||||
if _is_py3_and_has_bytes_args(args):
|
||||
warn_bytes_args()
|
||||
return args
|
||||
|
||||
args = remove_quotes_from_args(args)
|
||||
|
||||
from pydevd import SetupHolder
|
||||
@@ -363,10 +377,6 @@ def patch_fork_exec_executable_list(args, other_args):
|
||||
return other_args
|
||||
|
||||
|
||||
def patch_path(path):
|
||||
return sys.executable if is_python(path) else path
|
||||
|
||||
|
||||
def monkey_patch_module(module, funcname, create_func):
|
||||
if hasattr(module, funcname):
|
||||
original_name = 'original_' + funcname
|
||||
@@ -385,6 +395,11 @@ def warn_multiproc():
|
||||
"pydev debugger: To debug that process please enable 'Attach to subprocess automatically while debugging?' option in the debugger settings.\n")
|
||||
|
||||
|
||||
def warn_bytes_args():
|
||||
log_error_once(
|
||||
"pydev debugger: bytes arguments were passed to a new process creation function. Breakpoints may not work correctly.\n")
|
||||
|
||||
|
||||
def create_warn_multiproc(original_name):
|
||||
|
||||
def new_warn_multiproc(*args):
|
||||
@@ -395,6 +410,7 @@ def create_warn_multiproc(original_name):
|
||||
return getattr(os, original_name)(*args)
|
||||
return new_warn_multiproc
|
||||
|
||||
|
||||
def create_execl(original_name):
|
||||
def new_execl(path, *args):
|
||||
"""
|
||||
@@ -406,8 +422,9 @@ def create_execl(original_name):
|
||||
import os
|
||||
args = patch_args(args)
|
||||
if is_python_args(args):
|
||||
path = args[0]
|
||||
send_process_will_be_substituted()
|
||||
return getattr(os, original_name)(patch_path(path), *args)
|
||||
return getattr(os, original_name)(path, *args)
|
||||
return new_execl
|
||||
|
||||
|
||||
@@ -418,9 +435,11 @@ def create_execv(original_name):
|
||||
os.execvp(file, args)
|
||||
"""
|
||||
import os
|
||||
args = patch_args(args)
|
||||
if is_python_args(args):
|
||||
path = args[0]
|
||||
send_process_will_be_substituted()
|
||||
return getattr(os, original_name)(patch_path(path), patch_args(args))
|
||||
return getattr(os, original_name)(path, args)
|
||||
return new_execv
|
||||
|
||||
|
||||
@@ -431,9 +450,11 @@ def create_execve(original_name):
|
||||
"""
|
||||
def new_execve(path, args, env):
|
||||
import os
|
||||
args = patch_args(args)
|
||||
if is_python_args(args):
|
||||
path = args[0]
|
||||
send_process_will_be_substituted()
|
||||
return getattr(os, original_name)(patch_path(path), patch_args(args), env)
|
||||
return getattr(os, original_name)(path, args, env)
|
||||
return new_execve
|
||||
|
||||
|
||||
@@ -457,8 +478,9 @@ def create_spawnv(original_name):
|
||||
os.spawnvp(mode, file, args)
|
||||
"""
|
||||
import os
|
||||
args = patch_args(args)
|
||||
send_process_created_message()
|
||||
return getattr(os, original_name)(mode, path, patch_args(args))
|
||||
return getattr(os, original_name)(mode, path, args)
|
||||
return new_spawnv
|
||||
|
||||
|
||||
@@ -469,8 +491,9 @@ def create_spawnve(original_name):
|
||||
"""
|
||||
def new_spawnve(mode, path, args, env):
|
||||
import os
|
||||
args = patch_args(args)
|
||||
send_process_created_message()
|
||||
return getattr(os, original_name)(mode, path, patch_args(args), env)
|
||||
return getattr(os, original_name)(mode, path, args, env)
|
||||
return new_spawnve
|
||||
|
||||
|
||||
|
||||
5
python/testData/debug/test_call_exec_with_bytes_args.py
Normal file
5
python/testData/debug/test_call_exec_with_bytes_args.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
args = [sys.executable, b'test4.py']
|
||||
os.execv(args[0], args)
|
||||
5
python/testData/debug/test_call_spawn_with_bytes_args.py
Normal file
5
python/testData/debug/test_call_spawn_with_bytes_args.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
args = [sys.executable, b'test4.py']
|
||||
os.spawnv(os.P_WAIT, args[0], args)
|
||||
@@ -2,6 +2,7 @@ package com.jetbrains.env.python;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
@@ -35,8 +36,11 @@ import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
@@ -1954,7 +1958,7 @@ public class PythonDebuggerTest extends PyEnvTestCase {
|
||||
|
||||
@Test
|
||||
public void testExecutableScriptDebug() {
|
||||
|
||||
|
||||
Assume.assumeFalse("Don't run under Windows", UsefulTestCase.IS_UNDER_TEAMCITY && SystemInfo.isWindows);
|
||||
|
||||
runPythonTest(new PyDebuggerTask("/debug", "test_executable_script_debug.py") {
|
||||
@@ -2006,4 +2010,61 @@ public class PythonDebuggerTest extends PyEnvTestCase {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecAndSpawnWithBytesArgs() {
|
||||
|
||||
class ExecAndSpawnWithBytesArgsTask extends PyDebuggerTask {
|
||||
|
||||
private final static String BYTES_ARGS_WARNING = "pydev debugger: bytes arguments were passed to a new process creation function. " +
|
||||
"Breakpoints may not work correctly.\n";
|
||||
private final static String PYTHON2_TAG = "python2";
|
||||
|
||||
private Map<String, Set<String>> myEnvTags = Maps.newHashMap();
|
||||
|
||||
ExecAndSpawnWithBytesArgsTask(@Nullable String relativeTestDataPath, String scriptName) {
|
||||
super(relativeTestDataPath, scriptName);
|
||||
loadEnvTags();
|
||||
}
|
||||
|
||||
private void loadEnvTags() {
|
||||
List<String> roots = PythonDebuggerTest.getPythonRoots();
|
||||
|
||||
roots.forEach((root) -> {
|
||||
Set<String> tags = Sets.newHashSet();
|
||||
tags.addAll(PythonDebuggerTest.loadEnvTags(root));
|
||||
myEnvTags.put(root, tags);
|
||||
});
|
||||
}
|
||||
|
||||
private boolean hasPython2Tag(){
|
||||
String env = Paths.get(myRunConfiguration.getSdkHome()).getParent().getParent().toString();
|
||||
return myEnvTags.get(env).stream().anyMatch((tag) -> tag.startsWith(PYTHON2_TAG));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testing() throws Exception {
|
||||
if (hasPython2Tag()) {
|
||||
waitForTerminate();
|
||||
assertFalse(output().contains(BYTES_ARGS_WARNING));
|
||||
}
|
||||
else
|
||||
waitForOutput(BYTES_ARGS_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
runPythonTest(new ExecAndSpawnWithBytesArgsTask("/debug", "test_call_exec_with_bytes_args.py") {
|
||||
@Override
|
||||
protected void init() {
|
||||
setMultiprocessDebug(true);
|
||||
}
|
||||
});
|
||||
|
||||
runPythonTest(new ExecAndSpawnWithBytesArgsTask("/debug", "test_call_spawn_with_bytes_args.py") {
|
||||
@Override
|
||||
protected void init() {
|
||||
setMultiprocessDebug(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user