Skip to content

Commit d73497b

Browse files
miss-islingtonserhiy-storchaka
authored andcommitted
bpo-26544: Fixed implementation of platform.libc_ver(). (GH-7684). (GH-8193) (GH-8195)
(cherry picked from commit 2a9b8ba) (cherry picked from commit 7c43b80)
1 parent 336c715 commit d73497b

File tree

4 files changed

+23
-13
lines changed

4 files changed

+23
-13
lines changed

Doc/library/platform.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ Unix Platforms
270270
.. deprecated-removed:: 3.5 3.8
271271
See alternative like the `distro <https://pypi.org/project/distro>`_ package.
272272

273-
.. function:: libc_ver(executable=sys.executable, lib='', version='', chunksize=2048)
273+
.. function:: libc_ver(executable=sys.executable, lib='', version='', chunksize=16384)
274274

275275
Tries to determine the libc version against which the file executable (defaults
276276
to the Python interpreter) is linked. Returns a tuple of strings ``(lib,

Lib/platform.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,7 @@
144144
b'|'
145145
br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
146146

147-
def libc_ver(executable=sys.executable, lib='', version='',
148-
149-
chunksize=16384):
147+
def libc_ver(executable=sys.executable, lib='', version='', chunksize=16384):
150148

151149
""" Tries to determine the libc version that the file executable
152150
(which defaults to the Python interpreter) is linked against.
@@ -161,6 +159,7 @@ def libc_ver(executable=sys.executable, lib='', version='',
161159
The file is read and scanned in chunks of chunksize bytes.
162160
163161
"""
162+
from distutils.version import LooseVersion as V
164163
if hasattr(os.path, 'realpath'):
165164
# Python 2.2 introduced os.path.realpath(); it is used
166165
# here to work around problems with Cygwin not being
@@ -169,17 +168,19 @@ def libc_ver(executable=sys.executable, lib='', version='',
169168
with open(executable, 'rb') as f:
170169
binary = f.read(chunksize)
171170
pos = 0
172-
while 1:
171+
while pos < len(binary):
173172
if b'libc' in binary or b'GLIBC' in binary:
174173
m = _libc_search.search(binary, pos)
175174
else:
176175
m = None
177-
if not m:
178-
binary = f.read(chunksize)
179-
if not binary:
176+
if not m or m.end() == len(binary):
177+
chunk = f.read(chunksize)
178+
if chunk:
179+
binary = binary[max(pos, len(binary) - 1000):] + chunk
180+
pos = 0
181+
continue
182+
if not m:
180183
break
181-
pos = 0
182-
continue
183184
libcinit, glibc, glibcversion, so, threads, soversion = [
184185
s.decode('latin1') if s is not None else s
185186
for s in m.groups()]
@@ -189,12 +190,12 @@ def libc_ver(executable=sys.executable, lib='', version='',
189190
if lib != 'glibc':
190191
lib = 'glibc'
191192
version = glibcversion
192-
elif glibcversion > version:
193+
elif V(glibcversion) > V(version):
193194
version = glibcversion
194195
elif so:
195196
if lib != 'glibc':
196197
lib = 'libc'
197-
if soversion and soversion > version:
198+
if soversion and (not version or V(soversion) > V(version)):
198199
version = soversion
199200
if threads and version[-len(threads):] != threads:
200201
version = version + threads
@@ -389,6 +390,7 @@ def popen(cmd, mode='r', bufsize=-1):
389390
warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
390391
return os.popen(cmd, mode, bufsize)
391392

393+
392394
def _norm_version(version, build=''):
393395

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

Lib/test/test_platform.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,6 @@ def test_dist(self):
270270
res = platform.dist()
271271

272272
def test_libc_ver(self):
273-
import os
274273
if os.path.isdir(sys.executable) and \
275274
os.path.exists(sys.executable+'.exe'):
276275
# Cygwin horror
@@ -279,6 +278,13 @@ def test_libc_ver(self):
279278
executable = sys.executable
280279
res = platform.libc_ver(executable)
281280

281+
self.addCleanup(support.unlink, support.TESTFN)
282+
with open(support.TESTFN, 'wb') as f:
283+
f.write(b'x'*(16384-10))
284+
f.write(b'GLIBC_1.23.4\0GLIBC_1.9\0GLIBC_1.21\0')
285+
self.assertEqual(platform.libc_ver(support.TESTFN),
286+
('glibc', '1.23.4'))
287+
282288
def test_parse_release_file(self):
283289

284290
for input, output in (
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)