From 11b71244c82fda639c16624b7aae998655cbb2be Mon Sep 17 00:00:00 2001 From: Fabio Zadrozny Date: Thu, 3 Jun 2021 15:26:30 -0300 Subject: [PATCH] Don't try to monkey-patch if unexpected argument types are provided. Fixes #601 --- .../pydevd/_pydev_bundle/pydev_monkey.py | 40 ++++++++++++- .../pydevd/tests_python/test_pydev_monkey.py | 59 +++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/debugpy/_vendored/pydevd/_pydev_bundle/pydev_monkey.py b/src/debugpy/_vendored/pydevd/_pydev_bundle/pydev_monkey.py index bc43d2c8..148f8a3d 100644 --- a/src/debugpy/_vendored/pydevd/_pydev_bundle/pydev_monkey.py +++ b/src/debugpy/_vendored/pydevd/_pydev_bundle/pydev_monkey.py @@ -4,7 +4,7 @@ import re import sys from _pydev_imps._pydev_saved_modules import threading from _pydevd_bundle.pydevd_constants import get_global_debugger, IS_WINDOWS, IS_JYTHON, get_current_thread_id, \ - sorted_dict_repr + sorted_dict_repr, IS_PY2 from _pydev_bundle import pydev_log from contextlib import contextmanager from _pydevd_bundle import pydevd_constants @@ -15,6 +15,11 @@ try: except: xrange = range +try: + from pathlib import Path +except ImportError: + Path = None + #=============================================================================== # Things that are dependent on having the pydevd debugger #=============================================================================== @@ -161,11 +166,24 @@ def is_python(path): return False +class InvalidTypeInArgsException(Exception): + pass + + def remove_quotes_from_args(args): if sys.platform == "win32": new_args = [] for x in args: + if Path is not None and isinstance(x, Path): + x = str(x) + elif IS_PY2: + if not isinstance(x, (str, unicode)): + raise InvalidTypeInArgsException(str(type(x))) + else: + if not isinstance(x, (bytes, str)): + raise InvalidTypeInArgsException(str(type(x))) + double_quote, two_double_quotes = _get_str_type_compatible(x, ['"', '""']) if x != two_double_quotes: @@ -175,7 +193,19 @@ def remove_quotes_from_args(args): new_args.append(x) return new_args else: - return args + new_args = [] + for x in args: + if Path is not None and isinstance(x, Path): + x = x.as_posix() + elif IS_PY2: + if not isinstance(x, (str, unicode)): + raise InvalidTypeInArgsException(str(type(x))) + else: + if not isinstance(x, (bytes, str)): + raise InvalidTypeInArgsException(str(type(x))) + new_args.append(x) + + return new_args def quote_arg_win32(arg): @@ -230,7 +260,11 @@ def patch_args(args, is_exec=False): try: pydev_log.debug("Patching args: %s", args) original_args = args - unquoted_args = remove_quotes_from_args(args) + try: + unquoted_args = remove_quotes_from_args(args) + except InvalidTypeInArgsException as e: + pydev_log.info('Unable to monkey-patch subprocess arguments because a type found in the args is invalid: %s', e) + return original_args # Internally we should reference original_args (if we want to return them) or unquoted_args # to add to the list which will be then quoted in the end. diff --git a/src/debugpy/_vendored/pydevd/tests_python/test_pydev_monkey.py b/src/debugpy/_vendored/pydevd/tests_python/test_pydev_monkey.py index c1383f39..744ea2a3 100644 --- a/src/debugpy/_vendored/pydevd/tests_python/test_pydev_monkey.py +++ b/src/debugpy/_vendored/pydevd/tests_python/test_pydev_monkey.py @@ -49,6 +49,65 @@ def test_monkey_patch_return_original_args(): assert res == check +def test_monkey_patch_pathlib_args(): + try: + import pathlib + except ImportError: + pytest.skip('pathlib not available.') + + check = [pathlib.Path('echo'), '"my"', '"args"'] + res = pydev_monkey.patch_args(check[:]) + assert res == check + + +def test_monkey_patch_wrong_object_type(): + check = [1, 22, '"my"', '"args"'] + res = pydev_monkey.patch_args(check[:]) + assert res == check + + +def test_monkey_patch_wrong_object_type_2(): + check = ['C:\\bin\\python.exe', '-u', 1, '-qcconnect("127.0.0.1")'] + res = pydev_monkey.patch_args(check[:]) + assert res == check + + +def test_monkey_patch_args_module_subprocess_pathlib(): + try: + import pathlib + except ImportError: + pytest.skip('pathlib not available.') + + original = SetupHolder.setup + + try: + SetupHolder.setup = {'client': '127.0.0.1', 'port': '0', 'multiprocess': True} + if sys.platform == 'win32': + python_path = 'C:\\bin\\python.exe' + else: + python_path = '/bin/python' + check = [pathlib.Path(python_path), '-mtest', pathlib.Path('bar')] + from _pydevd_bundle.pydevd_command_line_handling import get_pydevd_file + assert pydev_monkey.patch_args(check) == [ + python_path, + get_pydevd_file(), + '--module', + '--port', + '0', + '--ppid', + str(os.getpid()), + '--client', + '127.0.0.1', + '--multiprocess', + '--protocol-quoted-line', + '--file', + 'test', + 'bar', + ] + finally: + SetupHolder.setup = original + + def test_monkey_patch_args_indc(): original = SetupHolder.setup