Commit b1e6e561 authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

bpo-26544: Fixed implementation of platform.libc_ver(). (GH-7684). (GH-8193) (GH-8196)

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