bpo-26544: Fixed implementation of platform.libc_ver(). (GH-7684). (GH-8193) (GH-8196)
(cherry picked from commit2a9b8babf0
). (cherry picked from commit7c43b80150
)
This commit is contained in:
parent
3a98ddd136
commit
b1e6e5615a
|
@ -140,9 +140,7 @@ _libc_search = re.compile(r'(__libc_init)'
|
|||
'|'
|
||||
'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
|
||||
|
||||
def libc_ver(executable=sys.executable,lib='',version='',
|
||||
|
||||
chunksize=2048):
|
||||
def libc_ver(executable=sys.executable,lib='',version='', chunksize=2048):
|
||||
|
||||
""" Tries to determine the libc version that the file executable
|
||||
(which defaults to the Python interpreter) is linked against.
|
||||
|
@ -157,40 +155,42 @@ def libc_ver(executable=sys.executable,lib='',version='',
|
|||
The file is read and scanned in chunks of chunksize bytes.
|
||||
|
||||
"""
|
||||
from distutils.version import LooseVersion as V
|
||||
if hasattr(os.path, 'realpath'):
|
||||
# Python 2.2 introduced os.path.realpath(); it is used
|
||||
# here to work around problems with Cygwin not being
|
||||
# able to open symlinks for reading
|
||||
executable = os.path.realpath(executable)
|
||||
f = open(executable,'rb')
|
||||
binary = f.read(chunksize)
|
||||
pos = 0
|
||||
while 1:
|
||||
m = _libc_search.search(binary,pos)
|
||||
if not m:
|
||||
binary = f.read(chunksize)
|
||||
if not binary:
|
||||
break
|
||||
pos = 0
|
||||
continue
|
||||
libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
|
||||
if libcinit and not lib:
|
||||
lib = 'libc'
|
||||
elif glibc:
|
||||
if lib != 'glibc':
|
||||
lib = 'glibc'
|
||||
version = glibcversion
|
||||
elif glibcversion > version:
|
||||
version = glibcversion
|
||||
elif so:
|
||||
if lib != 'glibc':
|
||||
with open(executable, 'rb') as f:
|
||||
binary = f.read(chunksize)
|
||||
pos = 0
|
||||
while pos < len(binary):
|
||||
m = _libc_search.search(binary,pos)
|
||||
if not m or m.end() == len(binary):
|
||||
chunk = f.read(chunksize)
|
||||
if chunk:
|
||||
binary = binary[max(pos, len(binary) - 1000):] + chunk
|
||||
pos = 0
|
||||
continue
|
||||
if not m:
|
||||
break
|
||||
libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
|
||||
if libcinit and not lib:
|
||||
lib = 'libc'
|
||||
if soversion and soversion > version:
|
||||
version = soversion
|
||||
if threads and version[-len(threads):] != threads:
|
||||
version = version + threads
|
||||
pos = m.end()
|
||||
f.close()
|
||||
elif glibc:
|
||||
if lib != 'glibc':
|
||||
lib = 'glibc'
|
||||
version = glibcversion
|
||||
elif V(glibcversion) > V(version):
|
||||
version = glibcversion
|
||||
elif so:
|
||||
if lib != 'glibc':
|
||||
lib = 'libc'
|
||||
if soversion and (not version or V(soversion) > V(version)):
|
||||
version = soversion
|
||||
if threads and version[-len(threads):] != threads:
|
||||
version = version + threads
|
||||
pos = m.end()
|
||||
return lib,version
|
||||
|
||||
def _dist_try_harder(distname,version,id):
|
||||
|
@ -451,6 +451,7 @@ def popen(cmd, mode='r', bufsize=None):
|
|||
else:
|
||||
return popen(cmd,mode,bufsize)
|
||||
|
||||
|
||||
def _norm_version(version, build=''):
|
||||
|
||||
""" Normalize the version and build strings and return a single
|
||||
|
|
|
@ -4,7 +4,7 @@ import unittest
|
|||
import platform
|
||||
import subprocess
|
||||
|
||||
from test import test_support
|
||||
from test import support
|
||||
|
||||
class PlatformTest(unittest.TestCase):
|
||||
def test_architecture(self):
|
||||
|
@ -18,7 +18,7 @@ class PlatformTest(unittest.TestCase):
|
|||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
return p.communicate()
|
||||
real = os.path.realpath(sys.executable)
|
||||
link = os.path.abspath(test_support.TESTFN)
|
||||
link = os.path.abspath(support.TESTFN)
|
||||
os.symlink(real, link)
|
||||
try:
|
||||
self.assertEqual(get(real), get(link))
|
||||
|
@ -163,7 +163,7 @@ class PlatformTest(unittest.TestCase):
|
|||
# using it, per
|
||||
# http://blogs.msdn.com/david.wang/archive/2006/03/26/HOWTO-Detect-Process-Bitness.aspx
|
||||
try:
|
||||
with test_support.EnvironmentVarGuard() as environ:
|
||||
with support.EnvironmentVarGuard() as environ:
|
||||
if 'PROCESSOR_ARCHITEW6432' in environ:
|
||||
del environ['PROCESSOR_ARCHITEW6432']
|
||||
environ['PROCESSOR_ARCHITECTURE'] = 'foo'
|
||||
|
@ -247,7 +247,6 @@ class PlatformTest(unittest.TestCase):
|
|||
res = platform.dist()
|
||||
|
||||
def test_libc_ver(self):
|
||||
import os
|
||||
if os.path.isdir(sys.executable) and \
|
||||
os.path.exists(sys.executable+'.exe'):
|
||||
# Cygwin horror
|
||||
|
@ -256,6 +255,13 @@ class PlatformTest(unittest.TestCase):
|
|||
executable = sys.executable
|
||||
res = platform.libc_ver(executable)
|
||||
|
||||
self.addCleanup(support.unlink, support.TESTFN)
|
||||
with open(support.TESTFN, 'wb') as f:
|
||||
f.write(b'x'*(16384-10))
|
||||
f.write(b'GLIBC_1.23.4\0GLIBC_1.9\0GLIBC_1.21\0')
|
||||
self.assertEqual(platform.libc_ver(support.TESTFN),
|
||||
('glibc', '1.23.4'))
|
||||
|
||||
def test_parse_release_file(self):
|
||||
|
||||
for input, output in (
|
||||
|
@ -275,7 +281,7 @@ class PlatformTest(unittest.TestCase):
|
|||
|
||||
|
||||
def test_main():
|
||||
test_support.run_unittest(
|
||||
support.run_unittest(
|
||||
PlatformTest
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fixed implementation of :func:`platform.libc_ver`. It almost always returned
|
||||
version '2.9' for glibc.
|
Loading…
Reference in New Issue