[Python-checkins] cpython (merge 3.6 -> default): Issue #28522: Fixes mishandled buffer reallocation in getpathp.c

steve.dower python-checkins at python.org
Thu Oct 27 17:29:35 EDT 2016


https://hg.python.org/cpython/rev/72e64fc8746b
changeset:   104763:72e64fc8746b
parent:      104761:d103ee917342
parent:      104762:eea669163131
user:        Steve Dower <steve.dower at microsoft.com>
date:        Thu Oct 27 14:29:13 2016 -0700
summary:
  Issue #28522: Fixes mishandled buffer reallocation in getpathp.c

files:
  Lib/test/test_site.py |  52 +++++++++++++++++++++++++++++++
  Misc/NEWS             |   2 +
  PC/getpathp.c         |  19 ++++++++--
  3 files changed, 69 insertions(+), 4 deletions(-)


diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py
--- a/Lib/test/test_site.py
+++ b/Lib/test/test_site.py
@@ -488,6 +488,58 @@
             'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
         self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()")
 
+    @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows")
+    def test_underpth_nosite_file(self):
+        _pth_file = os.path.splitext(sys.executable)[0] + '._pth'
+        try:
+            libpath = os.path.dirname(os.path.dirname(encodings.__file__))
+            with open(_pth_file, 'w') as f:
+                print('fake-path-name', file=f)
+                # Ensure the generated path is very long so that buffer
+                # resizing in getpathp.c is exercised
+                for _ in range(200):
+                    print(libpath, file=f)
+                print('# comment', file=f)
+
+            env = os.environ.copy()
+            env['PYTHONPATH'] = 'from-env'
+            rc = subprocess.call([sys.executable, '-c',
+                'import sys; sys.exit(sys.flags.no_site and '
+                'len(sys.path) > 200 and '
+                '%r in sys.path and %r in sys.path and %r not in sys.path)' % (
+                    os.path.join(sys.prefix, 'fake-path-name'),
+                    libpath,
+                    os.path.join(sys.prefix, 'from-env'),
+                )], env=env)
+            self.assertEqual(rc, 0)
+        finally:
+            os.unlink(_pth_file)
+
+    @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows")
+    def test_underpth_file(self):
+        _pth_file = os.path.splitext(sys.executable)[0] + '._pth'
+        try:
+            libpath = os.path.dirname(os.path.dirname(encodings.__file__))
+            with open(_pth_file, 'w') as f:
+                print('fake-path-name', file=f)
+                for _ in range(200):
+                    print(libpath, file=f)
+                print('# comment', file=f)
+                print('import site', file=f)
+
+            env = os.environ.copy()
+            env['PYTHONPATH'] = 'from-env'
+            rc = subprocess.call([sys.executable, '-c',
+                'import sys; sys.exit(not sys.flags.no_site and '
+                '%r in sys.path and %r in sys.path and %r not in sys.path)' % (
+                    os.path.join(sys.prefix, 'fake-path-name'),
+                    libpath,
+                    os.path.join(sys.prefix, 'from-env'),
+                )], env=env)
+            self.assertEqual(rc, 0)
+        finally:
+            os.unlink(_pth_file)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -321,6 +321,8 @@
 Windows
 -------
 
+- Issue #28522: Fixes mishandled buffer reallocation in getpathp.c
+
 - Issue #28402: Adds signed catalog files for stdlib on Windows.
 
 - Issue #28333: Enables Unicode for ps1/ps2 and input() prompts. (Patch by
diff --git a/PC/getpathp.c b/PC/getpathp.c
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -581,7 +581,8 @@
         wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
         wline[wn] = '\0';
 
-        while (wn + prefixlen + 4 > bufsiz) {
+        size_t usedsiz = wcslen(buf);
+        while (usedsiz + wn + prefixlen + 4 > bufsiz) {
             bufsiz += MAXPATHLEN;
             buf = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) * sizeof(wchar_t));
             if (!buf) {
@@ -590,11 +591,21 @@
             }
         }
 
-        if (buf[0])
+        if (usedsiz) {
             wcscat_s(buf, bufsiz, L";");
+            usedsiz += 1;
+        }
 
-        wchar_t *b = &buf[wcslen(buf)];
-        wcscat_s(buf, bufsiz, prefix);
+        errno_t result;
+        _Py_BEGIN_SUPPRESS_IPH
+        result = wcscat_s(buf, bufsiz, prefix);
+        _Py_END_SUPPRESS_IPH
+        if (result == EINVAL) {
+            Py_FatalError("invalid argument during ._pth processing");
+        } else if (result == ERANGE) {
+            Py_FatalError("buffer overflow during ._pth processing");
+        }
+        wchar_t *b = &buf[usedsiz];
         join(b, wline);
 
         PyMem_RawFree(wline);

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list