mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-106242: Fix path truncation in os.path.normpath (GH-106816)
This commit is contained in:
parent
607f18c894
commit
0932272431
5 changed files with 30 additions and 9 deletions
|
@ -260,6 +260,7 @@ extern int _Py_add_relfile(wchar_t *dirname,
|
||||||
size_t bufsize);
|
size_t bufsize);
|
||||||
extern size_t _Py_find_basename(const wchar_t *filename);
|
extern size_t _Py_find_basename(const wchar_t *filename);
|
||||||
PyAPI_FUNC(wchar_t*) _Py_normpath(wchar_t *path, Py_ssize_t size);
|
PyAPI_FUNC(wchar_t*) _Py_normpath(wchar_t *path, Py_ssize_t size);
|
||||||
|
extern wchar_t *_Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *length);
|
||||||
|
|
||||||
// The Windows Games API family does not provide these functions
|
// The Windows Games API family does not provide these functions
|
||||||
// so provide our own implementations. Remove them in case they get added
|
// so provide our own implementations. Remove them in case they get added
|
||||||
|
|
|
@ -460,6 +460,10 @@ class CommonTest(GenericTest):
|
||||||
for path in ('', '.', '/', '\\', '///foo/.//bar//'):
|
for path in ('', '.', '/', '\\', '///foo/.//bar//'):
|
||||||
self.assertIsInstance(self.pathmodule.normpath(path), str)
|
self.assertIsInstance(self.pathmodule.normpath(path), str)
|
||||||
|
|
||||||
|
def test_normpath_issue106242(self):
|
||||||
|
for path in ('\x00', 'foo\x00bar', '\x00\x00', '\x00foo', 'foo\x00'):
|
||||||
|
self.assertEqual(self.pathmodule.normpath(path), path)
|
||||||
|
|
||||||
def test_abspath_issue3426(self):
|
def test_abspath_issue3426(self):
|
||||||
# Check that abspath returns unicode when the arg is unicode
|
# Check that abspath returns unicode when the arg is unicode
|
||||||
# with both ASCII and non-ASCII cwds.
|
# with both ASCII and non-ASCII cwds.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fixes :func:`os.path.normpath` to handle embedded null characters without truncating the path.
|
|
@ -5274,7 +5274,9 @@ os__path_normpath_impl(PyObject *module, PyObject *path)
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyObject *result = PyUnicode_FromWideChar(_Py_normpath(buffer, len), -1);
|
Py_ssize_t norm_len;
|
||||||
|
wchar_t *norm_path = _Py_normpath_and_size(buffer, len, &norm_len);
|
||||||
|
PyObject *result = PyUnicode_FromWideChar(norm_path, norm_len);
|
||||||
PyMem_Free(buffer);
|
PyMem_Free(buffer);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2377,12 +2377,14 @@ _Py_find_basename(const wchar_t *filename)
|
||||||
path, which will be within the original buffer. Guaranteed to not
|
path, which will be within the original buffer. Guaranteed to not
|
||||||
make the path longer, and will not fail. 'size' is the length of
|
make the path longer, and will not fail. 'size' is the length of
|
||||||
the path, if known. If -1, the first null character will be assumed
|
the path, if known. If -1, the first null character will be assumed
|
||||||
to be the end of the path. */
|
to be the end of the path. 'normsize' will be set to contain the
|
||||||
|
length of the resulting normalized path. */
|
||||||
wchar_t *
|
wchar_t *
|
||||||
_Py_normpath(wchar_t *path, Py_ssize_t size)
|
_Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
|
||||||
{
|
{
|
||||||
assert(path != NULL);
|
assert(path != NULL);
|
||||||
if (!path[0] || size == 0) {
|
if (!path[0] && size < 0 || size == 0) {
|
||||||
|
*normsize = 0;
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
wchar_t *pEnd = size >= 0 ? &path[size] : NULL;
|
wchar_t *pEnd = size >= 0 ? &path[size] : NULL;
|
||||||
|
@ -2431,11 +2433,7 @@ _Py_normpath(wchar_t *path, Py_ssize_t size)
|
||||||
*p2++ = lastC = *p1;
|
*p2++ = lastC = *p1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sepCount) {
|
minP2 = p2 - 1;
|
||||||
minP2 = p2; // Invalid path
|
|
||||||
} else {
|
|
||||||
minP2 = p2 - 1; // Absolute path has SEP at minP2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Skip past two leading SEPs
|
// Skip past two leading SEPs
|
||||||
|
@ -2495,13 +2493,28 @@ _Py_normpath(wchar_t *path, Py_ssize_t size)
|
||||||
while (--p2 != minP2 && *p2 == SEP) {
|
while (--p2 != minP2 && *p2 == SEP) {
|
||||||
*p2 = L'\0';
|
*p2 = L'\0';
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
--p2;
|
||||||
}
|
}
|
||||||
|
*normsize = p2 - path + 1;
|
||||||
#undef SEP_OR_END
|
#undef SEP_OR_END
|
||||||
#undef IS_SEP
|
#undef IS_SEP
|
||||||
#undef IS_END
|
#undef IS_END
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In-place path normalisation. Returns the start of the normalized
|
||||||
|
path, which will be within the original buffer. Guaranteed to not
|
||||||
|
make the path longer, and will not fail. 'size' is the length of
|
||||||
|
the path, if known. If -1, the first null character will be assumed
|
||||||
|
to be the end of the path. */
|
||||||
|
wchar_t *
|
||||||
|
_Py_normpath(wchar_t *path, Py_ssize_t size)
|
||||||
|
{
|
||||||
|
Py_ssize_t norm_length;
|
||||||
|
return _Py_normpath_and_size(path, size, &norm_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get the current directory. buflen is the buffer size in wide characters
|
/* Get the current directory. buflen is the buffer size in wide characters
|
||||||
including the null character. Decode the path from the locale encoding.
|
including the null character. Decode the path from the locale encoding.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue