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

(cherry picked from commit 2a9b8babf0d09946ebebfdb2931cc0d3db5a1d3d).
(cherry picked from commit 7c43b801503c802ed6ea4b811f5bc73791249d94)
diff --git a/Lib/platform.py b/Lib/platform.py
index 55f2fa8..44a612b 100755
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -140,9 +140,7 @@
                           '|'
                           '(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 @@
         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 @@
     else:
         return popen(cmd,mode,bufsize)
 
+
 def _norm_version(version, build=''):
 
     """ Normalize the version and build strings and return a single