From 6b2cbeba58aeb0755bdefd02fb51a80ec66d6144 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Fri, 14 Dec 2012 17:04:59 +0200 Subject: Issue #16421: allow to load multiple modules from the same shared object. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch by Václav Šmilauer. --- Lib/test/test_imp.py | 14 + Misc/ACKS | 1 + Misc/NEWS | 4 + Modules/_testimportmultiple.c | 57 +++ PC/VS9.0/_testimportmultiple.vcproj | 521 ++++++++++++++++++++++++++++ PC/VS9.0/pcbuild.sln | 21 ++ PCbuild/_testimportmultiple.vcxproj | 218 ++++++++++++ PCbuild/_testimportmultiple.vcxproj.filters | 13 + PCbuild/pcbuild.sln | 18 + Python/import.c | 27 +- Tools/msi/msi.py | 1 + setup.py | 2 + 12 files changed, 887 insertions(+), 10 deletions(-) create mode 100644 Modules/_testimportmultiple.c create mode 100644 PC/VS9.0/_testimportmultiple.vcproj create mode 100644 PCbuild/_testimportmultiple.vcxproj create mode 100644 PCbuild/_testimportmultiple.vcxproj.filters diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py index 65c9f25..bf2141f 100644 --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -217,6 +217,20 @@ class ImportTests(unittest.TestCase): mod = imp.load_module(example, *x) self.assertEqual(mod.__name__, example) + def test_issue16421_multiple_modules_in_one_dll(self): + # Issue 16421: loading several modules from the same compiled file fails + m = '_testimportmultiple' + fileobj, pathname, description = imp.find_module(m) + fileobj.close() + mod0 = imp.load_dynamic(m, pathname) + mod1 = imp.load_dynamic('foo', pathname) + mod2 = imp.load_dynamic('bar', pathname) + self.assertEqual(mod0.__name__, m) + self.assertEqual(mod1.__name__, 'foo') + self.assertEqual(mod2.__name__, 'bar') + with self.assertRaises(ImportError): + imp.load_dynamic('nonexistent', pathname) + def test_load_dynamic_ImportError_path(self): # Issue #1559549 added `name` and `path` attributes to ImportError # in order to provide better detail. Issue #10854 implemented those diff --git a/Misc/ACKS b/Misc/ACKS index e7b2d46..bb96fab 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1109,6 +1109,7 @@ George Sipe J. Sipprell Kragen Sitaker Michael Sloan +Václav Šmilauer Christopher Smith Eric V. Smith Gregory P. Smith diff --git a/Misc/NEWS b/Misc/NEWS index 91fc7c0..f04a08e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ What's New in Python 3.4.0 Alpha 1? Core and Builtins ----------------- +- Issue #16421: loading multiple modules from one shared object is now + handled correctly (previously, the first module loaded from that file + was silently returned). Patch by Václav Šmilauer. + - Issue #16602: When a weakref's target was part of a long deallocation chain, the object could remain reachable through its weakref even though its refcount had dropped to zero. diff --git a/Modules/_testimportmultiple.c b/Modules/_testimportmultiple.c new file mode 100644 index 0000000..baad29d --- /dev/null +++ b/Modules/_testimportmultiple.c @@ -0,0 +1,57 @@ +/* + * C extensions module to test importing multiple modules from one compiled + * file (issue16421). This file defines 3 modules (_testimportmodule, + * foo, bar), only the first one is called the same as the compiled file. + */ +#include + +static struct PyModuleDef _testimportmultiple = { + PyModuleDef_HEAD_INIT, + "_testimportmultiple", + "_testimportmultiple doc", + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit__testimportmultiple() +{ + return PyModule_Create(&_testimportmultiple); +} + +static struct PyModuleDef _foomodule = { + PyModuleDef_HEAD_INIT, + "foo", + "foo doc", + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit_foo() +{ + return PyModule_Create(&_foomodule); +} + +static struct PyModuleDef _barmodule = { + PyModuleDef_HEAD_INIT, + "bar", + "bar doc", + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit_bar(){ + return PyModule_Create(&_barmodule); +} + diff --git a/PC/VS9.0/_testimportmultiple.vcproj b/PC/VS9.0/_testimportmultiple.vcproj new file mode 100644 index 0000000..14d910d --- /dev/null +++ b/PC/VS9.0/_testimportmultiple.vcproj @@ -0,0 +1,521 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PC/VS9.0/pcbuild.sln b/PC/VS9.0/pcbuild.sln index 94cd4b5..9956e46 100644 --- a/PC/VS9.0/pcbuild.sln +++ b/PC/VS9.0/pcbuild.sln @@ -87,6 +87,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testcapi", "_testcapi.vcpr {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testimportmultiple", "_testimportmultiple.vcproj", "{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}" + ProjectSection(ProjectDependencies) = postProject + {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_tkinter", "_tkinter.vcproj", "{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}" ProjectSection(ProjectDependencies) = postProject {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} @@ -422,6 +427,22 @@ Global {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|Win32.Build.0 = Release|Win32 {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|x64.ActiveCfg = Release|x64 {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|x64.Build.0 = Release|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|Win32.ActiveCfg = Debug|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|Win32.Build.0 = Debug|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|x64.ActiveCfg = Debug|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|x64.Build.0 = Debug|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|x64.Build.0 = PGInstrument|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|x64.Build.0 = PGUpdate|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|Win32.ActiveCfg = Release|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|Win32.Build.0 = Release|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|x64.ActiveCfg = Release|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|x64.Build.0 = Release|x64 {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|Win32.ActiveCfg = Debug|Win32 {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|Win32.Build.0 = Debug|Win32 {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/PCbuild/_testimportmultiple.vcxproj b/PCbuild/_testimportmultiple.vcxproj new file mode 100644 index 0000000..84984ff --- /dev/null +++ b/PCbuild/_testimportmultiple.vcxproj @@ -0,0 +1,218 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + Win32 + + + Release + x64 + + + + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781} + _testimportmultiple + Win32Proj + + + + DynamicLibrary + NotSet + true + + + DynamicLibrary + NotSet + true + + + DynamicLibrary + NotSet + true + + + DynamicLibrary + NotSet + + + DynamicLibrary + NotSet + true + + + DynamicLibrary + NotSet + true + + + DynamicLibrary + NotSet + true + + + DynamicLibrary + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + 0x1e1F0000 + + + + + X64 + + + 0x1e1F0000 + + + + + 0x1e1F0000 + + + + + X64 + + + 0x1e1F0000 + + + + + 0x1e1F0000 + + + + + X64 + + + 0x1e1F0000 + MachineX64 + + + + + 0x1e1F0000 + + + + + X64 + + + 0x1e1F0000 + MachineX64 + + + + + + + + {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} + false + + + + + + diff --git a/PCbuild/_testimportmultiple.vcxproj.filters b/PCbuild/_testimportmultiple.vcxproj.filters new file mode 100644 index 0000000..db0d0a6 --- /dev/null +++ b/PCbuild/_testimportmultiple.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + {1ec38ad9-1abf-4b80-8628-ac43ccba324b} + + + + + Source Files + + + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln index 0edcdf6..e5ba1de 100644 --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -38,6 +38,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_ssl", "_ssl.vcxproj", "{C6 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testcapi", "_testcapi.vcxproj", "{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testimportmultiple", "_testimportmultiple.vcxproj", "{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_tkinter", "_tkinter.vcxproj", "{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_bz2", "_bz2.vcxproj", "{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}" @@ -344,6 +346,22 @@ Global {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|Win32.Build.0 = Release|Win32 {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|x64.ActiveCfg = Release|x64 {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|x64.Build.0 = Release|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|Win32.ActiveCfg = Debug|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|Win32.Build.0 = Debug|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|x64.ActiveCfg = Debug|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|x64.Build.0 = Debug|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|x64.Build.0 = PGInstrument|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|x64.Build.0 = PGUpdate|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|Win32.ActiveCfg = Release|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|Win32.Build.0 = Release|Win32 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|x64.ActiveCfg = Release|x64 + {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|x64.Build.0 = Release|x64 {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|Win32.ActiveCfg = Debug|Win32 {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|Win32.Build.0 = Debug|Win32 {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/Python/import.c b/Python/import.c index 6882b57..8e7482a 100644 --- a/Python/import.c +++ b/Python/import.c @@ -452,12 +452,12 @@ PyImport_GetMagicTag(void) /* Magic for extension modules (built-in as well as dynamically loaded). To prevent initializing an extension module more than - once, we keep a static dictionary 'extensions' keyed by module name - (for built-in modules) or by filename (for dynamically loaded - modules), containing these modules. A copy of the module's - dictionary is stored by calling _PyImport_FixupExtensionObject() - immediately after the module initialization function succeeds. A - copy can be retrieved from there by calling + once, we keep a static dictionary 'extensions' keyed by the tuple + (module name, module name) (for built-in modules) or by + (filename, module name) (for dynamically loaded modules), containing these + modules. A copy of the module's dictionary is stored by calling + _PyImport_FixupExtensionObject() immediately after the module initialization + function succeeds. A copy can be retrieved from there by calling _PyImport_FindExtensionObject(). Modules which do support multiple initialization set their m_size @@ -470,7 +470,7 @@ int _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name, PyObject *filename) { - PyObject *modules, *dict; + PyObject *modules, *dict, *filename_name; struct PyModuleDef *def; if (extensions == NULL) { extensions = PyDict_New(); @@ -508,7 +508,11 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name, if (def->m_base.m_copy == NULL) return -1; } - PyDict_SetItem(extensions, filename, (PyObject*)def); + filename_name = PyTuple_Pack(2,filename, name); + if (filename_name == NULL) + return -1; + if (PyDict_SetItem(extensions, filename_name, (PyObject*)def) < 0) + return -1; return 0; } @@ -528,11 +532,14 @@ _PyImport_FixupBuiltin(PyObject *mod, char *name) PyObject * _PyImport_FindExtensionObject(PyObject *name, PyObject *filename) { - PyObject *mod, *mdict; + PyObject *mod, *mdict, *filename_name; PyModuleDef* def; if (extensions == NULL) return NULL; - def = (PyModuleDef*)PyDict_GetItem(extensions, filename); + filename_name = PyTuple_Pack(2,filename, name); + if (filename_name == NULL) + return NULL; + def = (PyModuleDef*)PyDict_GetItem(extensions, filename_name); if (def == NULL) return NULL; if (def->m_size == -1) { diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py index f9b477f..cd1c60b 100644 --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -101,6 +101,7 @@ extensions = [ '_decimal.pyd', '_testbuffer.pyd', '_sha3.pyd', + '_testimportmultiple.pyd', ] # Well-known component UUIDs diff --git a/setup.py b/setup.py index c46a2ff..0eca3ec 100644 --- a/setup.py +++ b/setup.py @@ -594,6 +594,8 @@ class PyBuildExt(build_ext): depends=['testcapi_long.h']) ) # Python PEP-3118 (buffer protocol) test module exts.append( Extension('_testbuffer', ['_testbuffer.c']) ) + # Test loading multiple modules from one compiled file (http://bugs.python.org/issue16421) + exts.append( Extension('_testimportmultiple', ['_testimportmultiple.c']) ) # profiler (_lsprof is for cProfile.py) exts.append( Extension('_lsprof', ['_lsprof.c', 'rotatingtree.c']) ) # static Unicode character database -- cgit v0.12