From b8860ef6150bb6b7f0770180e9471b3c80aa8ffc Mon Sep 17 00:00:00 2001 From: benoitc Date: Wed, 20 Nov 2019 00:19:07 +0100 Subject: [PATCH 1/2] fix gunicorn when used with musl libc find_library('c') doesn't work in Alpine Linux. This happen because musl has a simpler implementation of libc. This patch fix it by extending ctypes.util.find_library to search the libs using LD_LIBRARY_PATH. Patch is based on https://github.com/python/cpython/commit/e3f67780aab24401a50af64e688d38c24ee41ad0 See also https://bugs.python.org/issue21622 fix #2160 --- gunicorn/socketfromfd.py | 2 +- gunicorn/util.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/gunicorn/socketfromfd.py b/gunicorn/socketfromfd.py index 69299200..74f6503d 100644 --- a/gunicorn/socketfromfd.py +++ b/gunicorn/socketfromfd.py @@ -12,7 +12,7 @@ import socket import sys import platform -from ctypes.util import find_library +from .util import find_library __all__ = ('fromfd',) diff --git a/gunicorn/util.py b/gunicorn/util.py index 8ccaf9b3..233094cc 100644 --- a/gunicorn/util.py +++ b/gunicorn/util.py @@ -3,6 +3,7 @@ # This file is part of gunicorn released under the MIT license. # See the NOTICE for more information. import ast +import ctypes.util import email.utils import errno import fcntl @@ -635,3 +636,32 @@ def bytes_to_str(b): def unquote_to_wsgi_str(string): return urllib.parse.unquote_to_bytes(string).decode('latin-1') + + +def _findWalk_ldpath(name): + def _is_elf(filepath): + try: + with open(filepath, 'rb') as fh: + return fh.read(4) == b'\x7fELF' + except: + return False + from glob import glob + if os.path.isabs(name): + return name + + # search LD_LIBRARY_PATH list + paths = os.environ.get('LD_LIBRARY_PATH', '').split(':') + if paths: + for d in paths: + f = os.path.join(d, name) + if _is_elf(f): + return os.path.basename(f) + prefix = os.path.join(d, 'lib'+name) + for suffix in ['.so', '.so.*']: + for f in glob('{0}{1}'.format(prefix, suffix)): + if _is_elf(f): + return os.path.basename(f) + + +def find_library(name): + return ctypes.util.find_library(name) or _findWalk_ldpath(name) From d55c7cb01505a1c4db946ea76bac4aef04a248cf Mon Sep 17 00:00:00 2001 From: benoitc Date: Wed, 20 Nov 2019 21:36:01 +0100 Subject: [PATCH 2/2] fix lib discovery LD_LIBRARY_PATH is sometimes empty, this change fix it. Also test suffix with the "." as it seems to be an issue --- gunicorn/util.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/gunicorn/util.py b/gunicorn/util.py index 233094cc..402123da 100644 --- a/gunicorn/util.py +++ b/gunicorn/util.py @@ -650,17 +650,19 @@ def _findWalk_ldpath(name): return name # search LD_LIBRARY_PATH list - paths = os.environ.get('LD_LIBRARY_PATH', '').split(':') - if paths: - for d in paths: - f = os.path.join(d, name) - if _is_elf(f): - return os.path.basename(f) - prefix = os.path.join(d, 'lib'+name) - for suffix in ['.so', '.so.*']: - for f in glob('{0}{1}'.format(prefix, suffix)): - if _is_elf(f): - return os.path.basename(f) + paths = ['/lib', '/usr/local/lib', '/usr/lib'] + if 'LD_LIBRARY_PATH' in os.environ: + paths = os.environ['LD_LIBRARY_PATH'].split(':') + paths + + for d in paths: + f = os.path.join(d, name) + if _is_elf(f): + return os.path.basename(f) + prefix = os.path.join(d, 'lib'+name) + for suffix in ['so', 'so.*']: + for f in glob('{0}.{1}'.format(prefix, suffix)): + if _is_elf(f): + return os.path.basename(f) def find_library(name):