Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes memory leaks for nested fields #7

Merged
merged 2 commits into from
Jul 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rosidl_generator_py/resource/_msg.py.em
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import traceback
class Metaclass(type):
"""Metaclass of message '@(spec.base_type.type)'."""

_CREATE_ROS_MESSAGE = None
_CONVERT_FROM_PY = None
_CONVERT_TO_PY = None
_DESTROY_ROS_MESSAGE = None
Expand All @@ -42,6 +43,7 @@ class Metaclass(type):
logger.debug(
'Failed to import needed modules for type support:\n' + traceback.format_exc())
else:
cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg_@(module_name)
cls._CONVERT_FROM_PY = module.convert_from_py_msg_@(module_name)
cls._CONVERT_TO_PY = module.convert_to_py_msg_@(module_name)
cls._TYPE_SUPPORT = module.type_support_msg_@(module_name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
@#######################################################################
@
#include <Python.h>
#include <stdbool.h>
#include <stdint.h>

@{
Expand Down Expand Up @@ -55,8 +56,9 @@ for spec, subfolder in service_specs:
type_name = spec.base_type.type
module_name = convert_camel_case_to_lower_case_underscore(type_name)
}@
void * @(spec.base_type.pkg_name)_@(module_name)__convert_from_py(PyObject * _pymsg);
void * @(spec.base_type.pkg_name)_@(module_name)__create_ros_message(void);
void @(spec.base_type.pkg_name)_@(module_name)__destroy_ros_message(void * raw_ros_message);
bool @(spec.base_type.pkg_name)_@(module_name)__convert_from_py(PyObject * _pymsg, void * ros_message);
PyObject * @(spec.base_type.pkg_name)_@(module_name)__convert_to_py(void * raw_ros_message);
@[end for]@

Expand All @@ -79,7 +81,7 @@ static struct PyModuleDef @(package_name)__module = {
@[for spec, subfolder in message_specs]@
@{
type_name = convert_camel_case_to_lower_case_underscore(spec.base_type.type)
function_names = ['convert_from_py', 'destroy_ros_message', 'convert_to_py', 'type_support']
function_names = ['create_ros_message', 'destroy_ros_message', 'convert_from_py', 'convert_to_py', 'type_support']
}@

ROSIDL_GENERATOR_C_IMPORT
Expand Down
58 changes: 30 additions & 28 deletions rosidl_generator_py/resource/_msg_support.c.em
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@#######################################################################
@
#include <Python.h>
#include <stdbool.h>

#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__struct.h>
#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__functions.h>
Expand Down Expand Up @@ -52,7 +53,7 @@ if not field.type.is_primitive_type() and field.type.is_array:
msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type)
}@

void * @(spec.base_type.pkg_name)_@(module_name)__convert_from_py(PyObject * _pymsg)
bool @(spec.base_type.pkg_name)_@(module_name)__convert_from_py(PyObject * _pymsg, void * _ros_message)
{
@{
full_classname = '%s.%s._%s.%s' % (spec.base_type.pkg_name, subfolder, module_name, spec.base_type.type)
Expand Down Expand Up @@ -80,130 +81,126 @@ full_classname = '%s.%s._%s.%s' % (spec.base_type.pkg_name, subfolder, module_na
}
}
if (!class_name || !module_name) {
return NULL;
return false;
}
snprintf(full_classname_dest, sizeof(full_classname_dest), "%s.%s", module_name, class_name);
}
assert(strncmp(
"@(full_classname)",
full_classname_dest, @(len(full_classname))) == 0);
}
@(msg_typename) * ros_message = @(msg_typename)__create();
@(msg_typename) * ros_message = _ros_message;
@[if not spec.fields]@
(void)ros_message;
@[end if]@
@[for field in spec.fields]@
{ // @(field.name)
PyObject * field = PyObject_GetAttrString(_pymsg, "@(field.name)");
if (!field) {
return NULL;
return false;
}
@[ if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
typedef PyObject *(* convert_from_py_signature)(void *);
typedef bool (* convert_from_py_signature)(PyObject *, void *);
convert_from_py_signature convert_from_py = NULL;
// get conversion function
{
PyObject * msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
if (!msg_module) {
Py_DECREF(field);
return NULL;
return false;
}
PyObject * msg_class = PyObject_GetAttrString(msg_module, "@(field.type.type)");
Py_DECREF(msg_module);
if (!msg_class) {
Py_DECREF(field);
return NULL;
return false;
}
PyObject * msg_metaclass = PyObject_GetAttrString(msg_class, "__class__");
Py_DECREF(msg_class);
if (!msg_metaclass) {
Py_DECREF(field);
return NULL;
return false;
}
PyObject * convert_from_py_ = PyObject_GetAttrString(msg_metaclass, "_CONVERT_FROM_PY");
Py_DECREF(msg_metaclass);
if (!convert_from_py_) {
Py_DECREF(field);
return NULL;
return false;
}
convert_from_py = (convert_from_py_signature)PyCapsule_GetPointer(convert_from_py_, NULL);
Py_DECREF(convert_from_py_);
if (!convert_from_py) {
Py_DECREF(field);
return NULL;
return false;
}
}
@[ if field.type.is_array]@
PyObject * seq_field = PySequence_Fast(field, "expected a sequence in '@(field.name)'");
if (!seq_field) {
Py_DECREF(field);
return NULL;
return false;
}
@[ if field.type.array_size is None or field.type.is_upper_bound]@
Py_ssize_t size = PySequence_Size(field);
if (-1 == size) {
Py_DECREF(seq_field);
Py_DECREF(field);
return NULL;
return false;
}
if (!@(nested_type)__Array__init(&(ros_message->@(field.name)), size)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still wrapping my head around the message generation code. What checks that ros_message is not NULL before this point?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In current code caller checks in _rclpy.c after it allocated it with create_ros_message. I can add explicit check here, but current code already was not checking any other arguments like _pymsg or raw_ros_message, so I did not add any extra checks for this new argument.

PyErr_SetString(PyExc_RuntimeError, "unable to create @(nested_type)__Array ros_message");
Py_DECREF(seq_field);
Py_DECREF(field);
return NULL;
return false;
}
@(nested_type) * dest = ros_message->@(field.name).data;
@[ else]@
Py_ssize_t size = @(field.type.array_size);
@(nested_type) * dest = ros_message->@(field.name);
@[ end if]@
for (Py_ssize_t i = 0; i < size; ++i) {
@(nested_type) * item = (@(nested_type) *) convert_from_py(
PySequence_Fast_GET_ITEM(seq_field, i));
if (!item) {
if (!convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) {
Py_DECREF(seq_field);
Py_DECREF(field);
return NULL;
return false;
}
memcpy(&dest[i], item, sizeof(@(nested_type)));
}
Py_DECREF(seq_field);
@[ else]@
@(nested_type) * tmp = (@(nested_type) *) convert_from_py(field);
if (!tmp) {
return NULL;
if (!convert_from_py(field, &ros_message->@(field.name))) {
Py_DECREF(field);
return false;
}
ros_message->@(field.name) = *tmp;
@[ end if]@
@[ elif field.type.is_array]@
PyObject * seq_field = PySequence_Fast(field, "expected a sequence in '@(field.name)'");
if (!seq_field) {
Py_DECREF(field);
return NULL;
return false;
}
@[ if field.type.array_size is None or field.type.is_upper_bound]@
Py_ssize_t size = PySequence_Size(field);
if (-1 == size) {
Py_DECREF(seq_field);
Py_DECREF(field);
return NULL;
return false;
}
@[ if field.type.type == 'string']@
if (!rosidl_generator_c__String__Array__init(&(ros_message->@(field.name)), size)) {
PyErr_SetString(PyExc_RuntimeError, "unable to create String__Array ros_message");
Py_DECREF(seq_field);
Py_DECREF(field);
return NULL;
return false;
}
@[ else]@
if (!rosidl_generator_c__@(field.type.type)__Array__init(&(ros_message->@(field.name)), size)) {
PyErr_SetString(PyExc_RuntimeError, "unable to create @(field.type.type)__Array ros_message");
Py_DECREF(seq_field);
Py_DECREF(field);
return NULL;
return false;
}
@[ end if]@
@primitive_msg_type_to_c(field.type.type) * dest = ros_message->@(field.name).data;
Expand All @@ -216,7 +213,7 @@ nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
if (!item) {
Py_DECREF(seq_field);
Py_DECREF(field);
return NULL;
return false;
}
@[ if field.type.type == 'char']@
assert(PyUnicode_Check(item));
Expand Down Expand Up @@ -317,7 +314,12 @@ nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}
@[end for]@

return ros_message;
return true;
}

void * @(spec.base_type.pkg_name)_@(module_name)__create_ros_message(void)
{
return @(msg_typename)__create();
}

void @(spec.base_type.pkg_name)_@(module_name)__destroy_ros_message(void * raw_ros_message)
Expand Down