From a82f63f5af027a0eab0f0812d750b804368cbd25 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Dec 2020 22:37:27 +0100 Subject: [PATCH] bpo-32381: Add _PyRun_AnyFileObject() (GH-23723) pymain_run_file() no longer encodes the filename: pass the filename as an object to the new _PyRun_AnyFileObject() function. Add new private functions: * _PyRun_AnyFileObject() * _PyRun_InteractiveLoopObject() * _Py_FdIsInteractive() --- Include/cpython/pylifecycle.h | 1 + Include/cpython/pythonrun.h | 9 ++++ Modules/main.c | 35 +++---------- Python/pylifecycle.c | 15 ++++++ Python/pythonrun.c | 99 ++++++++++++++++++++++++++--------- 5 files changed, 106 insertions(+), 53 deletions(-) diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index f38ec5a4ae3..b4e2c8a8427 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -44,6 +44,7 @@ PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(PyObject *), PyObject *); PyAPI_FUNC(void) _Py_RestoreSignals(void); PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); +PyAPI_FUNC(int) _Py_FdIsInteractive(FILE *fp, PyObject *filename); PyAPI_FUNC(void) _Py_SetProgramFullPath(const wchar_t *); diff --git a/Include/cpython/pythonrun.h b/Include/cpython/pythonrun.h index febda73f3ec..e396a674bc4 100644 --- a/Include/cpython/pythonrun.h +++ b/Include/cpython/pythonrun.h @@ -13,6 +13,11 @@ PyAPI_FUNC(int) PyRun_AnyFileExFlags( const char *filename, /* decoded from the filesystem encoding */ int closeit, PyCompilerFlags *flags); +PyAPI_FUNC(int) _PyRun_AnyFileObject( + FILE *fp, + PyObject *filename, + int closeit, + PyCompilerFlags *flags); PyAPI_FUNC(int) PyRun_SimpleFileExFlags( FILE *fp, const char *filename, /* decoded from the filesystem encoding */ @@ -30,6 +35,10 @@ PyAPI_FUNC(int) PyRun_InteractiveLoopFlags( FILE *fp, const char *filename, /* decoded from the filesystem encoding */ PyCompilerFlags *flags); +PyAPI_FUNC(int) _PyRun_InteractiveLoopObject( + FILE *fp, + PyObject *filename, + PyCompilerFlags *flags); PyAPI_FUNC(PyObject *) PyRun_StringFlags(const char *, int, PyObject *, diff --git a/Modules/main.c b/Modules/main.c index 3aa4d91c9a3..7ffcb07a7fd 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -313,17 +313,8 @@ pymain_run_file(const PyConfig *config, PyCompilerFlags *cf) } FILE *fp = _Py_wfopen(filename, L"rb"); if (fp == NULL) { - char *cfilename_buffer; - const char *cfilename; - int err = errno; - cfilename_buffer = _Py_EncodeLocaleRaw(filename, NULL); - if (cfilename_buffer != NULL) - cfilename = cfilename_buffer; - else - cfilename = ""; - fprintf(stderr, "%ls: can't open file '%s': [Errno %d] %s\n", - config->program_name, cfilename, err, strerror(err)); - PyMem_RawFree(cfilename_buffer); + fprintf(stderr, "%ls: can't open file '%ls': [Errno %d] %s\n", + config->program_name, filename, errno, strerror(errno)); return 2; } @@ -353,25 +344,15 @@ pymain_run_file(const PyConfig *config, PyCompilerFlags *cf) return pymain_exit_err_print(); } - PyObject *unicode, *bytes = NULL; - const char *filename_str; - - unicode = PyUnicode_FromWideChar(filename, wcslen(filename)); - if (unicode != NULL) { - bytes = PyUnicode_EncodeFSDefault(unicode); - Py_DECREF(unicode); - } - if (bytes != NULL) { - filename_str = PyBytes_AsString(bytes); - } - else { - PyErr_Clear(); - filename_str = ""; + PyObject *filename_obj = PyUnicode_FromWideChar(filename, -1); + if (filename_obj == NULL) { + PyErr_Print(); + return -1; } /* PyRun_AnyFileExFlags(closeit=1) calls fclose(fp) before running code */ - int run = PyRun_AnyFileExFlags(fp, filename_str, 1, cf); - Py_XDECREF(bytes); + int run = _PyRun_AnyFileObject(fp, filename_obj, 1, cf); + Py_XDECREF(filename_obj); return (run != 0); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 70824ff6741..6a705b4d2b4 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2739,6 +2739,21 @@ Py_FdIsInteractive(FILE *fp, const char *filename) } +int +_Py_FdIsInteractive(FILE *fp, PyObject *filename) +{ + if (isatty((int)fileno(fp))) { + return 1; + } + if (!Py_InteractiveFlag) { + return 0; + } + return (filename == NULL) || + (PyUnicode_CompareWithASCIIString(filename, "") == 0) || + (PyUnicode_CompareWithASCIIString(filename, "???") == 0); +} + + /* Wrappers around sigaction() or signal(). */ PyOS_sighandler_t diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 15e407d9195..dacf1a64710 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -67,44 +67,69 @@ static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start, PyCompilerFlags *flags); +int +_PyRun_AnyFileObject(FILE *fp, PyObject *filename, int closeit, + PyCompilerFlags *flags) +{ + int decref_filename = 0; + if (filename == NULL) { + filename = PyUnicode_FromString("???"); + if (filename == NULL) { + PyErr_Print(); + return -1; + } + decref_filename = 1; + } + + int res; + if (_Py_FdIsInteractive(fp, filename)) { + res = _PyRun_InteractiveLoopObject(fp, filename, flags); + if (closeit) { + fclose(fp); + } + } + else { + res = _PyRun_SimpleFileObject(fp, filename, closeit, flags); + } + + if (decref_filename) { + Py_DECREF(filename); + } + return res; +} + + /* Parse input from a file and execute it */ int PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags) { - if (filename == NULL) - filename = "???"; - if (Py_FdIsInteractive(fp, filename)) { - int err = PyRun_InteractiveLoopFlags(fp, filename, flags); - if (closeit) - fclose(fp); - return err; + PyObject *filename_obj; + if (filename != NULL) { + filename_obj = PyUnicode_DecodeFSDefault(filename); + if (filename_obj == NULL) { + PyErr_Print(); + return -1; + } } - else - return PyRun_SimpleFileExFlags(fp, filename, closeit, flags); + else { + filename_obj = NULL; + } + int res = _PyRun_AnyFileObject(fp, filename_obj, closeit, flags); + Py_XDECREF(filename_obj); + return res; } + int -PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags *flags) +_PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { - PyObject *filename, *v; - int ret, err; PyCompilerFlags local_flags = _PyCompilerFlags_INIT; - int nomem_count = 0; -#ifdef Py_REF_DEBUG - int show_ref_count = _Py_GetConfig()->show_ref_count; -#endif - - filename = PyUnicode_DecodeFSDefault(filename_str); - if (filename == NULL) { - PyErr_Print(); - return -1; - } - if (flags == NULL) { flags = &local_flags; } - v = _PySys_GetObjectId(&PyId_ps1); + + PyObject *v = _PySys_GetObjectId(&PyId_ps1); if (v == NULL) { _PySys_SetObjectId(&PyId_ps1, v = PyUnicode_FromString(">>> ")); Py_XDECREF(v); @@ -114,7 +139,13 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags * _PySys_SetObjectId(&PyId_ps2, v = PyUnicode_FromString("... ")); Py_XDECREF(v); } - err = 0; + +#ifdef Py_REF_DEBUG + int show_ref_count = _Py_GetConfig()->show_ref_count; +#endif + int err = 0; + int ret; + int nomem_count = 0; do { ret = PyRun_InteractiveOneObjectEx(fp, filename, flags); if (ret == -1 && PyErr_Occurred()) { @@ -141,10 +172,26 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags * } #endif } while (ret != E_EOF); - Py_DECREF(filename); return err; } + +int +PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flags) +{ + PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); + if (filename_obj == NULL) { + PyErr_Print(); + return -1; + } + + int err = _PyRun_InteractiveLoopObject(fp, filename_obj, flags); + Py_DECREF(filename_obj); + return err; + +} + + /* A PyRun_InteractiveOneObject() auxiliary function that does not print the * error on failure. */ static int