Skip to content

Commit b1e6e56

Browse files
bpo-26544: Fixed implementation of platform.libc_ver(). (GH-7684). (GH-8193) (GH-8196)
(cherry picked from commit 2a9b8ba). (cherry picked from commit 7c43b80)
1 parent 3a98ddd commit b1e6e56

File tree

3 files changed

+45
-36
lines changed

3 files changed

+45
-36
lines changed

Lib/platform.py

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,7 @@
140140
'|'
141141
'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
142142

143-
def libc_ver(executable=sys.executable,lib='',version='',
144-
145-
chunksize=2048):
143+
def libc_ver(executable=sys.executable,lib='',version='', chunksize=2048):
146144

147145
""" Tries to determine the libc version that the file executable
148146
(which defaults to the Python interpreter) is linked against.
@@ -157,40 +155,42 @@ def libc_ver(executable=sys.executable,lib='',version='',
157155
The file is read and scanned in chunks of chunksize bytes.
158156
159157
"""
158+
from distutils.version import LooseVersion as V
160159
if hasattr(os.path, 'realpath'):
161160
# Python 2.2 introduced os.path.realpath(); it is used
162161
# here to work around problems with Cygwin not being
163162
# able to open symlinks for reading
164163
executable = os.path.realpath(executable)
165-
f = open(executable,'rb')
166-
binary = f.read(chunksize)
167-
pos = 0
168-
while 1:
169-
m = _libc_search.search(binary,pos)
170-
if not m:
171-
binary = f.read(chunksize)
172-
if not binary:
173-
break
174-
pos = 0
175-
continue
176-
libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
177-
if libcinit and not lib:
178-
lib = 'libc'
179-
elif glibc:
180-
if lib != 'glibc':
181-
lib = 'glibc'
182-
version = glibcversion
183-
elif glibcversion > version:
184-
version = glibcversion
185-
elif so:
186-
if lib != 'glibc':
164+
with open(executable, 'rb') as f:
165+
binary = f.read(chunksize)
166+
pos = 0
167+
while pos < len(binary):
168+
m = _libc_search.search(binary,pos)
169+
if not m or m.end() == len(binary):
170+
chunk = f.read(chunksize)
171+
if chunk:
172+
binary = binary[max(pos, len(binary) - 1000):] + chunk
173+
pos = 0
174+
continue
175+
if not m:
176+
break
177+
libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
178+
if libcinit and not lib:
187179
lib = 'libc'
188-
if soversion and soversion > version:
189-
version = soversion
190-
if threads and version[-len(threads):] != threads:
191-
version = version + threads
192-
pos = m.end()
193-
f.close()
180+
elif glibc:
181+
if lib != 'glibc':
182+
lib = 'glibc'
183+
version = glibcversion
184+
elif V(glibcversion) > V(version):
185+
version = glibcversion
186+
elif so:
187+
if lib != 'glibc':
188+
lib = 'libc'
189+
if soversion and (not version or V(soversion) > V(version)):
190+
version = soversion
191+
if threads and version[-len(threads):] != threads:
192+
version = version + threads
193+
pos = m.end()
194194
return lib,version
195195

196196
def _dist_try_harder(distname,version,id):
@@ -451,6 +451,7 @@ def popen(cmd, mode='r', bufsize=None):
451451
else:
452452
return popen(cmd,mode,bufsize)
453453

454+
454455
def _norm_version(version, build=''):
455456

456457
""" Normalize the version and build strings and return a single

Lib/test/test_platform.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import platform
55
import subprocess
66

7-
from test import test_support
7+
from test import support
88

99
class PlatformTest(unittest.TestCase):
1010
def test_architecture(self):
@@ -18,7 +18,7 @@ def get(python):
1818
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
1919
return p.communicate()
2020
real = os.path.realpath(sys.executable)
21-
link = os.path.abspath(test_support.TESTFN)
21+
link = os.path.abspath(support.TESTFN)
2222
os.symlink(real, link)
2323
try:
2424
self.assertEqual(get(real), get(link))
@@ -163,7 +163,7 @@ def test_uname_win32_ARCHITEW6432(self):
163163
# using it, per
164164
# http://blogs.msdn.com/david.wang/archive/2006/03/26/HOWTO-Detect-Process-Bitness.aspx
165165
try:
166-
with test_support.EnvironmentVarGuard() as environ:
166+
with support.EnvironmentVarGuard() as environ:
167167
if 'PROCESSOR_ARCHITEW6432' in environ:
168168
del environ['PROCESSOR_ARCHITEW6432']
169169
environ['PROCESSOR_ARCHITECTURE'] = 'foo'
@@ -247,7 +247,6 @@ def test_dist(self):
247247
res = platform.dist()
248248

249249
def test_libc_ver(self):
250-
import os
251250
if os.path.isdir(sys.executable) and \
252251
os.path.exists(sys.executable+'.exe'):
253252
# Cygwin horror
@@ -256,6 +255,13 @@ def test_libc_ver(self):
256255
executable = sys.executable
257256
res = platform.libc_ver(executable)
258257

258+
self.addCleanup(support.unlink, support.TESTFN)
259+
with open(support.TESTFN, 'wb') as f:
260+
f.write(b'x'*(16384-10))
261+
f.write(b'GLIBC_1.23.4\0GLIBC_1.9\0GLIBC_1.21\0')
262+
self.assertEqual(platform.libc_ver(support.TESTFN),
263+
('glibc', '1.23.4'))
264+
259265
def test_parse_release_file(self):
260266

261267
for input, output in (
@@ -275,7 +281,7 @@ def test_parse_release_file(self):
275281

276282

277283
def test_main():
278-
test_support.run_unittest(
284+
support.run_unittest(
279285
PlatformTest
280286
)
281287

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed implementation of :func:`platform.libc_ver`. It almost always returned
2+
version '2.9' for glibc.

0 commit comments

Comments
 (0)