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

gh-131591: Implement PEP 768 #131592

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft

gh-131591: Implement PEP 768 #131592

wants to merge 7 commits into from

Conversation

pablogsal
Copy link
Member

@pablogsal pablogsal commented Mar 22, 2025

@pablogsal
Copy link
Member Author

CC: @godlygeek @ivonastojanovic

Copy link

The following commit authors need to sign the Contributor License Agreement:

Click the button to sign:
CLA not signed

@@ -317,6 +318,7 @@ The following implementation-specific options are available:\n\
-X perf: support the Linux \"perf\" profiler; also PYTHONPERFSUPPORT=1\n\
-X perf_jit: support the Linux \"perf\" profiler with DWARF support;\n\
also PYTHON_PERF_JIT_SUPPORT=1\n\
-X disable-remote-debug: disable remote debugging; also PYTHON_DISABLE_REMOTE_DEBUG\n\
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the others use _ instead of - so this should probably be

Suggested change
-X disable-remote-debug: disable remote debugging; also PYTHON_DISABLE_REMOTE_DEBUG\n\
-X disable_remote_debug: disable remote debugging; also PYTHON_DISABLE_REMOTE_DEBUG\n\

if (env) {
active = 0;
}
const wchar_t *xoption = config_get_xoption(config, L"disable-remote-debug");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, all the other X options use underscores so this should probably be

Suggested change
const wchar_t *xoption = config_get_xoption(config, L"disable-remote-debug");
const wchar_t *xoption = config_get_xoption(config, L"disable_remote_debug");

Copy link
Contributor

@godlygeek godlygeek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial observations (I've looked at everything but the interesting stuff, haven't gotten to Python/remote_debugging.c or Lib/test/test_sys.py yet)

Comment on lines +35 to +36
int enabled;
int debugger_pending_call;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably be explicit about our sizes:

Suggested change
int enabled;
int debugger_pending_call;
int32_t enabled;
int32_t debugger_pending_call;

Granted int is 32 bit on all modern platforms, but given that this goes into the offsets and needs to be read from another process with potentially different integer types (like a 64-bit process attaching to a 32-bit one or vice versa) it's better to be explicit, I think.

Or, if you'd prefer, the offsets themselves could contain the size of the field - but I think that's overkill.

/* Remote debugger support */
# define MAX_SCRIPT_PATH_SIZE 512
typedef struct _remote_debugger_support {
int enabled;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this field is unused. You added enabled here, but never reference it anywhere, and the offsets instead use:

.remote_debugging_enabled = offsetof(PyInterpreterState, config.remote_debug),

I think this line should just be removed (which makes sense, anyway - we want a per-process enablement, not a per-thread enablement).

.debugger_support = { \
.eval_breaker = offsetof(PyThreadState, eval_breaker), \
.remote_debugger_support = offsetof(PyThreadState, remote_debugger_support), \
.remote_debugging_enabled = offsetof(PyInterpreterState, config.remote_debug), \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this field really go into the .debugger_support section? I think it should probably go into .interpreter_state instead, since everything else in this struct is specific to a single threadstate, except for this one field being per-interpreter.

@@ -936,7 +936,6 @@ struct _is {
_PyThreadStateImpl _initial_thread;
// _initial_thread should be the last field of PyInterpreterState.
// See https://github.com/python/cpython/issues/127117.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidental change?


#ifdef Py_REMOTE_DEBUG
const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
if (config->remote_debug) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth doing:

Suggested change
if (config->remote_debug) {
if (config->remote_debug == 1) {

to harden this at least a little bit against heap corruption.

int fd = PyObject_AsFileDescriptor(fileobj);
if (fd == -1) {
PyErr_FormatUnraisable("Error when getting file descriptor for debugger script %s", path);
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaks fileobj

Comment on lines +2429 to +2430

If no stack profiler is activated, this function has no effect.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What? This seems like a copy-paste error that should just be removed.

Suggested change
If no stack profiler is activated, this function has no effect.

to how signals are handled. There is no interface to determine when the
code has been executed. The caller is responsible for making sure that
the file still exists whenever the remote process tries to read it and that
it hasn't been overwritten.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably worth documenting that the remote process needs to be CPython, and needs to be Python 3.14+, right?

{
#ifdef MS_WINDOWS
// Get UTF-16 (wide char) version of the path for Windows
wchar_t *debugger_script_path_w = PyUnicode_AsWideCharString(script, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above we said that script could be either str|bytes, but I believe PyUnicode_AsWideCharString only accepts str. Perhaps on Windows the bytes option doesn't even make sense, though. Should we document that Unix allows bytes but Windows does not?


PyMem_Free(debugger_script_path_w);
#else
const char *debugger_script_path = PyUnicode_AsUTF8(script);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, looks like we're not currently handling bytes even for Unix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants