[Python-Dev] Preventing 1.5 extensions crashing under 1.6/2.0 Python

Barry Scott barry@scottb.demon.co.uk
Sun, 16 Jul 2000 13:46:56 +0100

I've been looking at the code to see how hard it is to
implement my two function solution to the mismatched
extensions crash.

I can do the work to generate a patch if the following
analysis and design is acceptable.

Requirements as I see it are:

1. Python extensions must match the python core to work correctly
2. Python must only load an extension that is compatible with its API
3. Extensions written against python15 do not have to work
   against python16 etc.
4. No Python Core resources available for implementing backward
   compatibility for API changes.
5. Extension writers prefer new version of Python to refuse to load
   old extensions rather the risk subtle bugs through compatibility
   code in core.

I'll use XXX to stand in for the extension name.

The changes require that pointers to two functions are
returned rather the one to initXXX.

The function prefixes "init" and "APIversion" might be made more
python specific rather then generic. I propose:

- PythonExtensionInitModuleXXX
- PythonExtenaionApiVersionXXX

The current code calls _PyImport_GetDynLoadFunc that
is implemented once for each OS. There are 9 implemented
currently. Each does the prepend of "init" to the
"shortname" function name.

If two function pointers are to be returned then
the single function _PyImport_GetDynLoadFunc will
need to change into a pair of functions to prevent
the possiblity of loading the shared lib twice.

	return a handle to a dynamically loaded module
	return a pointer to a function from a module

_PyImport_LoadDynamicModule would call _PyImport_GetDynLoadModule
once to load the module and then call _PyImport_GetDynLoadFunction
twice to get the pair of function pointers.

[Q: _PyImport_LoadDynamicModule may still crash if the Python
    cannot catch failures in the OS load mechanism.]

_PyImport_GetDynLoadFunction will no longer prefix the "init"
as that is part of the algorithm of _PyImport_LoadDynamicModule.
_PyImport_GetDynLoadFunction would do any name manging that the
OS requires to load find the symbol. Prefixing of "_" for example
on some unixes.

Each extension module implements PythonExtensionInitModuleXXX
and PythonExtensionApiVersionXXX. PythonExtensionInitModuleXXX
is implemented as before. PythonExtensionApiVersionXXX
returns the value PYTHON_API_VERSION as defined in modsupport.h.

[Q: Is PYTHON_API_VERSION the corrent symbol?]

int PythonExtensionApiVersionXXX()

void PythonExtensionInitModuleXXX()
	/* init stuff for module XXX */

_PyImport_LoadDynamicModule will:

1. Try to load the module
	- on failure reports an error
2. Try to find PythonExtensionInitModuleXXX from module
	- on failure report not a python extension - no initXXX function
3. Try to find PythonExtensionApiVersionXXX from module
	- on failure report its an old extension - please upgrade
4. Call PythonExtensionApiVersionXXX and compare to PYTHON_API_VERSION
	- if not equal report its an old extension - please upgrade
5. Call PythonExtensionInitModuleXXX

Comments please?