mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	bpo-32381: Fix PyRun_SimpleFileExFlags() encoding (GH-23642) (GH-23692)
Fix encoding name when running a ".pyc" file on Windows:
PyRun_SimpleFileExFlags() now uses the correct encoding to decode the
filename.
* Add pyrun_file() subfunction.
* Add pyrun_simple_file() subfunction.
* PyRun_SimpleFileExFlags() now calls _Py_fopen_obj() rather than
  _Py_fopen().
(cherry picked from commit b6d98c10ff)
			
			
This commit is contained in:
		
							parent
							
								
									170dec3598
								
							
						
					
					
						commit
						f0e42ae03c
					
				
					 2 changed files with 138 additions and 95 deletions
				
			
		|  | @ -0,0 +1,3 @@ | |||
| Fix encoding name when running a ``.pyc`` file on Windows: | ||||
| :c:func:`PyRun_SimpleFileExFlags()` now uses the correct encoding to decode | ||||
| the filename. | ||||
|  | @ -64,11 +64,15 @@ extern Py_EXPORTED_SYMBOL grammar _PyParser_Grammar; /* From graminit.c */ | |||
| static void flush_io(void); | ||||
| static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *, | ||||
|                           PyCompilerFlags *, PyArena *); | ||||
| static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *, | ||||
| static PyObject *run_pyc_file(FILE *, PyObject *, PyObject *, | ||||
|                               PyCompilerFlags *); | ||||
| static void err_input(perrdetail *); | ||||
| static void err_free(perrdetail *); | ||||
| static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *); | ||||
| static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start, | ||||
|                             PyObject *globals, PyObject *locals, int closeit, | ||||
|                             PyCompilerFlags *flags); | ||||
| 
 | ||||
| 
 | ||||
| /* Parse input from a file and execute it */ | ||||
| int | ||||
|  | @ -310,14 +314,24 @@ PyRun_InteractiveOneFlags(FILE *fp, const char *filename_str, PyCompilerFlags *f | |||
|    the file type, and, if we may close it, at the first few bytes. */ | ||||
| 
 | ||||
| static int | ||||
| maybe_pyc_file(FILE *fp, const char* filename, const char* ext, int closeit) | ||||
| maybe_pyc_file(FILE *fp, PyObject *filename, int closeit) | ||||
| { | ||||
|     if (strcmp(ext, ".pyc") == 0) | ||||
|     PyObject *ext = PyUnicode_FromString(".pyc"); | ||||
|     if (ext == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     Py_ssize_t endswith = PyUnicode_Tailmatch(filename, ext, 0, PY_SSIZE_T_MAX, +1); | ||||
|     Py_DECREF(ext); | ||||
|     if (endswith) { | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     /* Only look into the file if we are allowed to close it, since
 | ||||
|        it then should also be seekable. */ | ||||
|     if (closeit) { | ||||
|     if (!closeit) { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     /* Read only two bytes of the magic. If the file was opened in
 | ||||
|        text mode, the bytes 3 and 4 of the magic (\r\n) might not | ||||
|        be read as they are on disk. */ | ||||
|  | @ -343,49 +357,46 @@ maybe_pyc_file(FILE *fp, const char* filename, const char* ext, int closeit) | |||
|     } | ||||
|     return ispyc; | ||||
| } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int | ||||
| set_main_loader(PyObject *d, const char *filename, const char *loader_name) | ||||
| set_main_loader(PyObject *d, PyObject *filename, const char *loader_name) | ||||
| { | ||||
|     PyObject *filename_obj, *bootstrap, *loader_type = NULL, *loader; | ||||
|     int result = 0; | ||||
| 
 | ||||
|     filename_obj = PyUnicode_DecodeFSDefault(filename); | ||||
|     if (filename_obj == NULL) | ||||
|         return -1; | ||||
|     PyInterpreterState *interp = _PyInterpreterState_GET(); | ||||
|     bootstrap = PyObject_GetAttrString(interp->importlib, | ||||
|     PyObject *bootstrap = PyObject_GetAttrString(interp->importlib, | ||||
|                                                  "_bootstrap_external"); | ||||
|     if (bootstrap != NULL) { | ||||
|         loader_type = PyObject_GetAttrString(bootstrap, loader_name); | ||||
|         Py_DECREF(bootstrap); | ||||
|     } | ||||
|     if (loader_type == NULL) { | ||||
|         Py_DECREF(filename_obj); | ||||
|     if (bootstrap == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     loader = PyObject_CallFunction(loader_type, "sN", "__main__", filename_obj); | ||||
| 
 | ||||
|     PyObject *loader_type = PyObject_GetAttrString(bootstrap, loader_name); | ||||
|     Py_DECREF(bootstrap); | ||||
|     if (loader_type == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     PyObject *loader = PyObject_CallFunction(loader_type, | ||||
|                                              "sO", "__main__", filename); | ||||
|     Py_DECREF(loader_type); | ||||
|     if (loader == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (PyDict_SetItemString(d, "__loader__", loader) < 0) { | ||||
|         result = -1; | ||||
|         Py_DECREF(loader); | ||||
|         return -1; | ||||
|     } | ||||
|     Py_DECREF(loader); | ||||
|     return result; | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, | ||||
| 
 | ||||
| static int | ||||
| pyrun_simple_file(FILE *fp, PyObject *filename, int closeit, | ||||
|                   PyCompilerFlags *flags) | ||||
| { | ||||
|     PyObject *m, *d, *v; | ||||
|     const char *ext; | ||||
|     int set_file_name = 0, ret = -1; | ||||
|     size_t len; | ||||
| 
 | ||||
|     m = PyImport_AddModule("__main__"); | ||||
|     if (m == NULL) | ||||
|  | @ -393,29 +404,29 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, | |||
|     Py_INCREF(m); | ||||
|     d = PyModule_GetDict(m); | ||||
|     if (PyDict_GetItemString(d, "__file__") == NULL) { | ||||
|         PyObject *f; | ||||
|         f = PyUnicode_DecodeFSDefault(filename); | ||||
|         if (f == NULL) | ||||
|             goto done; | ||||
|         if (PyDict_SetItemString(d, "__file__", f) < 0) { | ||||
|             Py_DECREF(f); | ||||
|         if (PyDict_SetItemString(d, "__file__", filename) < 0) { | ||||
|             goto done; | ||||
|         } | ||||
|         if (PyDict_SetItemString(d, "__cached__", Py_None) < 0) { | ||||
|             Py_DECREF(f); | ||||
|             goto done; | ||||
|         } | ||||
|         set_file_name = 1; | ||||
|         Py_DECREF(f); | ||||
|     } | ||||
|     len = strlen(filename); | ||||
|     ext = filename + len - (len > 4 ? 4 : 0); | ||||
|     if (maybe_pyc_file(fp, filename, ext, closeit)) { | ||||
| 
 | ||||
|     int pyc = maybe_pyc_file(fp, filename, closeit); | ||||
|     if (pyc < 0) { | ||||
|         goto done; | ||||
|     } | ||||
| 
 | ||||
|     if (pyc) { | ||||
|         FILE *pyc_fp; | ||||
|         /* Try to run a pyc file. First, re-open in binary */ | ||||
|         if (closeit) | ||||
|         if (closeit) { | ||||
|             fclose(fp); | ||||
|         if ((pyc_fp = _Py_fopen(filename, "rb")) == NULL) { | ||||
|         } | ||||
| 
 | ||||
|         pyc_fp = _Py_fopen_obj(filename, "rb"); | ||||
|         if (pyc_fp == NULL) { | ||||
|             fprintf(stderr, "python: Can't reopen .pyc file\n"); | ||||
|             goto done; | ||||
|         } | ||||
|  | @ -426,16 +437,16 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, | |||
|             fclose(pyc_fp); | ||||
|             goto done; | ||||
|         } | ||||
|         v = run_pyc_file(pyc_fp, filename, d, d, flags); | ||||
|         v = run_pyc_file(pyc_fp, d, d, flags); | ||||
|     } else { | ||||
|         /* When running from stdin, leave __main__.__loader__ alone */ | ||||
|         if (strcmp(filename, "<stdin>") != 0 && | ||||
|         if (PyUnicode_CompareWithASCIIString(filename, "<stdin>") != 0 && | ||||
|             set_main_loader(d, filename, "SourceFileLoader") < 0) { | ||||
|             fprintf(stderr, "python: failed to set __main__.__loader__\n"); | ||||
|             ret = -1; | ||||
|             goto done; | ||||
|         } | ||||
|         v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d, | ||||
|         v = pyrun_file(fp, filename, Py_file_input, d, d, | ||||
|                        closeit, flags); | ||||
|     } | ||||
|     flush_io(); | ||||
|  | @ -459,6 +470,21 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, | ||||
|                         PyCompilerFlags *flags) | ||||
| { | ||||
|     PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); | ||||
|     if (filename_obj == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     int res = pyrun_simple_file(fp, filename_obj, closeit, flags); | ||||
|     Py_DECREF(filename_obj); | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) | ||||
| { | ||||
|  | @ -1081,24 +1107,18 @@ PyRun_StringFlags(const char *str, int start, PyObject *globals, | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| PyObject * | ||||
| PyRun_FileExFlags(FILE *fp, const char *filename_str, int start, PyObject *globals, | ||||
| 
 | ||||
| static PyObject * | ||||
| pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, | ||||
|            PyObject *locals, int closeit, PyCompilerFlags *flags) | ||||
| { | ||||
|     PyObject *ret = NULL; | ||||
|     PyArena *arena = PyArena_New(); | ||||
|     if (arena == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     mod_ty mod; | ||||
|     PyArena *arena = NULL; | ||||
|     PyObject *filename; | ||||
|     int use_peg = _PyInterpreterState_GET()->config._use_peg_parser; | ||||
| 
 | ||||
|     filename = PyUnicode_DecodeFSDefault(filename_str); | ||||
|     if (filename == NULL) | ||||
|         goto exit; | ||||
| 
 | ||||
|     arena = PyArena_New(); | ||||
|     if (arena == NULL) | ||||
|         goto exit; | ||||
| 
 | ||||
|     if (use_peg) { | ||||
|         mod = PyPegen_ASTFromFileObject(fp, filename, start, NULL, NULL, NULL, | ||||
|                                         flags, NULL, arena); | ||||
|  | @ -1108,20 +1128,40 @@ PyRun_FileExFlags(FILE *fp, const char *filename_str, int start, PyObject *globa | |||
|                                          flags, NULL, arena); | ||||
|     } | ||||
| 
 | ||||
|     if (closeit) | ||||
|     if (closeit) { | ||||
|         fclose(fp); | ||||
|     if (mod == NULL) { | ||||
|         goto exit; | ||||
|     } | ||||
|     ret = run_mod(mod, filename, globals, locals, flags, arena); | ||||
| 
 | ||||
| exit: | ||||
|     Py_XDECREF(filename); | ||||
|     if (arena != NULL) | ||||
|     PyObject *ret; | ||||
|     if (mod != NULL) { | ||||
|         ret = run_mod(mod, filename, globals, locals, flags, arena); | ||||
|     } | ||||
|     else { | ||||
|         ret = NULL; | ||||
|     } | ||||
|     PyArena_Free(arena); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| PyObject * | ||||
| PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, | ||||
|                   PyObject *locals, int closeit, PyCompilerFlags *flags) | ||||
| { | ||||
|     PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); | ||||
|     if (filename_obj == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     PyObject *res = pyrun_file(fp, filename_obj, start, globals, | ||||
|                                locals, closeit, flags); | ||||
|     Py_DECREF(filename_obj); | ||||
|     return res; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| flush_io(void) | ||||
| { | ||||
|  | @ -1202,8 +1242,8 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, | |||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| run_pyc_file(FILE *fp, const char *filename, PyObject *globals, | ||||
|              PyObject *locals, PyCompilerFlags *flags) | ||||
| run_pyc_file(FILE *fp, PyObject *globals, PyObject *locals, | ||||
|              PyCompilerFlags *flags) | ||||
| { | ||||
|     PyThreadState *tstate = _PyThreadState_GET(); | ||||
|     PyCodeObject *co; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner