Skip to content

Commit 25955a0

Browse files
authored
Get debug attach to work for 3.12 (#1683)
* Get debug attach to work for 3.12 * Skip flakey test and update binaries * Fix the skip if to work correctly
1 parent ae6812b commit 25955a0

21 files changed

+30
-13
lines changed

src/debugpy/_vendored/pydevd/pydevd_attach_to_process/add_code_to_python_process.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def run_python_code_windows(pid, python_code, connect_debugger_tracing=False, sh
308308
args = [target_executable, str(pid), target_dll_run_on_dllmain]
309309
subprocess.check_call(args)
310310

311-
if not event.wait_for_event_set(15):
311+
if not event.wait_for_event_set(30):
312312
print("Timeout error: the attach may not have completed.")
313313
sys.stdout.flush()
314314
print("--- Finished dll injection ---\n")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

src/debugpy/_vendored/pydevd/pydevd_attach_to_process/common/py_utils.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ typedef PyThreadState* (PyInterpreterState_ThreadHead)(PyInterpreterState* inter
1111
typedef PyThreadState* (PyThreadState_Next)(PyThreadState *tstate);
1212
typedef PyThreadState* (PyThreadState_Swap)(PyThreadState *tstate);
1313
typedef PyThreadState* (_PyThreadState_UncheckedGet)();
14+
typedef PyThreadState* (_PyThreadState_GetCurrent)();
1415
typedef PyObject* (PyObject_CallFunctionObjArgs)(PyObject *callable, ...); // call w/ varargs, last arg should be nullptr
1516
typedef PyObject* (PyInt_FromLong)(long);
1617
typedef PyObject* (PyErr_Occurred)();

src/debugpy/_vendored/pydevd/pydevd_attach_to_process/common/py_version.hpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ enum PythonVersion {
2121
PythonVersion_38 = 0x0308,
2222
PythonVersion_39 = 0x0309,
2323
PythonVersion_310 = 0x030A,
24-
PythonVersion_311 = 0x030B
24+
PythonVersion_311 = 0x030B,
25+
PythonVersion_312 = 0x030C,
26+
PythonVersion_313 = 0x030D,
2527
};
2628

2729

@@ -70,6 +72,12 @@ static PythonVersion GetPythonVersion(void *module) {
7072
if(version[3] == '1'){
7173
return PythonVersion_311;
7274
}
75+
if(version[3] == '2'){
76+
return PythonVersion_312;
77+
}
78+
if(version[3] == '3'){
79+
return PythonVersion_313;
80+
}
7381
}
7482
return PythonVersion_Unknown; // we don't care about 3.1 anymore...
7583

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

src/debugpy/_vendored/pydevd/pydevd_attach_to_process/windows/attach.cpp

+17-9
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141

4242
// Access to std::cout and std::endl
4343
#include <iostream>
44-
#include <mutex>
4544
// DECLDIR will perform an export for us
4645
#define DLL_EXPORT
4746

@@ -108,9 +107,9 @@ struct InitializeThreadingInfo {
108107
PyImport_ImportModule* pyImportMod;
109108
PyEval_Lock* initThreads;
110109

111-
std::mutex mutex;
112-
HANDLE initedEvent; // Note: only access with mutex locked (and check if not already nullptr).
113-
bool completed; // Note: only access with mutex locked
110+
CRITICAL_SECTION cs;
111+
HANDLE initedEvent; // Note: only access with cs locked (and check if not already nullptr).
112+
bool completed; // Note: only access with cs locked
114113
};
115114

116115

@@ -122,12 +121,12 @@ int AttachCallback(void *voidInitializeThreadingInfo) {
122121
initializeThreadingInfo->initThreads(); // Note: calling multiple times is ok.
123122
initializeThreadingInfo->pyImportMod("threading");
124123

125-
initializeThreadingInfo->mutex.lock();
124+
EnterCriticalSection(&initializeThreadingInfo->cs);
125+
initializeThreadingInfo->completed = true;
126126
if(initializeThreadingInfo->initedEvent != nullptr) {
127127
SetEvent(initializeThreadingInfo->initedEvent);
128128
}
129-
initializeThreadingInfo->completed = true;
130-
initializeThreadingInfo->mutex.unlock();
129+
LeaveCriticalSection(&initializeThreadingInfo->cs);
131130
return 0;
132131
}
133132

@@ -311,13 +310,19 @@ extern "C"
311310
// Either _PyThreadState_Current or _PyThreadState_UncheckedGet are required
312311
DEFINE_PROC_NO_CHECK(curPythonThread, PyThreadState**, "_PyThreadState_Current", -220); // optional
313312
DEFINE_PROC_NO_CHECK(getPythonThread, _PyThreadState_UncheckedGet*, "_PyThreadState_UncheckedGet", -230); // optional
313+
DEFINE_PROC_NO_CHECK(getPythonThread13, _PyThreadState_GetCurrent*, "_PyThreadState_GetCurrent", -231); // optional
314+
if (getPythonThread == nullptr && getPythonThread13 != nullptr) {
315+
std::cout << "Using Python 3.13 or later, using _PyThreadState_GetCurrent" << std::endl << std::flush;
316+
getPythonThread = getPythonThread13;
317+
}
314318

315319
if (curPythonThread == nullptr && getPythonThread == nullptr) {
316320
// we're missing some APIs, we cannot attach.
317321
std::cerr << "Error, missing Python threading API!!" << std::endl << std::flush;
318322
return -240;
319323
}
320324

325+
321326
// Either _Py_CheckInterval or _PyEval_[GS]etSwitchInterval are useful, but not required
322327
DEFINE_PROC_NO_CHECK(intervalCheck, int*, "_Py_CheckInterval", -250); // optional
323328
DEFINE_PROC_NO_CHECK(getSwitchInterval, _PyEval_GetSwitchInterval*, "_PyEval_GetSwitchInterval", -260); // optional
@@ -368,22 +373,25 @@ extern "C"
368373
initializeThreadingInfo->pyImportMod = pyImportMod;
369374
initializeThreadingInfo->initThreads = initThreads;
370375
initializeThreadingInfo->initedEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
376+
InitializeCriticalSection(&initializeThreadingInfo->cs);
377+
371378

372379
// Add the call to initialize threading.
373380
addPendingCall(&AttachCallback, initializeThreadingInfo);
374381

375382
::WaitForSingleObject(initializeThreadingInfo->initedEvent, 5000);
376383

377384
// Whether this completed or not, release the event handle as we won't use it anymore.
378-
initializeThreadingInfo->mutex.lock();
385+
EnterCriticalSection(&initializeThreadingInfo->cs);
379386
CloseHandle(initializeThreadingInfo->initedEvent);
380387
bool completed = initializeThreadingInfo->completed;
381388
initializeThreadingInfo->initedEvent = nullptr;
382-
initializeThreadingInfo->mutex.unlock();
389+
LeaveCriticalSection(&initializeThreadingInfo->cs);
383390

384391
if(completed) {
385392
// Note that this structure will leak if addPendingCall did not complete in the timeout
386393
// (we can't release now because it's possible that it'll still be called).
394+
DeleteCriticalSection(&initializeThreadingInfo->cs);
387395
delete initializeThreadingInfo;
388396
if (showDebugInfo) {
389397
std::cout << "addPendingCall to initialize threads/import threading completed. " << std::endl << std::flush;

src/debugpy/_vendored/pydevd/pydevd_attach_to_process/windows/compile_windows.bat

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ setlocal
77

88
@set VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
99
@echo Using vswhere at %VSWHERE%
10-
@for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set VSDIR=%%i
10+
@for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -prerelease -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set VSDIR=%%i
1111
@echo Using Visual C++ at %VSDIR%
1212

1313
call "%VSDIR%\VC\Auxiliary\Build\vcvarsall.bat" x86 -vcvars_spectre_libs=spectre

tests/debugpy/test_attach.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
@pytest.mark.parametrize("stop_method", ["breakpoint", "pause"])
1414
@pytest.mark.parametrize("is_client_connected", ["is_client_connected", ""])
15-
@pytest.mark.parametrize("wait_for_client", ["wait_for_client", ""])
15+
@pytest.mark.parametrize("wait_for_client", ["wait_for_client", pytest.param("", marks=pytest.mark.skipif(sys.platform.startswith("darwin"), reason="Flakey test on Mac"))])
1616
def test_attach_api(pyfile, wait_for_client, is_client_connected, stop_method):
1717
@pyfile
1818
def code_to_debug():

0 commit comments

Comments
 (0)