summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2010-02-11 19:15:37 +0000
committerAmaury Pouly <pamaury@rockbox.org>2010-02-11 19:15:37 +0000
commite5caf93e237a168f923a2eeb7bccaae9b9a51c30 (patch)
tree465678c398f728181f1749ffb2c872f954798462
parent552a54d87ffceb20eff1b206832cd10ad3677a24 (diff)
downloadrockbox-e5caf93e237a168f923a2eeb7bccaae9b9a51c30.tar.gz
rockbox-e5caf93e237a168f923a2eeb7bccaae9b9a51c30.tar.bz2
rockbox-e5caf93e237a168f923a2eeb7bccaae9b9a51c30.zip
Commit FS#10889: detect file handles leaks in plugins and automatically close them on exit and warn the user.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24598 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugin.c84
-rw-r--r--firmware/export/config.h6
2 files changed, 89 insertions, 1 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index a1ffa3abe1..0d4d8ed0f6 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -63,6 +63,15 @@
#define PREFIX
#endif
+#if defined(HAVE_PLUGIN_CHECK_OPEN_CLOSE) && (MAX_OPEN_FILES>32)
+#warning "MAX_OPEN_FILES>32, disabling plugin file open/close checking"
+#undef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+#endif
+
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+static unsigned int open_files;
+#endif
+
#ifdef SIMULATOR
static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
void *sim_plugin_load(char *plugin, void **pd);
@@ -83,6 +92,13 @@ static char current_plugin[MAX_PATH];
char *plugin_get_current_filename(void);
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+/* Some wrappers used to monitor open and close and detect leaks*/
+static int open_wrapper(const char* pathname, int flags);
+static int close_wrapper(int fd);
+static int creat_wrapper(const char *pathname);
+#endif
+
static const struct plugin_api rockbox_api = {
/* lcd */
@@ -276,11 +292,20 @@ static const struct plugin_api rockbox_api = {
#endif /* HAVE_BUTTON_LIGHT */
/* file */
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+ (open_func)open_wrapper,
+ close_wrapper,
+#else
(open_func)PREFIX(open),
PREFIX(close),
+ #endif
(read_func)PREFIX(read),
PREFIX(lseek),
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+ (creat_func)creat_wrapper,
+#else
(creat_func)PREFIX(creat),
+#endif
(write_func)PREFIX(write),
PREFIX(remove),
PREFIX(rename),
@@ -805,8 +830,12 @@ int plugin_load(const char* plugin, const void* parameter)
touchscreen_set_mode(TOUCHSCREEN_BUTTON);
#endif
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+ open_files = 0;
+#endif
+
rc = hdr->entry_point(parameter);
-
+
/* Go back to the global setting in case the plugin changed it */
#ifdef HAVE_TOUCHSCREEN
touchscreen_set_mode(global_settings.touch_mode);
@@ -850,6 +879,25 @@ int plugin_load(const char* plugin, const void* parameter)
if (pfn_tsr_exit == NULL)
plugin_loaded = false;
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+ if(open_files != 0 && !plugin_loaded)
+ {
+ int fd;
+ logf("Plugin '%s' leaks file handles", plugin);
+
+ static const char *lines[] =
+ { ID2P(LANG_PLUGIN_ERROR),
+ "#leak-file-handles" };
+ static const struct text_message message={ lines, 2 };
+ button_clear_queue(); /* Empty the keyboard buffer */
+ gui_syncyesno_run(&message, NULL, NULL);
+
+ for(fd=0; fd < MAX_OPEN_FILES; fd++)
+ if(open_files & (1<<fd))
+ close_wrapper(fd);
+ }
+#endif
+
sim_plugin_close(pd);
if (rc == PLUGIN_ERROR)
@@ -926,3 +974,37 @@ char *plugin_get_current_filename(void)
{
return current_plugin;
}
+
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+static int open_wrapper(const char* pathname, int flags)
+{
+ int fd = PREFIX(open)(pathname,flags);
+
+ if(fd >= 0)
+ open_files |= 1<<fd;
+
+ return fd;
+}
+
+static int close_wrapper(int fd)
+{
+ if((~open_files) & (1<<fd))
+ {
+ logf("double close from plugin");
+ }
+ if(fd >= 0)
+ open_files &= (~(1<<fd));
+
+ return PREFIX(close)(fd);
+}
+
+static int creat_wrapper(const char *pathname)
+{
+ int fd = PREFIX(creat)(pathname);
+
+ if(fd >= 0)
+ open_files |= (1<<fd);
+
+ return fd;
+}
+#endif /* HAVE_PLUGIN_CHECK_OPEN_CLOSE */
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 516161191b..994397e595 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -908,5 +908,11 @@ Lyre prototype 1 */
#define STORAGE_ALIGN_MASK 0
#endif
+/* This attribute can be used to enable to detection of plugin file handles leaks.
+ * When enabled, the plugin core will monitor open/close/creat and when the plugin exits
+ * will display an error message if the plugin leaked some file handles */
+#ifndef SIMULATOR
+#define HAVE_PLUGIN_CHECK_OPEN_CLOSE
+#endif
#endif /* __CONFIG_H__ */