| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 88a3342 commit ece3841
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -299,4 +299,8 @@ Importing Modules | |||
| 299 | 299 | field; failure to provide the sentinel value can result in a memory fault. | |
| 300 | 300 | Returns ``0`` on success or ``-1`` if insufficient memory could be allocated to | |
| 301 | 301 | extend the internal table. In the event of failure, no modules are added to the | |
| 302 | - internal table. This should be called before :c:func:`Py_Initialize`. | ||
| 302 | + internal table. This must be called before :c:func:`Py_Initialize`. | ||
| 303 | + | ||
| 304 | + If Python is initialized multiple times, :c:func:`PyImport_AppendInittab` or | ||
| 305 | + :c:func:`PyImport_ExtendInittab` must be called before each Python | ||
| 306 | + initialization. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1193,7 +1193,10 @@ The caller is responsible to handle exceptions (error or exit) using | |||
| 1193 | 1193 | ||
| 1194 | 1194 | If :c:func:`PyImport_FrozenModules`, :c:func:`PyImport_AppendInittab` or | |
| 1195 | 1195 | :c:func:`PyImport_ExtendInittab` are used, they must be set or called after | |
| 1196 | - Python preinitialization and before the Python initialization. | ||
| 1196 | + Python preinitialization and before the Python initialization. If Python is | ||
| 1197 | + initialized multiple times, :c:func:`PyImport_AppendInittab` or | ||
| 1198 | + :c:func:`PyImport_ExtendInittab` must be called before each Python | ||
| 1199 | + initialization. | ||
| 1197 | 1200 | ||
| 1198 | 1201 | The current configuration (``PyConfig`` type) is stored in | |
| 1199 | 1202 | ``PyInterpreterState.config``. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -30,6 +30,7 @@ | |||
| 30 | 30 | # _PyCoreConfig_InitIsolatedConfig() | |
| 31 | 31 | API_ISOLATED = 3 | |
| 32 | 32 | ||
| 33 | + INIT_LOOPS = 16 | ||
| 33 | 34 | MAX_HASH_SEED = 4294967295 | |
| 34 | 35 | ||
| 35 | 36 | ||
@@ -111,21 +112,21 @@ def run_repeated_init_and_subinterpreters(self): | |||
| 111 | 112 | self.assertEqual(err, "") | |
| 112 | 113 | ||
| 113 | 114 | # The output from _testembed looks like this: | |
| 114 | - # --- Pass 0 --- | ||
| 115 | + # --- Pass 1 --- | ||
| 115 | 116 | # interp 0 <0x1cf9330>, thread state <0x1cf9700>: id(modules) = 139650431942728 | |
| 116 | 117 | # interp 1 <0x1d4f690>, thread state <0x1d35350>: id(modules) = 139650431165784 | |
| 117 | 118 | # interp 2 <0x1d5a690>, thread state <0x1d99ed0>: id(modules) = 139650413140368 | |
| 118 | 119 | # interp 3 <0x1d4f690>, thread state <0x1dc3340>: id(modules) = 139650412862200 | |
| 119 | 120 | # interp 0 <0x1cf9330>, thread state <0x1cf9700>: id(modules) = 139650431942728 | |
| 120 | - # --- Pass 1 --- | ||
| 121 | + # --- Pass 2 --- | ||
| 121 | 122 | # ... | |
| 122 | 123 | ||
| 123 | 124 | interp_pat = (r"^interp (\d+) <(0x[\dA-F]+)>, " | |
| 124 | 125 | r"thread state <(0x[\dA-F]+)>: " | |
| 125 | 126 | r"id\(modules\) = ([\d]+)$") | |
| 126 | 127 | Interp = namedtuple("Interp", "id interp tstate modules") | |
| 127 | 128 | ||
| 128 | - numloops = 0 | ||
| 129 | + numloops = 1 | ||
| 129 | 130 | current_run = [] | |
| 130 | 131 | for line in out.splitlines(): | |
| 131 | 132 | if line == "--- Pass {} ---".format(numloops): | |
@@ -159,6 +160,8 @@ def run_repeated_init_and_subinterpreters(self): | |||
| 159 | 160 | ||
| 160 | 161 | ||
| 161 | 162 | class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase): | |
| 163 | + maxDiff = 100 * 50 | ||
| 164 | + | ||
| 162 | 165 | def test_subinterps_main(self): | |
| 163 | 166 | for run in self.run_repeated_init_and_subinterpreters(): | |
| 164 | 167 | main = run[0] | |
@@ -194,6 +197,14 @@ def test_subinterps_distinct_state(self): | |||
| 194 | 197 | self.assertNotEqual(sub.tstate, main.tstate) | |
| 195 | 198 | self.assertNotEqual(sub.modules, main.modules) | |
| 196 | 199 | ||
| 200 | + def test_repeated_init_and_inittab(self): | ||
| 201 | + out, err = self.run_embedded_interpreter("test_repeated_init_and_inittab") | ||
| 202 | + self.assertEqual(err, "") | ||
| 203 | + | ||
| 204 | + lines = [f"--- Pass {i} ---" for i in range(1, INIT_LOOPS+1)] | ||
| 205 | + lines = "\n".join(lines) + "\n" | ||
| 206 | + self.assertEqual(out, lines) | ||
| 207 | + | ||
| 197 | 208 | def test_forced_io_encoding(self): | |
| 198 | 209 | # Checks forced configuration of embedded interpreter IO streams | |
| 199 | 210 | env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape") | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,4 @@ | |||
| 1 | + :c:func:`Py_RunMain` now resets :c:data:`PyImport_Inittab` to its initial value | ||
| 2 | + at exit. It must be possible to call :c:func:`PyImport_AppendInittab` or | ||
| 3 | + :c:func:`PyImport_ExtendInittab` at each Python initialization. | ||
| 4 | + Patch by Victor Stinner. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,6 +22,9 @@ | |||
| 22 | 22 | /* Use path starting with "./" avoids a search along the PATH */ | |
| 23 | 23 | #define PROGRAM_NAME L"./_testembed" | |
| 24 | 24 | ||
| 25 | + #define INIT_LOOPS 16 | ||
| 26 | + | ||
| 27 | + | ||
| 25 | 28 | static void _testembed_Py_Initialize(void) | |
| 26 | 29 | { | |
| 27 | 30 | Py_SetProgramName(PROGRAM_NAME); | |
@@ -54,9 +57,8 @@ static int test_repeated_init_and_subinterpreters(void) | |||
| 54 | 57 | { | |
| 55 | 58 | PyThreadState *mainstate, *substate; | |
| 56 | 59 | PyGILState_STATE gilstate; | |
| 57 | - int i, j; | ||
| 58 | 60 | ||
| 59 | - for (i=0; i<15; i++) { | ||
| 61 | + for (int i=1; i <= INIT_LOOPS; i++) { | ||
| 60 | 62 | printf("--- Pass %d ---\n", i); | |
| 61 | 63 | _testembed_Py_Initialize(); | |
| 62 | 64 | mainstate = PyThreadState_Get(); | |
@@ -67,7 +69,7 @@ static int test_repeated_init_and_subinterpreters(void) | |||
| 67 | 69 | print_subinterp(); | |
| 68 | 70 | PyThreadState_Swap(NULL); | |
| 69 | 71 | ||
| 70 | - for (j=0; j<3; j++) { | ||
| 72 | + for (int j=0; j<3; j++) { | ||
| 71 | 73 | substate = Py_NewInterpreter(); | |
| 72 | 74 | print_subinterp(); | |
| 73 | 75 | Py_EndInterpreter(substate); | |
@@ -83,6 +85,20 @@ static int test_repeated_init_and_subinterpreters(void) | |||
| 83 | 85 | return 0; | |
| 84 | 86 | } | |
| 85 | 87 | ||
| 88 | + #define EMBEDDED_EXT_NAME "embedded_ext" | ||
| 89 | + | ||
| 90 | + static PyModuleDef embedded_ext = { | ||
| 91 | + PyModuleDef_HEAD_INIT, | ||
| 92 | + .m_name = EMBEDDED_EXT_NAME, | ||
| 93 | + .m_size = 0, | ||
| 94 | + }; | ||
| 95 | + | ||
| 96 | + static PyObject* | ||
| 97 | + PyInit_embedded_ext(void) | ||
| 98 | + { | ||
| 99 | + return PyModule_Create(&embedded_ext); | ||
| 100 | + } | ||
| 101 | + | ||
| 86 | 102 | /***************************************************** | |
| 87 | 103 | * Test forcing a particular IO encoding | |
| 88 | 104 | *****************************************************/ | |
@@ -1735,6 +1751,38 @@ static int list_frozen(void) | |||
| 1735 | 1751 | } | |
| 1736 | 1752 | ||
| 1737 | 1753 | ||
| 1754 | + static int test_repeated_init_and_inittab(void) | ||
| 1755 | + { | ||
| 1756 | + // bpo-44441: Py_RunMain() must reset PyImport_Inittab at exit. | ||
| 1757 | + // It must be possible to call PyImport_AppendInittab() or | ||
| 1758 | + // PyImport_ExtendInittab() before each Python initialization. | ||
| 1759 | + for (int i=1; i <= INIT_LOOPS; i++) { | ||
| 1760 | + printf("--- Pass %d ---\n", i); | ||
| 1761 | + | ||
| 1762 | + // Call PyImport_AppendInittab() at each iteration | ||
| 1763 | + if (PyImport_AppendInittab(EMBEDDED_EXT_NAME, | ||
| 1764 | + &PyInit_embedded_ext) != 0) { | ||
| 1765 | + fprintf(stderr, "PyImport_AppendInittab() failed\n"); | ||
| 1766 | + return 1; | ||
| 1767 | + } | ||
| 1768 | + | ||
| 1769 | + // Initialize Python | ||
| 1770 | + wchar_t* argv[] = {PROGRAM_NAME, L"-c", L"pass"}; | ||
| 1771 | + PyConfig config; | ||
| 1772 | + PyConfig_InitPythonConfig(&config); | ||
| 1773 | + config.isolated = 1; | ||
| 1774 | + config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv); | ||
| 1775 | + init_from_config_clear(&config); | ||
| 1776 | + | ||
| 1777 | + // Py_RunMain() calls _PyImport_Fini2() which resets PyImport_Inittab | ||
| 1778 | + int exitcode = Py_RunMain(); | ||
| 1779 | + if (exitcode != 0) { | ||
| 1780 | + return exitcode; | ||
| 1781 | + } | ||
| 1782 | + } | ||
| 1783 | + return 0; | ||
| 1784 | + } | ||
| 1785 | + | ||
| 1738 | 1786 | ||
| 1739 | 1787 | /* ********************************************************* | |
| 1740 | 1788 | * List of test cases and the function that implements it. | |
@@ -1755,8 +1803,10 @@ struct TestCase | |||
| 1755 | 1803 | }; | |
| 1756 | 1804 | ||
| 1757 | 1805 | static struct TestCase TestCases[] = { | |
| 1806 | + // Python initialization | ||
| 1758 | 1807 | {"test_forced_io_encoding", test_forced_io_encoding}, | |
| 1759 | 1808 | {"test_repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters}, | |
| 1809 | + {"test_repeated_init_and_inittab", test_repeated_init_and_inittab}, | ||
| 1760 | 1810 | {"test_pre_initialization_api", test_pre_initialization_api}, | |
| 1761 | 1811 | {"test_pre_initialization_sys_options", test_pre_initialization_sys_options}, | |
| 1762 | 1812 | {"test_bpo20891", test_bpo20891}, | |
@@ -1796,6 +1846,7 @@ static struct TestCase TestCases[] = { | |||
| 1796 | 1846 | {"test_run_main", test_run_main}, | |
| 1797 | 1847 | {"test_get_argc_argv", test_get_argc_argv}, | |
| 1798 | 1848 | ||
| 1849 | + // Audit | ||
| 1799 | 1850 | {"test_open_code_hook", test_open_code_hook}, | |
| 1800 | 1851 | {"test_audit", test_audit}, | |
| 1801 | 1852 | {"test_audit_subinterpreter", test_audit_subinterpreter}, | |
@@ -1805,8 +1856,10 @@ static struct TestCase TestCases[] = { | |||
| 1805 | 1856 | {"test_audit_run_startup", test_audit_run_startup}, | |
| 1806 | 1857 | {"test_audit_run_stdin", test_audit_run_stdin}, | |
| 1807 | 1858 | ||
| 1859 | + // Specific C API | ||
| 1808 | 1860 | {"test_unicode_id_init", test_unicode_id_init}, | |
| 1809 | 1861 | ||
| 1862 | + // Command | ||
| 1810 | 1863 | {"list_frozen", list_frozen}, | |
| 1811 | 1864 | {NULL, NULL} | |
| 1812 | 1865 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -255,6 +255,9 @@ _PyImport_Fini2(void) | |||
| 255 | 255 | PyMemAllocatorEx old_alloc; | |
| 256 | 256 | _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); | |
| 257 | 257 | ||
| 258 | + // Reset PyImport_Inittab | ||
| 259 | + PyImport_Inittab = _PyImport_Inittab; | ||
| 260 | + | ||
| 258 | 261 | /* Free memory allocated by PyImport_ExtendInittab() */ | |
| 259 | 262 | PyMem_RawFree(inittab_copy); | |
| 260 | 263 | inittab_copy = NULL; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments