From: Aman Gupta <themastermind1@gmail.com>
To: archer@sourceware.org
Subject: [patch] fixing leaking struct value* in py-value.c
Date: Thu, 10 Dec 2009 23:16:00 -0000 [thread overview]
Message-ID: <e1c05edd0912101515v41e2fd54l75287580989710a2@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 6128 bytes --]
Bug: http://sourceware.org/bugzilla/show_bug.cgi?id=10896
Given:
$ cat simple.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
struct blah {
char test[2];
int i;
float none;
} *list_of_blahs;
int main(){
list_of_blahs = malloc(sizeof(struct blah) * 2000000);
printf("pid: %d\n", getpid());
while(1){
sleep(1);
}
}
$ cat simple.py
gdb.execute('p list_of_blahs')
list = gdb.history(0)
end = list + 1000000
while list < end:
list['i']
list += 1
$ ./simple &
[1] 16572
$ gdb -ex 'py execfile("./simple.py")' ./simple 16572
The gdb process will leak a large amount of memory (>512mb RSS) while
executing the python loop. Some (but not all) of this memory is
returned after the loop completes and free_all_values() is called for
the next command. The following patch against archer-tromey-python
keeps the memory usage constant during the loop.
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 14efd79..f305b01 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -143,7 +143,7 @@ valpy_new (PyTypeObject *subtype, PyObject *args,
PyObject *keywords)
}
value_obj->value = value;
- value_incref (value);
+ release_value_or_incref (value);
value_obj->address = NULL;
value_obj->type = NULL;
note_value (value_obj);
@@ -267,6 +267,7 @@ valpy_cast (PyObject *self, PyObject *args)
{
PyObject *type_obj;
struct type *type;
+ PyObject *res_obj = NULL;
struct value *res_val = NULL; /* Initialize to appease gcc warning. */
volatile struct gdb_exception except;
@@ -305,8 +306,10 @@ valpy_getitem (PyObject *self, PyObject *key)
{
value_object *self_value = (value_object *) self;
char *field = NULL;
+ PyObject *res_obj = NULL;
struct value *res_val = NULL;
volatile struct gdb_exception except;
+ struct value *mark = value_mark ();
if (gdbpy_is_string (key))
{
@@ -344,9 +347,13 @@ valpy_getitem (PyObject *self, PyObject *key)
}
xfree (field);
- GDB_PY_HANDLE_EXCEPTION (except);
+ GDB_PY_HANDLE_EXCEPTION_AND_CLEANUP (except, mark);
+
+ if (res_val)
+ res_obj = value_to_value_object (res_val);
- return res_val ? value_to_value_object (res_val) : NULL;
+ value_free_to_mark (mark);
+ return res_obj;
}
static int
@@ -427,8 +434,10 @@ enum valpy_opcode
static PyObject *
valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
{
+ PyObject *res_obj = NULL;
struct value *res_val = NULL; /* Initialize to appease gcc warning. */
volatile struct gdb_exception except;
+ struct value *mark = value_mark ();
TRY_CATCH (except, RETURN_MASK_ALL)
{
@@ -519,9 +528,13 @@ valpy_binop (enum valpy_opcode opcode, PyObject
*self, PyObject *other)
break;
}
}
- GDB_PY_HANDLE_EXCEPTION (except);
+ GDB_PY_HANDLE_EXCEPTION_AND_CLEANUP (except, mark);
+
+ if (res_val)
+ res_obj = value_to_value_object (res_val);
- return res_val ? value_to_value_object (res_val) : NULL;
+ value_free_to_mark (mark);
+ return res_obj;
}
static PyObject *
@@ -684,6 +697,7 @@ valpy_richcompare (PyObject *self, PyObject *other, int op)
int result = 0;
struct value *value_other;
volatile struct gdb_exception except;
+ struct value *mark = value_mark ();
if (other == Py_None)
/* Comparing with None is special. From what I can tell, in Python
@@ -742,6 +756,7 @@ valpy_richcompare (PyObject *self, PyObject *other, int op)
break;
}
}
+ value_free_to_mark (mark);
GDB_PY_HANDLE_EXCEPTION (except);
/* In this case, the Python exception has already been set. */
@@ -851,7 +866,7 @@ value_to_value_object (struct value *val)
if (val_obj != NULL)
{
val_obj->value = val;
- value_incref (val);
+ release_value_or_incref (val);
val_obj->address = NULL;
val_obj->type = NULL;
note_value (val_obj);
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 47662d9..309ee5b 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -149,11 +149,17 @@ PyObject *gdbpy_parameter_value (enum var_types, void *);
/* Use this after a TRY_EXCEPT to throw the appropriate Python
exception. */
#define GDB_PY_HANDLE_EXCEPTION(Exception) \
+ GDB_PY_HANDLE_EXCEPTION_AND_CLEANUP(Exception, NULL)
+
+#define GDB_PY_HANDLE_EXCEPTION_AND_CLEANUP(Exception, mark) \
do { \
- if (Exception.reason < 0) \
+ if (Exception.reason < 0) { \
+ if (mark) \
+ value_free_to_mark (mark); \
return PyErr_Format (Exception.reason == RETURN_QUIT \
? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \
"%s", Exception.message); \
+ } \
} while (0)
/* Use this after a TRY_EXCEPT to throw the appropriate Python
diff --git a/gdb/value.c b/gdb/value.c
index 2f31185..9187a7f 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -691,7 +691,7 @@ free_all_values (void)
/* Remove VAL from the chain all_values
so it will not be freed automatically. */
-void
+int
release_value (struct value *val)
{
struct value *v;
@@ -699,7 +699,7 @@ release_value (struct value *val)
if (all_values == val)
{
all_values = val->next;
- return;
+ return 1;
}
for (v = all_values; v; v = v->next)
@@ -707,9 +707,21 @@ release_value (struct value *val)
if (v->next == val)
{
v->next = val->next;
- break;
+ return 1;
}
}
+
+ return 0;
+}
+
+/* Release VAL or increment its reference count if
+ it was released already */
+
+void
+release_value_or_incref (struct value *val)
+{
+ if (release_value (val) == 0)
+ value_incref (val);
}
/* Release all values up to mark */
diff --git a/gdb/value.h b/gdb/value.h
index 0da7031..5705210 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -595,7 +595,9 @@ extern void value_free (struct value *val);
extern void free_all_values (void);
-extern void release_value (struct value *val);
+extern int release_value (struct value *val);
+
+extern void release_value_or_incref (struct value *val);
extern int record_latest_value (struct value *val);
[-- Attachment #2: gdb-python-leak.patch --]
[-- Type: application/octet-stream, Size: 5266 bytes --]
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 14efd79..f305b01 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -143,7 +143,7 @@ valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *keywords)
}
value_obj->value = value;
- value_incref (value);
+ release_value_or_incref (value);
value_obj->address = NULL;
value_obj->type = NULL;
note_value (value_obj);
@@ -267,6 +267,7 @@ valpy_cast (PyObject *self, PyObject *args)
{
PyObject *type_obj;
struct type *type;
+ PyObject *res_obj = NULL;
struct value *res_val = NULL; /* Initialize to appease gcc warning. */
volatile struct gdb_exception except;
@@ -305,8 +306,10 @@ valpy_getitem (PyObject *self, PyObject *key)
{
value_object *self_value = (value_object *) self;
char *field = NULL;
+ PyObject *res_obj = NULL;
struct value *res_val = NULL;
volatile struct gdb_exception except;
+ struct value *mark = value_mark ();
if (gdbpy_is_string (key))
{
@@ -344,9 +347,13 @@ valpy_getitem (PyObject *self, PyObject *key)
}
xfree (field);
- GDB_PY_HANDLE_EXCEPTION (except);
+ GDB_PY_HANDLE_EXCEPTION_AND_CLEANUP (except, mark);
+
+ if (res_val)
+ res_obj = value_to_value_object (res_val);
- return res_val ? value_to_value_object (res_val) : NULL;
+ value_free_to_mark (mark);
+ return res_obj;
}
static int
@@ -427,8 +434,10 @@ enum valpy_opcode
static PyObject *
valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
{
+ PyObject *res_obj = NULL;
struct value *res_val = NULL; /* Initialize to appease gcc warning. */
volatile struct gdb_exception except;
+ struct value *mark = value_mark ();
TRY_CATCH (except, RETURN_MASK_ALL)
{
@@ -519,9 +528,13 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
break;
}
}
- GDB_PY_HANDLE_EXCEPTION (except);
+ GDB_PY_HANDLE_EXCEPTION_AND_CLEANUP (except, mark);
+
+ if (res_val)
+ res_obj = value_to_value_object (res_val);
- return res_val ? value_to_value_object (res_val) : NULL;
+ value_free_to_mark (mark);
+ return res_obj;
}
static PyObject *
@@ -684,6 +697,7 @@ valpy_richcompare (PyObject *self, PyObject *other, int op)
int result = 0;
struct value *value_other;
volatile struct gdb_exception except;
+ struct value *mark = value_mark ();
if (other == Py_None)
/* Comparing with None is special. From what I can tell, in Python
@@ -742,6 +756,7 @@ valpy_richcompare (PyObject *self, PyObject *other, int op)
break;
}
}
+ value_free_to_mark (mark);
GDB_PY_HANDLE_EXCEPTION (except);
/* In this case, the Python exception has already been set. */
@@ -851,7 +866,7 @@ value_to_value_object (struct value *val)
if (val_obj != NULL)
{
val_obj->value = val;
- value_incref (val);
+ release_value_or_incref (val);
val_obj->address = NULL;
val_obj->type = NULL;
note_value (val_obj);
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 47662d9..309ee5b 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -149,11 +149,17 @@ PyObject *gdbpy_parameter_value (enum var_types, void *);
/* Use this after a TRY_EXCEPT to throw the appropriate Python
exception. */
#define GDB_PY_HANDLE_EXCEPTION(Exception) \
+ GDB_PY_HANDLE_EXCEPTION_AND_CLEANUP(Exception, NULL)
+
+#define GDB_PY_HANDLE_EXCEPTION_AND_CLEANUP(Exception, mark) \
do { \
- if (Exception.reason < 0) \
+ if (Exception.reason < 0) { \
+ if (mark) \
+ value_free_to_mark (mark); \
return PyErr_Format (Exception.reason == RETURN_QUIT \
? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \
"%s", Exception.message); \
+ } \
} while (0)
/* Use this after a TRY_EXCEPT to throw the appropriate Python
diff --git a/gdb/value.c b/gdb/value.c
index 2f31185..9187a7f 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -691,7 +691,7 @@ free_all_values (void)
/* Remove VAL from the chain all_values
so it will not be freed automatically. */
-void
+int
release_value (struct value *val)
{
struct value *v;
@@ -699,7 +699,7 @@ release_value (struct value *val)
if (all_values == val)
{
all_values = val->next;
- return;
+ return 1;
}
for (v = all_values; v; v = v->next)
@@ -707,9 +707,21 @@ release_value (struct value *val)
if (v->next == val)
{
v->next = val->next;
- break;
+ return 1;
}
}
+
+ return 0;
+}
+
+/* Release VAL or increment its reference count if
+ it was released already */
+
+void
+release_value_or_incref (struct value *val)
+{
+ if (release_value (val) == 0)
+ value_incref (val);
}
/* Release all values up to mark */
diff --git a/gdb/value.h b/gdb/value.h
index 0da7031..5705210 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -595,7 +595,9 @@ extern void value_free (struct value *val);
extern void free_all_values (void);
-extern void release_value (struct value *val);
+extern int release_value (struct value *val);
+
+extern void release_value_or_incref (struct value *val);
extern int record_latest_value (struct value *val);
next reply other threads:[~2009-12-10 23:16 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-12-10 23:16 Aman Gupta [this message]
2010-01-12 11:22 ` Phil Muldoon
[not found] ` <AANLkTi=qwg88TbawxPcKSk+iMZwz9aB_L3oqyaEe32Yc@mail.gmail.com>
2010-11-04 19:43 ` Aman Gupta
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e1c05edd0912101515v41e2fd54l75287580989710a2@mail.gmail.com \
--to=themastermind1@gmail.com \
--cc=archer@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).