diff options
Diffstat (limited to 'gdb/python/py-value.c')
-rw-r--r-- | gdb/python/py-value.c | 116 |
1 files changed, 69 insertions, 47 deletions
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index c843c2c..255a308 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -70,41 +70,64 @@ struct value_object { work around a linker bug on MacOS. */ static value_object *values_in_python = NULL; +/* Clear out an old GDB value stored within SELF, and reset the fields to + nullptr. This should be called when a gdb.Value is deallocated, and + also if a gdb.Value is reinitialized with a new value. */ + +static void +valpy_clear_value (value_object *self) +{ + /* Indicate we are no longer interested in the value object. */ + value_decref (self->value); + self->value = nullptr; + + Py_CLEAR (self->address); + Py_CLEAR (self->type); + Py_CLEAR (self->dynamic_type); +} + /* Called by the Python interpreter when deallocating a value object. */ static void valpy_dealloc (PyObject *obj) { value_object *self = (value_object *) obj; - /* Remove SELF from the global list. */ - if (self->prev) - self->prev->next = self->next; - else + /* If SELF failed to initialize correctly then it may not have a value + contained within it. */ + if (self->value != nullptr) { - gdb_assert (values_in_python == self); - values_in_python = self->next; - } - if (self->next) - self->next->prev = self->prev; - - value_decref (self->value); + /* Remove SELF from the global list of values. */ + if (self->prev != nullptr) + self->prev->next = self->next; + else + { + gdb_assert (values_in_python == self); + values_in_python = self->next; + } + if (self->next != nullptr) + self->next->prev = self->prev; - Py_XDECREF (self->address); - Py_XDECREF (self->type); - Py_XDECREF (self->dynamic_type); + /* Release the value object and any cached Python objects. */ + valpy_clear_value (self); + } Py_TYPE (self)->tp_free (self); } -/* Helper to push a Value object on the global list. */ +/* Helper to push a gdb.Value object on to the global list of values. If + VALUE_OBJ is already on the lit then this does nothing. */ + static void note_value (value_object *value_obj) { - value_obj->next = values_in_python; - if (value_obj->next) - value_obj->next->prev = value_obj; - value_obj->prev = NULL; - values_in_python = value_obj; + if (value_obj->next == nullptr) + { + gdb_assert (value_obj->prev == nullptr); + value_obj->next = values_in_python; + if (value_obj->next != nullptr) + value_obj->next->prev = value_obj; + values_in_python = value_obj; + } } /* Convert a python object OBJ with type TYPE to a gdb value. The @@ -142,60 +165,55 @@ convert_buffer_and_type_to_value (PyObject *obj, struct type *type) return value_from_contents (type, (const gdb_byte *) py_buf.buf); } -/* Called when a new gdb.Value object needs to be allocated. Returns NULL on - error, with a python exception set. */ -static PyObject * -valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) +/* Implement gdb.Value.__init__. */ + +static int +valpy_init (PyObject *self, PyObject *args, PyObject *kwds) { static const char *keywords[] = { "val", "type", NULL }; PyObject *val_obj = nullptr; PyObject *type_obj = nullptr; - if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "O|O", keywords, + if (!gdb_PyArg_ParseTupleAndKeywords (args, kwds, "O|O", keywords, &val_obj, &type_obj)) - return nullptr; + return -1; struct type *type = nullptr; - - if (type_obj != nullptr) + if (type_obj != nullptr && type_obj != Py_None) { type = type_object_to_type (type_obj); if (type == nullptr) { PyErr_SetString (PyExc_TypeError, _("type argument must be a gdb.Type.")); - return nullptr; + return -1; } } - value_object *value_obj = (value_object *) subtype->tp_alloc (subtype, 1); - if (value_obj == NULL) - { - PyErr_SetString (PyExc_MemoryError, _("Could not allocate memory to " - "create Value object.")); - return NULL; - } - struct value *value; - if (type == nullptr) value = convert_value_from_python (val_obj); else value = convert_buffer_and_type_to_value (val_obj, type); - if (value == nullptr) { - subtype->tp_free (value_obj); - return NULL; + gdb_assert (PyErr_Occurred ()); + return -1; } + /* There might be a previous value here. */ + value_object *value_obj = (value_object *) self; + if (value_obj->value != nullptr) + valpy_clear_value (value_obj); + + /* Store the value into this Python object. */ value_obj->value = release_value (value).release (); - value_obj->address = NULL; - value_obj->type = NULL; - value_obj->dynamic_type = NULL; + + /* Ensure that this gdb.Value is in the set of all gdb.Value objects. If + we are already in the set then this is call does nothing. */ note_value (value_obj); - return (PyObject *) value_obj; + return 0; } /* Iterate over all the Value objects, calling preserve_one_value on @@ -1784,6 +1802,8 @@ value_to_value_object (struct value *val) if (val_obj != NULL) { val_obj->value = release_value (val).release (); + val_obj->next = nullptr; + val_obj->prev = nullptr; val_obj->address = NULL; val_obj->type = NULL; val_obj->dynamic_type = NULL; @@ -1805,6 +1825,8 @@ value_to_value_object_no_release (struct value *val) { value_incref (val); val_obj->value = val; + val_obj->next = nullptr; + val_obj->prev = nullptr; val_obj->address = NULL; val_obj->type = NULL; val_obj->dynamic_type = NULL; @@ -2232,7 +2254,7 @@ PyTypeObject value_object_type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + valpy_init, /* tp_init */ 0, /* tp_alloc */ - valpy_new /* tp_new */ + PyType_GenericNew, /* tp_new */ }; |