@@ -40,7 +40,20 @@ def glibc_version_string_ctypes() -> Optional[str]:
40
40
# manpage says, "If filename is NULL, then the returned handle is for the
41
41
# main program". This way we can let the linker do the work to figure out
42
42
# which libc our process is actually using.
43
- process_namespace = ctypes .CDLL (None )
43
+ #
44
+ # We must also handle the special case where the executable is not a
45
+ # dynamically linked executable. This can occur when using musl libc,
46
+ # for example. In this situation, dlopen() will error, leading to an
47
+ # OSError. Interestingly, at least in the case of musl, there is no
48
+ # errno set on the OSError. The single string argument used to construct
49
+ # OSError comes from libc itself and is therefore not portable to
50
+ # hard code here. In any case, failure to call dlopen() means we
51
+ # can proceed, so we bail on our attempt.
52
+ try :
53
+ process_namespace = ctypes .CDLL (None )
54
+ except OSError :
55
+ return None
56
+
44
57
try :
45
58
gnu_get_libc_version = process_namespace .gnu_get_libc_version
46
59
except AttributeError :
@@ -50,7 +63,7 @@ def glibc_version_string_ctypes() -> Optional[str]:
50
63
51
64
# Call gnu_get_libc_version, which returns a string like "2.5"
52
65
gnu_get_libc_version .restype = ctypes .c_char_p
53
- version_str = gnu_get_libc_version ()
66
+ version_str : str = gnu_get_libc_version ()
54
67
# py2 / py3 compatibility:
55
68
if not isinstance (version_str , str ):
56
69
version_str = version_str .decode ("ascii" )
0 commit comments