[PATCH] fix osutil.c, error handling, fd leak

Benoit Boissinot benoit.boissinot at ens-lyon.org
Thu Sep 11 13:06:49 CDT 2008


On Thu, Sep 11, 2008 at 01:28:01PM -0400, Petr Kodl wrote:
> 
> Isn't this going to decrement Py_None one too many if the PyList_Append
> fails?
> 

You're right, thanks.

updated patch below.

# HG changeset patch
# User Benoit Boissinot <benoit.boissinot at ens-lyon.org>
# Date 1221146411 -7200
# Node ID 31afce165e9bb1ac83f3a35fa22f6ad5116c2093
# Parent  ab57069232b4d9ce95e5898d9154410988008ba2
osutil: proper error handling

Check after every call that might fail, raise the proper exception
(e.g. return NULL after a python function fails).
Fix a filedescriptor that wasn't closed.
The braces lines 164 are on purpose to remove a gcc warning.

diff --git a/mercurial/osutil.c b/mercurial/osutil.c
--- a/mercurial/osutil.c
+++ b/mercurial/osutil.c
@@ -100,7 +100,7 @@
 			   int keep_stat, int *need_stat)
 {
 	struct dirent *ent;
-	PyObject *name, *py_kind, *val;
+	PyObject *name = NULL, *py_kind = NULL, *val = NULL;
 
 #ifdef DT_REG
 	*need_stat = 0;
@@ -130,22 +130,22 @@
 			}
 #endif
 
-		if (kind != -1)
+		if (kind != -1) {
 			py_kind = PyInt_FromLong(kind);
-		else {
+			if (!py_kind)
+				return NULL;
+		} else {
 			py_kind = Py_None;
 			Py_INCREF(Py_None);
 		}
 
+		name = PyString_FromString(ent->d_name);
+		if (!name)
+			goto fail;
+
 		val = PyTuple_New(keep_stat ? 3 : 2);
-		name = PyString_FromString(ent->d_name);
-
-		if (!name || !py_kind || !val) {
-			Py_XDECREF(name);
-			Py_XDECREF(py_kind);
-			Py_XDECREF(val);
-			return PyErr_NoMemory();
-		}
+		if (!val)
+			goto fail;
 
 		PyTuple_SET_ITEM(val, 0, name);
 		PyTuple_SET_ITEM(val, 1, py_kind);
@@ -154,11 +154,18 @@
 			Py_INCREF(Py_None);
 		}
 
-		PyList_Append(list, val);
+		if (PyList_Append(list, val) == -1)
+			goto fail_val;
 		Py_DECREF(val);
 	}
 
-	return 0;
+	return list;
+fail:
+	Py_XDECREF(name);
+	Py_XDECREF(py_kind);
+fail_val:
+	Py_XDECREF(val);
+	return NULL;
 }
 
 static PyObject *statfiles(PyObject *list, PyObject *ctor_args, int keep,
@@ -172,23 +179,28 @@
 	ssize_t size = PyList_Size(list);
 
 	for (i = 0; i < size; i++) {
-		PyObject *elt = PyList_GetItem(list, i);
-		char *name = PyString_AsString(PyTuple_GET_ITEM(elt, 0));
-		PyObject *py_st = NULL;
-		PyObject *py_kind = PyTuple_GET_ITEM(elt, 1);
+		PyObject *elt, *py_kind;
+		char *name;
+			
+		elt = PyList_GetItem(list, i);
+		if (!elt)
+			return NULL;
+		name = PyString_AsString(PyTuple_GET_ITEM(elt, 0));
+		if (!name)
+			return NULL;
+		py_kind = PyTuple_GET_ITEM(elt, 1);
 
-		kind = py_kind == Py_None ? -1 : PyInt_AsLong(py_kind);
-		if (kind != -1 && !keep)
+		if (!keep && py_kind != Py_None)
 			continue;
 
 		strncpy(path + len + 1, name, PATH_MAX - len);
 		path[PATH_MAX] = 0;
 
 		if (keep) {
-			py_st = PyObject_CallObject(
-				(PyObject *)&listdir_stat_type, ctor_args);
+			PyObject *py_st = PyObject_CallObject(
+					(PyObject *)&listdir_stat_type, ctor_args);
 			if (!py_st)
-				return PyErr_NoMemory();
+				return NULL;
 			stp = &((struct listdir_stat *)py_st)->st;
 			PyTuple_SET_ITEM(elt, 2, py_st);
 		}
@@ -202,7 +214,7 @@
 			return PyErr_SetFromErrnoWithFilename(PyExc_OSError,
 							      path);
 
-		if (kind == -1) {
+		if (py_kind == Py_None) {
 			if (S_ISREG(stp->st_mode))
 				kind = S_IFREG;
 			else if (S_ISDIR(stp->st_mode))
@@ -219,18 +231,22 @@
 				kind = S_IFSOCK;
 			else
 				kind = stp->st_mode;
+		} else {
+			kind = PyInt_AsLong(py_kind);
+			if (kind == -1 && PyErr_Occurred())
+				return NULL;
 		}
 
 		if (py_kind == Py_None && kind != -1) {
 			py_kind = PyInt_FromLong(kind);
 			if (!py_kind)
-				return PyErr_NoMemory();
+				return NULL;
 			Py_XDECREF(Py_None);
 			PyTuple_SET_ITEM(elt, 1, py_kind);
 		}
 	}
 
-	return 0;
+	return list;
 }
 
 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
@@ -239,13 +255,13 @@
 	DIR *dir = NULL;
 	PyObject *statobj = NULL;
 	PyObject *list = NULL;
-	PyObject *err = NULL;
+	PyObject *ret = NULL;
 	PyObject *ctor_args = NULL;
 	char *path;
 	char full_path[PATH_MAX + 10];
 	int path_len;
 	int need_stat, keep_stat;
-	int dfd;
+	int dfd = -1;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist,
 					 &path, &path_len, &statobj))
@@ -262,7 +278,7 @@
 	dfd = -1;
 #endif
 	if (!dir) {
-		err = PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
+		PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
 		goto bail;
 	}
 
@@ -274,27 +290,31 @@
 	strncpy(full_path, path, PATH_MAX);
 	full_path[path_len] = '/';
 
-	err = listfiles(list, dir, keep_stat, &need_stat);
-	if (err)
+	ret = listfiles(list, dir, keep_stat, &need_stat);
+	if (!ret)
 		goto bail;
 
-	PyList_Sort(list);
+	if (PyList_Sort(list) == -1)
+		goto bail;
 
 	if (!keep_stat && !need_stat)
 		goto done;
 
-	err = statfiles(list, ctor_args, keep_stat, full_path, path_len, dfd);
-	if (!err)
+	ret = statfiles(list, ctor_args, keep_stat, full_path, path_len, dfd);
+	if (ret)
 		goto done;
 
  bail:
+	ret = NULL;
 	Py_XDECREF(list);
 
  done:
 	Py_XDECREF(ctor_args);
 	if (dir)
 		closedir(dir);
-	return err ? err : list;
+	if (dfd != -1)
+		close(dfd);
+	return ret;
 }
 
 

-- 
:wq


More information about the Mercurial-devel mailing list