summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2010-08-03 16:08:16 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2010-08-03 16:08:16 (GMT)
commit29b238e0dc8263d413d3b423260d18bdaacd8a3f (patch)
tree2afcbab5a02bf410d445df676c23c8cd861c6016
parent38557f2ac94a8d50c2d1ffd3e13d29e7ebeff141 (diff)
downloadcpython-29b238e0dc8263d413d3b423260d18bdaacd8a3f.zip
cpython-29b238e0dc8263d413d3b423260d18bdaacd8a3f.tar.gz
cpython-29b238e0dc8263d413d3b423260d18bdaacd8a3f.tar.bz2
Issue #9450: Fix memory leaks in readline.remove/replace_history_entry.
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/readline.c46
2 files changed, 37 insertions, 12 deletions
diff --git a/Misc/NEWS b/Misc/NEWS
index 3797380..9382011 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -21,6 +21,9 @@ Core and Builtins
Extensions
----------
+- Issue #9450: Fix memory leak in readline.replace_history_item and
+ readline.remove_history_item for readline version >= 5.0.
+
- Issue #8105: Validate file descriptor passed to mmap.mmap on Windows.
- Issue #8046: Add context manager protocol support and .closed property
diff --git a/Modules/readline.c b/Modules/readline.c
index 6567cc5..c8aac8c 100644
--- a/Modules/readline.c
+++ b/Modules/readline.c
@@ -378,6 +378,38 @@ PyDoc_STRVAR(doc_set_completer_delims,
"set_completer_delims(string) -> None\n\
set the readline word delimiters for tab-completion");
+/* _py_free_history_entry: Utility function to free a history entry. */
+
+#if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0500
+
+/* Readline version >= 5.0 introduced a timestamp field into the history entry
+ structure; this needs to be freed to avoid a memory leak. This version of
+ readline also introduced the handy 'free_history_entry' function, which
+ takes care of the timestamp. */
+
+static void
+_py_free_history_entry(HIST_ENTRY *entry)
+{
+ histdata_t data = free_history_entry(entry);
+ free(data);
+}
+
+#else
+
+/* No free_history_entry function; free everything manually. */
+
+static void
+_py_free_history_entry(HIST_ENTRY *entry)
+{
+ if (entry->line)
+ free((void *)entry->line);
+ if (entry->data)
+ free(entry->data);
+ free(entry);
+}
+
+#endif
+
static PyObject *
py_remove_history(PyObject *self, PyObject *args)
{
@@ -399,12 +431,7 @@ py_remove_history(PyObject *self, PyObject *args)
return NULL;
}
/* free memory allocated for the history entry */
- if (entry->line)
- free(entry->line);
- if (entry->data)
- free(entry->data);
- free(entry);
-
+ _py_free_history_entry(entry);
Py_RETURN_NONE;
}
@@ -436,12 +463,7 @@ py_replace_history(PyObject *self, PyObject *args)
return NULL;
}
/* free memory allocated for the old history entry */
- if (old_entry->line)
- free(old_entry->line);
- if (old_entry->data)
- free(old_entry->data);
- free(old_entry);
-
+ _py_free_history_entry(old_entry);
Py_RETURN_NONE;
}