-
Notifications
You must be signed in to change notification settings - Fork 57
Description
I have found that Python generated code for message type conversion leaks a lot of memory. This happens inside convert_from_py functions for messages that have non-primitive types as fields. convert_from_py function is called both for every message that is sent and received (rclpy_publish and rclpy_take functions from _rclpy.c file).
For example, if message X contains "std_msgs/Header header" as field, the following fragment is generated in its X_convert_from_py function:
{ // header
...
... omitting irrelevant code to get convert_from_py function ...
...
std_msgs__msg__Header * tmp = (std_msgs__msg__Header *) convert_from_py(field);
if (!tmp) {
return NULL;
}
ros_message->header = *tmp;
Py_DECREF(field);
}
Nobody frees tmp pointer which is malloc'ed when calling convert_from_py function pointer (for header type).
The question is here is how to free tmp pointer?
-
it is wrong to
destroy_from_py(tmp)function before Py_DECREF, because caller of X_convert_from_py (like rclpy_publish from _rclpy.c) will call destroy_ros_message on object, and that will destroy ros_message->header members. Header contains String type which means string destroy function will be called twice and this will either crash program or corrupt memory. -
it is wrong to put just
free(tmp)there, because it won't release the objects inside tmp.
One potential solution would be to introduce new convert_from_py function for each type. Something like convert_from_py_internal.
Its signature would be: void convert_from_py_internal(PyObject* obj, void* msg);
Its purpose would be to not allocate any memory, but only assign necessary fields to existing message structure.
This way code snippet above would change to this:
{ // header
...
... omitting irrevant code to get convert_from_py_internal function ...
...
convert_from_py_internal(field, &ros_message->header);
Py_DECREF(field);
}
The callers (like rclpy_publish function in _rclpy) would still could call convert_from_py to get newly allocated C message structure, but internal conversions would happen directly on fields of already allocated message structures - no extra allocations, and no memory leaks.
What do you think about this? I can create pull request that implements this.
Let me know if you need more information on this.