[gnome-shell] Close file descriptors on re-exec



commit 56644dfada06ae515057ff793d1a7402edf59931
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Tue Apr 21 17:21:06 2009 -0400

    Close file descriptors on re-exec
    
    Use code copied from GLib to close all file descriptors before we reexec ourselves
    on the restart Alt-F2 command. This fixes serious memory leaks when we have mapped
    graphics buffers.
    
    http://bugzilla.gnome.org/show_bug.cgi?id=579776
---
 configure.ac       |    3 ++
 src/shell-global.c |  103 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 104 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index e3da44d..0c52b68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,6 +60,9 @@ GJS_JS_NATIVE_DIR=`$PKG_CONFIG --variable=jsnativedir gjs-1.0`
 AC_SUBST(GJS_JS_DIR)
 AC_SUBST(GJS_JS_NATIVE_DIR)
 
+AC_CHECK_FUNCS(fdwalk)
+AC_CHECK_HEADERS([sys/resource.h])
+
 # Sets GLIB_GENMARSHAL and GLIB_MKENUMS
 AM_PATH_GLIB_2_0()
 G_IR_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
diff --git a/src/shell-global.c b/src/shell-global.c
index 2a2b747..c01dd51 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -7,10 +7,12 @@
 #include <clutter/glx/clutter-glx.h>
 #include <clutter/x11/clutter-x11.h>
 #include <gdk/gdkx.h>
-#include <unistd.h>
+#include <dirent.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <dbus/dbus-glib.h>
 #include <libgnomeui/gnome-thumbnail.h>
 
@@ -592,6 +594,95 @@ shell_global_ungrab_keyboard (ShellGlobal *global)
   global->keyboard_grabbed = FALSE;
 }
 
+/* Code to close all file descriptors before we exec; copied from gspawn.c in GLib.
+ *
+ * Authors: Padraig O'Briain, Matthias Clasen, Lennart Poettering
+ *
+ * http://bugzilla.gnome.org/show_bug.cgi?id=469231
+ * http://bugzilla.gnome.org/show_bug.cgi?id=357585
+ */
+
+static int
+set_cloexec (void *data, gint fd)
+{
+  if (fd >= GPOINTER_TO_INT (data))
+    fcntl (fd, F_SETFD, FD_CLOEXEC);
+
+  return 0;
+}
+
+#ifndef HAVE_FDWALK
+static int
+fdwalk (int (*cb)(void *data, int fd), void *data)
+{
+  gint open_max;
+  gint fd;
+  gint res = 0;
+
+#ifdef HAVE_SYS_RESOURCE_H
+  struct rlimit rl;
+#endif
+
+#ifdef __linux__
+  DIR *d;
+
+  if ((d = opendir("/proc/self/fd"))) {
+      struct dirent *de;
+
+      while ((de = readdir(d))) {
+          glong l;
+          gchar *e = NULL;
+
+          if (de->d_name[0] == '.')
+              continue;
+
+          errno = 0;
+          l = strtol(de->d_name, &e, 10);
+          if (errno != 0 || !e || *e)
+              continue;
+
+          fd = (gint) l;
+
+          if ((glong) fd != l)
+              continue;
+
+          if (fd == dirfd(d))
+              continue;
+
+          if ((res = cb (data, fd)) != 0)
+              break;
+        }
+
+      closedir(d);
+      return res;
+  }
+
+  /* If /proc is not mounted or not accessible we fall back to the old
+   * rlimit trick */
+
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+  if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
+      open_max = rl.rlim_max;
+  else
+#endif
+      open_max = sysconf (_SC_OPEN_MAX);
+
+  for (fd = 0; fd < open_max; fd++)
+      if ((res = cb (data, fd)) != 0)
+          break;
+
+  return res;
+}
+#endif
+
+static void
+pre_exec_close_fds(void)
+{
+  fdwalk (set_cloexec, GINT_TO_POINTER(3));
+}
+
 /**
  * shell_global_reexec_self:
  * @global: A #ShellGlobal
@@ -621,7 +712,15 @@ shell_global_reexec_self (ShellGlobal *global)
   for (buf_p = buf; buf_p < buf_end; buf_p = buf_p + strlen (buf_p) + 1)
     g_ptr_array_add (arr, buf_p);
   
-  g_ptr_array_add (arr, NULL); 
+  g_ptr_array_add (arr, NULL);
+
+  /* Close all file descriptors other than stdin/stdout/stderr, otherwise
+   * they will leak and stay open after the exec. In particular, this is
+   * important for file descriptors that represent mapped graphics buffer
+   * objects.
+   */
+  pre_exec_close_fds ();
+
   execvp (arr->pdata[0], (char**)arr->pdata);
   g_warning ("failed to reexec: %s", g_strerror (errno));
   g_ptr_array_free (arr, TRUE);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]