diff --git a/PyInstaller/bootloader/Windows-64bit/run.exe b/PyInstaller/bootloader/Windows-64bit/run.exe index fe607c20c62..a44b7f8c3ea 100644 Binary files a/PyInstaller/bootloader/Windows-64bit/run.exe and b/PyInstaller/bootloader/Windows-64bit/run.exe differ diff --git a/PyInstaller/bootloader/Windows-64bit/run_d.exe b/PyInstaller/bootloader/Windows-64bit/run_d.exe index ae028c20402..e754ac05007 100644 Binary files a/PyInstaller/bootloader/Windows-64bit/run_d.exe and b/PyInstaller/bootloader/Windows-64bit/run_d.exe differ diff --git a/PyInstaller/bootloader/Windows-64bit/runw.exe b/PyInstaller/bootloader/Windows-64bit/runw.exe index 4a246f12c19..4ec560c885a 100644 Binary files a/PyInstaller/bootloader/Windows-64bit/runw.exe and b/PyInstaller/bootloader/Windows-64bit/runw.exe differ diff --git a/PyInstaller/bootloader/Windows-64bit/runw_d.exe b/PyInstaller/bootloader/Windows-64bit/runw_d.exe index 5e2d750416d..fc300a75f77 100644 Binary files a/PyInstaller/bootloader/Windows-64bit/runw_d.exe and b/PyInstaller/bootloader/Windows-64bit/runw_d.exe differ diff --git a/bootloader/src/pyi_launch.c b/bootloader/src/pyi_launch.c index d9cd431eb34..d5e0f448b7e 100644 --- a/bootloader/src/pyi_launch.c +++ b/bootloader/src/pyi_launch.c @@ -363,13 +363,17 @@ int pyi_launch_run_scripts(ARCHIVE_STATUS *status) { unsigned char *data; + const char *cchar_pvalue, *cchar_tb; char buf[PATH_MAX]; + char *char_pvalue, *char_tb, *module_name; size_t namelen; TOC * ptoc = status->tocbuff; PyObject *__main__; PyObject *__file__; PyObject *main_dict; PyObject *code, *retval; + PyObject *ptype, *pvalue, *ptraceback; + PyObject *pyth_str_pvalue, *pyth_tb, *pyth_str_tb, *pyth_module, *pyth_func; __main__ = PI_PyImport_AddModule("__main__"); @@ -422,14 +426,64 @@ pyi_launch_run_scripts(ARCHIVE_STATUS *status) /* Run it */ retval = PI_PyEval_EvalCode(code, main_dict, main_dict); - /* If retval is NULL, an error occured. Otherwise, it is a Python object. + /* If retval is NULL, an error occurred. Otherwise, it is a Python object. * (Since we evaluate module-level code, which is not allowed to return an * object, the Python object returned is always None.) */ if (!retval) { - PI_PyErr_Print(); - /* If the error was SystemExit, PyErr_Print calls exit() without - * returning. So don't print "Failed to execute" on SystemExit. */ FATALERROR("Failed to execute script %s\n", ptoc->name); + + #if defined(_WIN32) && defined(WINDOWED) && defined(LAUNCH_DEBUG) + /* If running in Windows in windowed mode with debug, print + * the traceback to a message box */ + + /* First get the value of the error */ + + PI_PyErr_Fetch(&ptype, &pvalue, &ptraceback); + pyth_str_pvalue = PI_PyObject_Str(pvalue); + + if (is_py2) { + char_pvalue = PI_PyString_AsString(pyth_str_pvalue); + FATALERROR("Error: %s\n", char_pvalue); + } else { + cchar_pvalue = PI_PyUnicode_AsUTF8(pyth_str_pvalue); + FATALERROR("Error: %s\n", cchar_pvalue); + } + Py_DECREF(pyth_str_pvalue); + + /* Next see if we can get a full traceback, only works with + * --noarchive */ + + module_name = "traceback"; + pyth_module = PI_PyImport_ImportModule(module_name); + + if (pyth_module != NULL) { + pyth_func = PI_PyObject_GetAttrString(pyth_module, "format_exception"); + if (pyth_func) { + pyth_tb = PI_PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, NULL); + pyth_str_tb = PI_PyObject_Str(pyth_tb); + if (is_py2) { + char_tb = PI_PyString_AsString(pyth_str_tb); + FATALERROR("Traceback: %s\n", char_tb); + } else { + cchar_tb = PI_PyUnicode_AsUTF8(pyth_str_tb); + FATALERROR("Traceback: %s\n", cchar_tb); + } + Py_DECREF(pyth_tb); + Py_DECREF(pyth_str_tb); + } + Py_DECREF(pyth_func); + } + Py_DECREF(ptype); + Py_DECREF(pvalue); + Py_DECREF(ptraceback); + Py_DECREF(pyth_module); + + #else /* if defined(_WIN32) and defined(WINDOWED) and defined(LAUNCH_DEBUG) */ + + PI_PyErr_Print(); + + #endif /* if defined(_WIN32) and defined(WINDOWED) and defined(LAUNCH_DEBUG) */ + return -1; } free(data); diff --git a/bootloader/src/pyi_python.c b/bootloader/src/pyi_python.c index 91804f26daf..a337b5d8389 100644 --- a/bootloader/src/pyi_python.c +++ b/bootloader/src/pyi_python.c @@ -55,6 +55,11 @@ DECLPROC(PyErr_Clear); DECLPROC(PyErr_Occurred); DECLPROC(PyErr_Print); +DECLPROC(PyErr_Fetch); +DECLPROC(PyObject_Str); +DECLPROC(PyUnicode_AsUTF8); +DECLPROC(PyObject_GetAttrString); + DECLPROC(PyImport_AddModule); DECLPROC(PyImport_ExecCodeModule); DECLPROC(PyImport_ImportModule); @@ -63,9 +68,11 @@ DECLPROC(PyList_New); DECLPROC(PyLong_AsLong); DECLPROC(PyModule_GetDict); DECLPROC(PyObject_CallFunction); +DECLPROC(PyObject_CallFunctionObjArgs); DECLPROC(PyObject_SetAttrString); DECLPROC(PyRun_SimpleString); DECLPROC(PyString_FromString); +DECLPROC(PyString_AsString); DECLPROC(PySys_AddWarnOption); DECLPROC(PySys_SetArgvEx); DECLPROC(PySys_GetObject); @@ -127,12 +134,20 @@ pyi_python_map_names(HMODULE dll, int pyvers) GETPROC(dll, PyLong_AsLong); GETPROC(dll, PyModule_GetDict); GETPROC(dll, PyObject_CallFunction); + GETPROC(dll, PyObject_CallFunctionObjArgs); GETPROC(dll, PyObject_SetAttrString); + GETPROC(dll, PyObject_GetAttrString); + GETPROC(dll, PyRun_SimpleString); + GETPROC(dll, PyObject_Str); + + GETPROC(dll, PyErr_Fetch); + if (pyvers < 30) { GETPROC(dll, PyString_FromString); GETPROC(dll, PyString_FromFormat); + GETPROC(dll, PyString_AsString); } ; GETPROC(dll, PySys_AddWarnOption); @@ -168,6 +183,11 @@ pyi_python_map_names(HMODULE dll, int pyvers) GETPROC(dll, PyUnicode_DecodeFSDefault); } + if (pyvers >= 33) { + /* new in Python 3.3 */ + GETPROC(dll, PyUnicode_AsUTF8); + } + VS("LOADER: Loaded functions from Python library.\n"); return 0; diff --git a/bootloader/src/pyi_python.h b/bootloader/src/pyi_python.h index fb57e48a5e4..07cebc306f6 100644 --- a/bootloader/src/pyi_python.h +++ b/bootloader/src/pyi_python.h @@ -122,6 +122,7 @@ EXTDECLPROC(PyObject *, PyString_FromString, (const char *)); /* Create a Unicode object from the char buffer. The bytes will be interpreted as being UTF-8 encoded. */ EXTDECLPROC(PyObject *, PyUnicode_FromString, (const char *)); EXTDECLPROC(PyObject *, PyObject_CallFunction, (PyObject *, char *, ...)); +EXTDECLPROC(PyObject *, PyObject_CallFunctionObjArgs, (PyObject *, ...)); EXTDECLPROC(PyObject *, PyModule_GetDict, (PyObject *)); EXTDECLPROC(PyObject *, PyDict_GetItemString, (PyObject *, char *)); EXTDECLPROC(void, PyErr_Clear, (void) ); @@ -151,6 +152,13 @@ EXTDECLPROC(PyObject *, PyUnicode_Decode, EXTDECLPROC(PyObject *, PyEval_EvalCode, (PyObject *, PyObject *, PyObject *)); EXTDECLPROC(PyObject *, PyMarshal_ReadObjectFromString, (const char *, size_t)); /* Py_ssize_t */ +/* Used to get traceback information while launching run scripts */ +EXTDECLPROC(void, PyErr_Fetch, (PyObject **, PyObject **, PyObject **)); +EXTDECLPROC(PyObject *, PyObject_Str, (PyObject *)); +EXTDECLPROC(PyObject *, PyObject_GetAttrString, (PyObject *, const char *)); +EXTDECLPROC(const char *, PyUnicode_AsUTF8, (PyObject *)); +EXTDECLPROC(char *, PyString_AsString, (PyObject *)); + /* * Macros for reference counting through exported functions * (that is: without binding to the binary structure of a PyObject. diff --git a/news/4592.bootloader.rst b/news/4592.bootloader.rst new file mode 100644 index 00000000000..e2315c8137d --- /dev/null +++ b/news/4592.bootloader.rst @@ -0,0 +1 @@ +(Windows) Add ability to get traceback to debug pyiboot01_bootstrap errors. \ No newline at end of file