gh-65821: Fix ctypes.util.find_library with musl by ncopa · Pull Request #18380 · python/cpython · GitHub
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 55 additions & 6 deletions Lib/ctypes/util.py
9 changes: 9 additions & 0 deletions Lib/test/test_ctypes/test_find.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ def test_find_library_with_ld(self):
unittest.mock.patch("ctypes.util._findLib_gcc", lambda *args: None):
self.assertNotEqual(find_library('c'), None)

def test_find_library_musl(self):
from _ctypes import get_interp
interp = get_interp()
if interp == None or interp.find("ld-musl-") == -1:
self.skipTest('ld-musl not detected')

with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None), \
unittest.mock.patch("ctypes.util._get_soname", lambda *args: None):
self.assertNotEqual(find_library('c'), None)

if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix :func:`ctypes.util.find_library` with musl libc.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not mention the introduced API.

53 changes: 53 additions & 0 deletions Modules/_ctypes/callproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@
#include <alloca.h>
#endif

#ifdef HAVE_ELF_H
#include <elf.h>
#endif
#ifdef HAVE_LINK_H
#include <link.h>
#endif

#ifdef _Py_MEMORY_SANITIZER
#include <sanitizer/msan_interface.h>
#endif
Expand Down Expand Up @@ -1992,7 +1999,52 @@ buffer_info(PyObject *self, PyObject *arg)
return Py_BuildValue("siN", dict->format, dict->ndim, shape);
}

#ifndef MS_WIN32

#ifdef HAVE_DL_ITERATE_PHDR
static int
interp_cb(struct dl_phdr_info *info, size_t size, void *data)
{
const char **ps = data;
Comment thread
erlend-aasland marked this conversation as resolved.
const char *base = (const char *)info->dlpi_addr;
const ElfW(Phdr) *ph = info->dlpi_phdr;
int phn = info->dlpi_phnum;

for (int i=0; i < phn; i++) {
if (ph[i].p_type == PT_INTERP) {
*ps = base + ph[i].p_vaddr;
return 1;
}
}
return 0;
}

static PyObject *
get_interp(PyObject *self, PyObject *arg)
{
const char *s = NULL;
if (PySys_Audit("ctypes.get_interp", NULL) < 0) {
return NULL;
}

if (dl_iterate_phdr(interp_cb, &s) == 1) {
return PyUnicode_FromString(s);
}

return NULL;
}

#else

static PyObject *
get_interp(PyObject *self, PyObject *arg)
{
return Py_None;
}

#endif

#endif

PyMethodDef _ctypes_module_methods[] = {
{"get_errno", get_errno, METH_NOARGS},
Expand All @@ -2015,6 +2067,7 @@ PyMethodDef _ctypes_module_methods[] = {
"dlopen(name, flag={RTLD_GLOBAL|RTLD_LOCAL}) open a shared library"},
{"dlclose", py_dl_close, METH_VARARGS, "dlclose a library"},
{"dlsym", py_dl_sym, METH_VARARGS, "find symbol in shared library"},
{"get_interp", get_interp, METH_NOARGS},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation is missing for this new API.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, if you introduce a new API, please use Argument Clinic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some way to add it as an internal function? So we don't expose it as a public API

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, you could prefix it with an underscore.

#endif
#ifdef __APPLE__
{"_dyld_shared_cache_contains_path", py_dyld_shared_cache_contains_path, METH_VARARGS, "check if path is in the shared cache"},
Expand Down
6 changes: 3 additions & 3 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2755,8 +2755,8 @@ AC_DEFINE(STDC_HEADERS, 1, [Define to 1 if you have the ANSI C header files.])

# checks for header files
AC_CHECK_HEADERS([ \
alloca.h asm/types.h bluetooth.h conio.h crypt.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \
ieeefp.h io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/memfd.h \
alloca.h asm/types.h bluetooth.h conio.h crypt.h direct.h dlfcn.h elf.h endian.h errno.h fcntl.h grp.h \
ieeefp.h io.h langinfo.h libintl.h libutil.h link.h linux/auxvec.h sys/auxv.h linux/fs.h linux/memfd.h \
linux/random.h linux/soundcard.h \
linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \
sched.h setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \
Expand Down Expand Up @@ -4717,7 +4717,7 @@ fi
# checks for library functions
AC_CHECK_FUNCS([ \
accept4 alarm bind_textdomain_codeset chmod chown clock close_range confstr \
copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \
copy_file_range ctermid dl_iterate_phdr dup dup3 execv explicit_bzero explicit_memset \
faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \
fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \
gai_strerror getegid getentropy geteuid getgid getgrgid getgrgid_r \
Expand Down
9 changes: 9 additions & 0 deletions pyconfig.h.in