diff --git a/Modules.Setup.2.7.static b/Modules.Setup.2.7.static index 44e7465..7deeea0 100644 --- a/Modules.Setup.2.7.static +++ b/Modules.Setup.2.7.static @@ -375,7 +375,7 @@ _curses _cursesmodule.c -lncurses # it is a highly experimental and dangerous device for calling # *arbitrary* C functions in *arbitrary* shared libraries: -#dl dlmodule.c +dl dlmodule.c # Modules that provide persistent dictionary-like semantics. You will diff --git a/Modules.dlmodule.2.7.c b/Modules.dlmodule.2.7.c new file mode 100644 index 0000000..cd33eb4 --- /dev/null +++ b/Modules.dlmodule.2.7.c @@ -0,0 +1,339 @@ + +/* dl module */ + +#include "Python.h" + +/* StaticPython */ +/* --- fake -ldl */ + +#include +#include + +/*#include */ +#define dlopen fake_dlopen +#define dlclose fake_dlclose +#define dlerror fake_dlerror +#define dlsym fake_dlsym + +/* Implements the slower insertion sort instead, but is compact. It makes no + * copies if the input is already sorted. + */ +void fake_qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { + register char *cur; + char *savecur, *end; + char tmp[size]; /* Variable-length array. */ + if (nmemb > 1) { + for (cur = (char*)base + size, end = (char*)base + (size * nmemb); cur != end; cur += size) { + if (compar(cur, cur - size) < 0) { + memcpy(tmp, cur, size); + savecur = cur; + do { + memcpy(cur, cur - size, size); + cur -= size; + } while (cur != (char*)base && compar(tmp, cur - size) < 0); + memcpy(cur, tmp, size); + cur = savecur; + } + } + } +} + +void *dlopen(const char *filename, int flag) { + return (void*)1; +} +char *dlerror(void) { + return "symbol not emulated"; +} +void *dlsym(void *handle, const char *symbol) { + (void)handle; + if (!strcmp(symbol, "qsort")) return fake_qsort; + if (!strcmp(symbol, "mmap")) return mmap; + if (!strcmp(symbol, "mprotect")) return mprotect; + if (!strcmp(symbol, "munmap")) return munmap; + if (!strcmp(symbol, "memmove")) return memmove; + return 0; +} +int dlclose(void *handle) { + (void)handle; + return 0; +} + +/* StaticPython */ + + +#ifdef __VMS +#include +#endif + +#ifndef RTLD_LAZY +#define RTLD_LAZY 1 +#endif + +typedef void *PyUnivPtr; +typedef struct { + PyObject_HEAD + PyUnivPtr *dl_handle; +} dlobject; + +static PyTypeObject Dltype; + +static PyObject *Dlerror; + +static PyObject * +newdlobject(PyUnivPtr *handle) +{ + dlobject *xp; + xp = PyObject_New(dlobject, &Dltype); + if (xp == NULL) + return NULL; + xp->dl_handle = handle; + return (PyObject *)xp; +} + +static void +dl_dealloc(dlobject *xp) +{ + if (xp->dl_handle != NULL) + dlclose(xp->dl_handle); + PyObject_Del(xp); +} + +static PyObject * +dl_close(dlobject *xp) +{ + if (xp->dl_handle != NULL) { + dlclose(xp->dl_handle); + xp->dl_handle = NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +dl_sym(dlobject *xp, PyObject *args) +{ + char *name; + PyUnivPtr *func; + if (PyString_Check(args)) { + name = PyString_AS_STRING(args); + } else { + PyErr_Format(PyExc_TypeError, "expected string, found %.200s", + Py_TYPE(args)->tp_name); + return NULL; + } + func = dlsym(xp->dl_handle, name); + if (func == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyInt_FromLong((long)func); +} + +static PyObject * +dl_call(dlobject *xp, PyObject *args) +{ + PyObject *name; + long (*func)(long, long, long, long, long, + long, long, long, long, long); + long alist[10]; + long res; + Py_ssize_t i; + Py_ssize_t n = PyTuple_Size(args); + const char *buffer; + Py_ssize_t size; + if (n < 1) { + PyErr_SetString(PyExc_TypeError, "at least a name is needed"); + return NULL; + } + name = PyTuple_GetItem(args, 0); + if (PyInt_Check(name)) { /* StaticPython */ + func = (long (*)(long, long, long, long, long, + long, long, long, long, long)) + PyInt_AsLong(name); + } else if (PyString_Check(name)) { + func = (long (*)(long, long, long, long, long, + long, long, long, long, long)) + dlsym(xp->dl_handle, PyString_AsString(name)); + } else { + PyErr_SetString(PyExc_TypeError, + "function name must be a string"); + return NULL; + } + if (func == NULL) { + PyErr_SetString(PyExc_ValueError, dlerror()); + return NULL; + } + if (n-1 > 10) { + PyErr_SetString(PyExc_TypeError, + "too many arguments (max 10)"); + return NULL; + } + for (i = 1; i < n; i++) { + PyObject *v = PyTuple_GetItem(args, i); + if (PyInt_Check(v)) + alist[i-1] = PyInt_AS_LONG(v); + else if (PyLong_Check(v)) { /* StaticPython */ + alist[i-1] = res = PyInt_AsLong(v); + if (res == -1 && PyErr_Occurred()) return 0; + } + else if (PyString_Check(v)) + alist[i-1] = (long)PyString_AsString(v); + else if (v == Py_None) + alist[i-1] = (long) ((char *)NULL); + else if (!PyObject_AsCharBuffer(v, &buffer, &size)) { + alist[i-1] = (long)buffer; + } + else { + PyErr_SetString(PyExc_TypeError, + "arguments must be int, string or None"); + return NULL; + } + } + for (; i <= 10; i++) + alist[i-1] = 0; + res = (*func)(alist[0], alist[1], alist[2], alist[3], alist[4], + alist[5], alist[6], alist[7], alist[8], alist[9]); + return PyInt_FromLong(res); +} + +static PyMethodDef dlobject_methods[] = { + {"call", (PyCFunction)dl_call, METH_VARARGS}, + {"sym", (PyCFunction)dl_sym, METH_O}, + {"close", (PyCFunction)dl_close, METH_NOARGS}, + {NULL, NULL} /* Sentinel */ +}; + +static PyObject * +dl_getattr(dlobject *xp, char *name) +{ + return Py_FindMethod(dlobject_methods, (PyObject *)xp, name); +} + + +static PyTypeObject Dltype = { + PyVarObject_HEAD_INIT(NULL, 0) + "dl.dl", /*tp_name*/ + sizeof(dlobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)dl_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)dl_getattr,/*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +static PyObject * +dl_open(PyObject *self, PyObject *args) +{ + char *name; + int mode; + PyUnivPtr *handle; + if (sizeof(int) != sizeof(long) || + sizeof(long) != sizeof(char *)) { + PyErr_SetString(PyExc_SystemError, + "module dl requires sizeof(int) == sizeof(long) == sizeof(char*)"); + return NULL; + } + + if (PyArg_ParseTuple(args, "z:open", &name)) + mode = RTLD_LAZY; + else { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "zi:open", &name, &mode)) + return NULL; +#ifndef RTLD_NOW + if (mode != RTLD_LAZY) { + PyErr_SetString(PyExc_ValueError, "mode must be 1"); + return NULL; + } +#endif + } + handle = dlopen(name, mode); + if (handle == NULL) { + char *errmsg = dlerror(); + if (!errmsg) + errmsg = "dlopen() error"; + PyErr_SetString(Dlerror, errmsg); + return NULL; + } +#ifdef __VMS + /* Under OpenVMS dlopen doesn't do any check, just save the name + * for later use, so we have to check if the file is readable, + * the name can be a logical or a file from SYS$SHARE. + */ + if (access(name, R_OK)) { + char fname[strlen(name) + 20]; + strcpy(fname, "SYS$SHARE:"); + strcat(fname, name); + strcat(fname, ".EXE"); + if (access(fname, R_OK)) { + dlclose(handle); + PyErr_SetString(Dlerror, + "File not found or protection violation"); + return NULL; + } + } +#endif + return newdlobject(handle); +} + +static PyMethodDef dl_methods[] = { + {"open", dl_open, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +initdl(void) +{ + PyObject *m, *d, *x; + + if (PyErr_WarnPy3k("the dl module has been removed in " + "Python 3.0; use the ctypes module instead", 2) < 0) + return; + + /* Initialize object type */ + Py_TYPE(&Dltype) = &PyType_Type; + + /* Create the module and add the functions */ + m = Py_InitModule("dl", dl_methods); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + Dlerror = x = PyErr_NewException("dl.error", NULL, NULL); + PyDict_SetItemString(d, "error", x); + x = PyInt_FromLong((long)RTLD_LAZY); + PyDict_SetItemString(d, "RTLD_LAZY", x); +#define INSINT(X) insint(d,#X,X) +#ifdef RTLD_NOW + INSINT(RTLD_NOW); +#endif +#ifdef RTLD_NOLOAD + INSINT(RTLD_NOLOAD); +#endif +#ifdef RTLD_GLOBAL + INSINT(RTLD_GLOBAL); +#endif +#ifdef RTLD_LOCAL + INSINT(RTLD_LOCAL); +#endif +#ifdef RTLD_PARENT + INSINT(RTLD_PARENT); +#endif +#ifdef RTLD_GROUP + INSINT(RTLD_GROUP); +#endif +#ifdef RTLD_WORLD + INSINT(RTLD_WORLD); +#endif +#ifdef RTLD_NODELETE + INSINT(RTLD_NODELETE); +#endif +} diff --git a/Modules.dlmodule.2.7.c.orig b/Modules.dlmodule.2.7.c.orig new file mode 100644 index 0000000..c349ad0 --- /dev/null +++ b/Modules.dlmodule.2.7.c.orig @@ -0,0 +1,284 @@ + +/* dl module */ + +#include "Python.h" + +#include + +#ifdef __VMS +#include +#endif + +#ifndef RTLD_LAZY +#define RTLD_LAZY 1 +#endif + +typedef void *PyUnivPtr; +typedef struct { + PyObject_HEAD + PyUnivPtr *dl_handle; +} dlobject; + +static PyTypeObject Dltype; + +static PyObject *Dlerror; + +static PyObject * +newdlobject(PyUnivPtr *handle) +{ + dlobject *xp; + xp = PyObject_New(dlobject, &Dltype); + if (xp == NULL) + return NULL; + xp->dl_handle = handle; + return (PyObject *)xp; +} + +static void +dl_dealloc(dlobject *xp) +{ + if (xp->dl_handle != NULL) + dlclose(xp->dl_handle); + PyObject_Del(xp); +} + +static PyObject * +dl_close(dlobject *xp) +{ + if (xp->dl_handle != NULL) { + dlclose(xp->dl_handle); + xp->dl_handle = NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +dl_sym(dlobject *xp, PyObject *args) +{ + char *name; + PyUnivPtr *func; + if (PyString_Check(args)) { + name = PyString_AS_STRING(args); + } else { + PyErr_Format(PyExc_TypeError, "expected string, found %.200s", + Py_TYPE(args)->tp_name); + return NULL; + } + func = dlsym(xp->dl_handle, name); + if (func == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyInt_FromLong((long)func); +} + +static PyObject * +dl_call(dlobject *xp, PyObject *args) +{ + PyObject *name; + long (*func)(long, long, long, long, long, + long, long, long, long, long); + long alist[10]; + long res; + Py_ssize_t i; + Py_ssize_t n = PyTuple_Size(args); + if (n < 1) { + PyErr_SetString(PyExc_TypeError, "at least a name is needed"); + return NULL; + } + name = PyTuple_GetItem(args, 0); + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "function name must be a string"); + return NULL; + } + func = (long (*)(long, long, long, long, long, + long, long, long, long, long)) + dlsym(xp->dl_handle, PyString_AsString(name)); + if (func == NULL) { + PyErr_SetString(PyExc_ValueError, dlerror()); + return NULL; + } + if (n-1 > 10) { + PyErr_SetString(PyExc_TypeError, + "too many arguments (max 10)"); + return NULL; + } + for (i = 1; i < n; i++) { + PyObject *v = PyTuple_GetItem(args, i); + if (PyInt_Check(v)) + alist[i-1] = PyInt_AsLong(v); + else if (PyString_Check(v)) + alist[i-1] = (long)PyString_AsString(v); + else if (v == Py_None) + alist[i-1] = (long) ((char *)NULL); + else { + PyErr_SetString(PyExc_TypeError, + "arguments must be int, string or None"); + return NULL; + } + } + for (; i <= 10; i++) + alist[i-1] = 0; + res = (*func)(alist[0], alist[1], alist[2], alist[3], alist[4], + alist[5], alist[6], alist[7], alist[8], alist[9]); + return PyInt_FromLong(res); +} + +static PyMethodDef dlobject_methods[] = { + {"call", (PyCFunction)dl_call, METH_VARARGS}, + {"sym", (PyCFunction)dl_sym, METH_O}, + {"close", (PyCFunction)dl_close, METH_NOARGS}, + {NULL, NULL} /* Sentinel */ +}; + +static PyObject * +dl_getattr(dlobject *xp, char *name) +{ + return Py_FindMethod(dlobject_methods, (PyObject *)xp, name); +} + + +static PyTypeObject Dltype = { + PyVarObject_HEAD_INIT(NULL, 0) + "dl.dl", /*tp_name*/ + sizeof(dlobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)dl_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)dl_getattr,/*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +static PyObject * +dl_open(PyObject *self, PyObject *args) +{ + char *name; + int mode; + PyUnivPtr *handle; + if (sizeof(int) != sizeof(long) || + sizeof(long) != sizeof(char *)) { + PyErr_SetString(PyExc_SystemError, + "module dl requires sizeof(int) == sizeof(long) == sizeof(char*)"); + return NULL; + } + + if (PyArg_ParseTuple(args, "z:open", &name)) + mode = RTLD_LAZY; + else { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "zi:open", &name, &mode)) + return NULL; +#ifndef RTLD_NOW + if (mode != RTLD_LAZY) { + PyErr_SetString(PyExc_ValueError, "mode must be 1"); + return NULL; + } +#endif + } + handle = dlopen(name, mode); + if (handle == NULL) { + char *errmsg = dlerror(); + if (!errmsg) + errmsg = "dlopen() error"; + PyErr_SetString(Dlerror, errmsg); + return NULL; + } +#ifdef __VMS + /* Under OpenVMS dlopen doesn't do any check, just save the name + * for later use, so we have to check if the file is readable, + * the name can be a logical or a file from SYS$SHARE. + */ + if (access(name, R_OK)) { + char fname[strlen(name) + 20]; + strcpy(fname, "SYS$SHARE:"); + strcat(fname, name); + strcat(fname, ".EXE"); + if (access(fname, R_OK)) { + dlclose(handle); + PyErr_SetString(Dlerror, + "File not found or protection violation"); + return NULL; + } + } +#endif + return newdlobject(handle); +} + +static PyMethodDef dl_methods[] = { + {"open", dl_open, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* From socketmodule.c + * Convenience routine to export an integer value. + * + * Errors are silently ignored, for better or for worse... + */ +static void +insint(PyObject *d, char *name, int value) +{ + PyObject *v = PyInt_FromLong((long) value); + if (!v || PyDict_SetItemString(d, name, v)) + PyErr_Clear(); + + Py_XDECREF(v); +} + +PyMODINIT_FUNC +initdl(void) +{ + PyObject *m, *d, *x; + + if (PyErr_WarnPy3k("the dl module has been removed in " + "Python 3.0; use the ctypes module instead", 2) < 0) + return; + + /* Initialize object type */ + Py_TYPE(&Dltype) = &PyType_Type; + + /* Create the module and add the functions */ + m = Py_InitModule("dl", dl_methods); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + Dlerror = x = PyErr_NewException("dl.error", NULL, NULL); + PyDict_SetItemString(d, "error", x); + x = PyInt_FromLong((long)RTLD_LAZY); + PyDict_SetItemString(d, "RTLD_LAZY", x); +#define INSINT(X) insint(d,#X,X) +#ifdef RTLD_NOW + INSINT(RTLD_NOW); +#endif +#ifdef RTLD_NOLOAD + INSINT(RTLD_NOLOAD); +#endif +#ifdef RTLD_GLOBAL + INSINT(RTLD_GLOBAL); +#endif +#ifdef RTLD_LOCAL + INSINT(RTLD_LOCAL); +#endif +#ifdef RTLD_PARENT + INSINT(RTLD_PARENT); +#endif +#ifdef RTLD_GROUP + INSINT(RTLD_GROUP); +#endif +#ifdef RTLD_WORLD + INSINT(RTLD_WORLD); +#endif +#ifdef RTLD_NODELETE + INSINT(RTLD_NODELETE); +#endif +} diff --git a/build.sh b/build.sh index 2b0942f..41787e3 100755 --- a/build.sh +++ b/build.sh @@ -193,7 +193,7 @@ if test -z "$STEPS"; then # Don't include betry here. # Please note that fixsetup appears multiple times here. This is intentional, # to get Modules/Setup right. - STEPS="initbuilddir initdeps buildlibssl buildlibevent2 buildlibtc configure fixsemaphore patchsetup fixsetup patchimport patchgetpath patchsqlite patchmu patchssl patchlocale fixsetup makeminipython extractpyrex patchsyncless patchgevent patchgeventmysql patchmsgpack patchpythontokyocabinet patchpythonlmdb patchconcurrence patchpycrypto patchaloaes fixsetup makepython buildpythonlibzip buildtarget" + STEPS="initbuilddir initdeps buildlibssl buildlibevent2 buildlibtc configure fixsemaphore patchsetup fixsetup patchimport patchdl patchgetpath patchsqlite patchmu patchssl patchlocale fixsetup makeminipython extractpyrex patchsyncless patchgevent patchgeventmysql patchmsgpack patchpythontokyocabinet patchpythonlmdb patchconcurrence patchpycrypto patchaloaes fixsetup makepython buildpythonlibzip buildtarget" fi INSTS="$INSTS_BASE" @@ -607,6 +607,15 @@ patchimport() { perl -pi~ -e 's@#ifdef HAVE_DYNAMIC_LOADING(?!_NOT)@#ifdef HAVE_DYNAMIC_LOADING_NOT /* StaticPython */@g' "$BUILDDIR"/Python/import.c "$BUILDDIR"/Python/importdl.c || return "$?" } +patchdl() { + # This patch is idempotent. + if test "$IS_PY3"; then : + elif test "$IS_MU"; then : + else + cp Modules.dlmodule.2.7.c "$BUILDDIR/Modules/dlmodule.c" || return "$?" + fi +} + patchgetpath() { # This patch is idempotent. # TODO(pts): Make sure that the source string is there for patching. diff --git a/calculate_path.2.7.c b/calculate_path.2.7.c index 9f1d17d..2076e3c 100644 --- a/calculate_path.2.7.c +++ b/calculate_path.2.7.c @@ -2,6 +2,8 @@ /* StaticPython */ /* StaticPython-appended */ #include +#include +#include static void calculate_path (void) { extern char *Py_GetProgramName(void); @@ -52,14 +54,29 @@ static void calculate_path (void) { /**** pts ****/ { int fd = open(proc_exe_path, O_RDONLY); + char hdr[22]; /* fprintf(stderr, "progpath=(%s)\n", progpath); */ if (fd < 0) { /* If /proc is not avaialbe, e.g. in chroot */ + after_bad_proc_exe: xzip_path = progpath; /* Use argv[0] for the .zip filename */ } else { xzip_path = proc_exe_path; + if (lseek(fd, -22, SEEK_END) < 0) { + bad_proc_exe: + close(fd); + goto after_bad_proc_exe; + } + if (read(fd, hdr, 22) != 22) goto bad_proc_exe; + /* ZIP end-ef-central-directory header with comment size == 0. */ + /* We check this because Linux i386 code running Docker on macOS + * Ventura 13 with Apple Silicon doesn't have a working + * /proc/self/exe, so we fall back to progpath (arg[0], sys.interpreter). + */ + if (memcmp(hdr, "PK\5\6", 4) != 0 || hdr[20] != 0 || hdr[21] != 0) goto bad_proc_exe; close(fd); } } + /*fprintf(stderr, "info: xzip_path=(%s)\n", xzip_path);*/ /**** pts ****/ if (rtpypath == NULL || rtpypath[0] == '\0') { diff --git a/release/pythonmu2.7-static b/release/pythonmu2.7-static index 6984882..af7ac5f 100755 Binary files a/release/pythonmu2.7-static and b/release/pythonmu2.7-static differ