@@ -2451,38 +2451,71 @@ sys_is_remote_debug_enabled_impl(PyObject *module)
24512451#endif
24522452}
24532453
2454+ /*[clinic input]
2455+ sys.remote_exec
2456+
2457+ pid: int
2458+ script: object
2459+
2460+ Executes a file containing Python code in a given remote Python process.
2461+
2462+ This function returns immediately, and the code will be executed by the
2463+ target process's main thread at the next available opportunity, similarly
2464+ to how signals are handled. There is no interface to determine when the
2465+ code has been executed. The caller is responsible for making sure that
2466+ the file still exists whenever the remote process tries to read it and that
2467+ it hasn't been overwritten.
2468+
2469+ The remote process must be running a CPython interpreter of the same major
2470+ and minor version as the local process. If either the local or remote
2471+ interpreter is pre-release (alpha, beta, or release candidate) then the
2472+ local and remote interpreters must be the same exact version.
2473+
2474+ Args:
2475+ pid (int): The process ID of the target Python process.
2476+ script (str|bytes): The path to a file containing
2477+ the Python code to be executed.
2478+ [clinic start generated code]*/
2479+
24542480static PyObject *
2455- sys_remote_exec_unicode_path (PyObject * module , int pid , PyObject * script )
2481+ sys_remote_exec_impl (PyObject * module , int pid , PyObject * script )
2482+ /*[clinic end generated code: output=7d94c56afe4a52c0 input=39908ca2c5fe1eb0]*/
24562483{
2457- const char * debugger_script_path = PyUnicode_AsUTF8 (script );
2458- if (debugger_script_path == NULL ) {
2484+ PyObject * path ;
2485+ const char * debugger_script_path ;
2486+
2487+ if (PyUnicode_FSConverter (script , & path ) < 0 ) {
24592488 return NULL ;
24602489 }
2461-
2490+ debugger_script_path = PyBytes_AS_STRING ( path );
24622491#ifdef MS_WINDOWS
2492+ PyObject * unicode_path ;
2493+ if (PyUnicode_FSDecoder (path , & unicode_path ) < 0 ) {
2494+ goto error ;
2495+ }
24632496 // Use UTF-16 (wide char) version of the path for permission checks
2464- wchar_t * debugger_script_path_w = PyUnicode_AsWideCharString (script , NULL );
2497+ wchar_t * debugger_script_path_w = PyUnicode_AsWideCharString (unicode_path , NULL );
2498+ Py_DECREF (unicode_path );
24652499 if (debugger_script_path_w == NULL ) {
2466- return NULL ;
2500+ goto error ;
24672501 }
2468-
2469- // Check file attributes using wide character version (W) instead of ANSI (A)
24702502 DWORD attr = GetFileAttributesW (debugger_script_path_w );
2471- PyMem_Free (debugger_script_path_w );
24722503 if (attr == INVALID_FILE_ATTRIBUTES ) {
24732504 DWORD err = GetLastError ();
2505+ PyMem_Free (debugger_script_path_w );
24742506 if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ) {
24752507 PyErr_SetString (PyExc_FileNotFoundError , "Script file does not exist" );
24762508 }
24772509 else if (err == ERROR_ACCESS_DENIED ) {
24782510 PyErr_SetString (PyExc_PermissionError , "Script file cannot be read" );
24792511 }
24802512 else {
2481- PyErr_SetFromWindowsErr (0 );
2513+ PyErr_SetFromWindowsErr (err );
24822514 }
2483- return NULL ;
2515+ goto error ;
24842516 }
2485- #else
2517+ PyMem_Free (debugger_script_path_w );
2518+ #else // MS_WINDOWS
24862519 if (access (debugger_script_path , F_OK | R_OK ) != 0 ) {
24872520 switch (errno ) {
24882521 case ENOENT :
@@ -2494,54 +2527,19 @@ sys_remote_exec_unicode_path(PyObject *module, int pid, PyObject *script)
24942527 default :
24952528 PyErr_SetFromErrno (PyExc_OSError );
24962529 }
2497- return NULL ;
2530+ goto error ;
24982531 }
2499- #endif
2500-
2532+ #endif // MS_WINDOWS
25012533 if (_PySysRemoteDebug_SendExec (pid , 0 , debugger_script_path ) < 0 ) {
2502- return NULL ;
2534+ goto error ;
25032535 }
25042536
2537+ Py_DECREF (path );
25052538 Py_RETURN_NONE ;
2506- }
2507-
2508- /*[clinic input]
2509- sys.remote_exec
2510-
2511- pid: int
2512- script: object
2513-
2514- Executes a file containing Python code in a given remote Python process.
2515-
2516- This function returns immediately, and the code will be executed by the
2517- target process's main thread at the next available opportunity, similarly
2518- to how signals are handled. There is no interface to determine when the
2519- code has been executed. The caller is responsible for making sure that
2520- the file still exists whenever the remote process tries to read it and that
2521- it hasn't been overwritten.
25222539
2523- The remote process must be running a CPython interpreter of the same major
2524- and minor version as the local process. If either the local or remote
2525- interpreter is pre-release (alpha, beta, or release candidate) then the
2526- local and remote interpreters must be the same exact version.
2527-
2528- Args:
2529- pid (int): The process ID of the target Python process.
2530- script (str|bytes): The path to a file containing
2531- the Python code to be executed.
2532- [clinic start generated code]*/
2533-
2534- static PyObject *
2535- sys_remote_exec_impl (PyObject * module , int pid , PyObject * script )
2536- /*[clinic end generated code: output=7d94c56afe4a52c0 input=39908ca2c5fe1eb0]*/
2537- {
2538- PyObject * ret = NULL ;
2539- PyObject * path ;
2540- if (PyUnicode_FSDecoder (script , & path )) {
2541- ret = sys_remote_exec_unicode_path (module , pid , path );
2542- Py_DECREF (path );
2543- }
2544- return ret ;
2540+ error :
2541+ Py_DECREF (path );
2542+ return NULL ;
25452543}
25462544
25472545
0 commit comments