Skip to content

Commit

Permalink
Memory leak in Python target fixed (#246)
Browse files Browse the repository at this point in the history
* memory leak fix

* Update core/lf_token.c

Co-authored-by: Edward A. Lee <eal@eecs.berkeley.edu>

* Update python_port.c

It was incorporated to assist with debugging.

* Update python/lib/python_port.c

Co-authored-by: Edward A. Lee <eal@eecs.berkeley.edu>

* Update python/lib/python_port.c

Co-authored-by: Edward A. Lee <eal@eecs.berkeley.edu>

* Update core/lf_token.c

Co-authored-by: Marten Lohstroh <marten@berkeley.edu>

* Update core/lf_token.c

Co-authored-by: Marten Lohstroh <marten@berkeley.edu>

* Update lf_token.c

* Update python_port.c

* Added back Py_INCREF(val) and define a new destructor for output port

* Add python count decrement to the header file

The function is called by the deserializer during federated execution.

* Fixed SegFault during unfederated execution

This commit fixes segfault for unfederated execution, but leads to memory leak during federated execution.

* Minor cleanup.

---------

Co-authored-by: Edward A. Lee <eal@eecs.berkeley.edu>
Co-authored-by: Marten Lohstroh <marten@berkeley.edu>
Co-authored-by: Peter Donovan <peterdonovan@berkeley.edu>
  • Loading branch information
4 people authored Jul 11, 2023
1 parent 9e9f427 commit 294fbb2
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 15 deletions.
17 changes: 9 additions & 8 deletions core/lf_token.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,24 @@ lf_token_t* lf_writable_copy(lf_port_base_t* port) {

////////////////////////////////////////////////////////////////////
//// Internal functions.

void _lf_free_token_value(lf_token_t* token) {
if (token->value != NULL) {
// Count frees to issue a warning if this is never freed.
_lf_count_payload_allocations--;
// Free the value field (the payload).
// First check whether the value field is garbage collected (e.g. in the
// Python target), in which case the payload should not be freed.
#ifndef _LF_GARBAGE_COLLECTED
LF_PRINT_DEBUG("_lf_free_token_value: Freeing allocated memory for payload (token value): %p",
token->value);
if (token->type->destructor == NULL) {
free(token->value);
} else {
token->value);
// First check the token's destructor field and invoke it if it is not NULL.
if (token->type->destructor != NULL) {
token->type->destructor(token->value);
}
// If Python Target is not enabled and destructor is NULL
// Token values should be freed
else {
#ifndef _PYTHON_TARGET_ENABLED
free(token->value);
#endif
}
token->value = NULL;
}
}
Expand Down
1 change: 1 addition & 0 deletions python/include/python_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,5 @@ typedef struct {
FEDERATED_CAPSULE_EXTENSION
} generic_port_capsule_struct;

void python_count_decrement(void* py_object);
#endif
28 changes: 21 additions & 7 deletions python/lib/python_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,21 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "python_port.h"
#include "reactor.h"
#include "api/api.h"
#include "api/set.h"

PyTypeObject py_port_capsule_t;

//////////// destructor Function(s) /////////////
/**
* Decrease the reference count of PyObject. When the reference count hits zero,
* Python can free its memory.
* @param py_object A PyObject with count 1 or greater.
*/
void python_count_decrement(void* py_object) {
Py_XDECREF((PyObject*)py_object);
}

//////////// set Function(s) /////////////
/**
* Set the value and is_present field of self which is of type
Expand Down Expand Up @@ -68,7 +80,7 @@ PyTypeObject py_port_capsule_t;
* @param args contains:
* - val: The value to insert into the port struct.
*/
PyObject* py_port_set(PyObject *self, PyObject *args) {
PyObject* py_port_set(PyObject* self, PyObject* args) {
generic_port_capsule_struct* p = (generic_port_capsule_struct*)self;
PyObject* val = NULL;

Expand All @@ -85,13 +97,15 @@ PyObject* py_port_set(PyObject *self, PyObject *args) {
}

if (val) {
LF_PRINT_DEBUG("Setting value %p.", val);
Py_XDECREF(port->value);
Py_INCREF(val);
// Call the core lib API to set the port
_LF_SET(port, val);

LF_PRINT_DEBUG("Setting value %p with reference count %d.", val, (int) Py_REFCNT(val));
//Py_INCREF(val);
//python_count_decrement(port->value);

lf_token_t* token = lf_new_token((void*)port, val, 1);
lf_set_destructor(port, python_count_decrement);
lf_set_token(port, token);
Py_INCREF(val);

// Also set the values for the port capsule.
p->value = val;
p->is_present = true;
Expand Down

0 comments on commit 294fbb2

Please # to comment.