SF bug #495021: Crash calling os.stat with a trailing backslash

Patch from Mark Hammond, plus code rearrangement and comments from me.
posix_do_stat():  Windows-specific code could try to free() stack
memory in some cases when a path ending with a forward or backward slash
was passed to os.stat().
This commit is contained in:
Tim Peters 2001-12-19 19:05:01 +00:00
parent 04a866170d
commit 500bd035fa

View file

@ -679,7 +679,8 @@ posix_do_stat(PyObject *self, PyObject *args, char *format,
int (*statfunc)(const char *, STRUCT_STAT *)) int (*statfunc)(const char *, STRUCT_STAT *))
{ {
STRUCT_STAT st; STRUCT_STAT st;
char *path = NULL; char *path = NULL; /* pass this to stat; do not free() it */
char *pathfree = NULL; /* this memory must be free'd */
int res; int res;
#ifdef MS_WIN32 #ifdef MS_WIN32
@ -690,25 +691,30 @@ posix_do_stat(PyObject *self, PyObject *args, char *format,
if (!PyArg_ParseTuple(args, format, if (!PyArg_ParseTuple(args, format,
Py_FileSystemDefaultEncoding, &path)) Py_FileSystemDefaultEncoding, &path))
return NULL; return NULL;
pathfree = path;
#ifdef MS_WIN32 #ifdef MS_WIN32
pathlen = strlen(path); pathlen = strlen(path);
/* the library call can blow up if the file name is too long! */ /* the library call can blow up if the file name is too long! */
if (pathlen > MAX_PATH) { if (pathlen > MAX_PATH) {
PyMem_Free(path); PyMem_Free(pathfree);
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return posix_error(); return posix_error();
} }
if ((pathlen > 0) && (path[pathlen-1] == '\\' || path[pathlen-1] == '/')) { /* Remove trailing slash or backslash, unless it's the current
/* exception for specific or current drive root */ drive root (/ or \) or a specific drive's root (like c:\ or c:/).
if (!((pathlen == 1) || */
((pathlen == 3) && if (pathlen > 0 &&
(path[1] == ':') && (path[pathlen-1]== '\\' || path[pathlen-1] == '/')) {
(path[2] == '\\' || path[2] == '/')))) /* It does end with a slash -- exempt the root drive cases. */
{ /* XXX UNC root drives should also be exempted? */
if (pathlen == 1 || (pathlen == 3 && path[1] == ':'))
/* leave it alone */;
else {
/* nuke the trailing backslash */
strncpy(pathcopy, path, pathlen); strncpy(pathcopy, path, pathlen);
pathcopy[pathlen-1] = '\0'; /* nuke the trailing backslash */ pathcopy[pathlen-1] = '\0';
path = pathcopy; path = pathcopy;
} }
} }
@ -718,9 +724,9 @@ posix_do_stat(PyObject *self, PyObject *args, char *format,
res = (*statfunc)(path, &st); res = (*statfunc)(path, &st);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (res != 0) if (res != 0)
return posix_error_with_allocated_filename(path); return posix_error_with_allocated_filename(pathfree);
PyMem_Free(path); PyMem_Free(pathfree);
return _pystat_fromstructstat(st); return _pystat_fromstructstat(st);
} }