Skip to content

Commit

Permalink
Revamp how we check for the correct class. (#218)
Browse files Browse the repository at this point in the history
* Revamp how we check for the correct class.

In an issue it was pointed out that we are decref'ing
before we actually use some of the data, which means that
in theory the garbage collector could reclaim the data
before we used it.  So the original point of this change
was to fix that issue.

However, while looking at it I realized we could slightly
improve performance here by avoiding a copy of the class
and module into a combined string.  Instead, we can compare
them separately, which should reduce the copies.

* Fix a warning when building in Release mode.

Since the variables are only used in an assert, which
can be compiled out, this could lead to a warning.
Inline the call instead, which should get rid of the warning.

Signed-off-by: Chris Lalancette <[email protected]>
  • Loading branch information
clalancette authored Oct 8, 2024
1 parent acf97aa commit 7077033
Showing 1 changed file with 24 additions and 28 deletions.
52 changes: 24 additions & 28 deletions rosidl_generator_py/resource/_msg_support.c.em
Original file line number Diff line number Diff line change
Expand Up @@ -158,41 +158,37 @@ PyObject * @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_unde

@{
module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_path.stem)
class_module = '%s.%s' % ('.'.join(message.structure.namespaced_type.namespaces), module_name)
namespaced_type = message.structure.namespaced_type.name
}@
ROSIDL_GENERATOR_C_EXPORT
bool @('__'.join(message.structure.namespaced_type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message)
{
@{
full_classname = '%s.%s.%s' % ('.'.join(message.structure.namespaced_type.namespaces), module_name, message.structure.namespaced_type.name)
}@
// check that the passed message is of the expected Python class
{
char full_classname_dest[@(len(full_classname) + 1)];
{
char * class_name = NULL;
char * module_name = NULL;
{
PyObject * class_attr = PyObject_GetAttrString(_pymsg, "__class__");
if (class_attr) {
PyObject * name_attr = PyObject_GetAttrString(class_attr, "__name__");
if (name_attr) {
class_name = (char *)PyUnicode_1BYTE_DATA(name_attr);
Py_DECREF(name_attr);
}
PyObject * module_attr = PyObject_GetAttrString(class_attr, "__module__");
if (module_attr) {
module_name = (char *)PyUnicode_1BYTE_DATA(module_attr);
Py_DECREF(module_attr);
}
Py_DECREF(class_attr);
}
}
if (!class_name || !module_name) {
return false;
}
snprintf(full_classname_dest, sizeof(full_classname_dest), "%s.%s", module_name, class_name);
PyObject * class_attr = PyObject_GetAttrString(_pymsg, "__class__");
if (class_attr == NULL) {
return false;
}
PyObject * name_attr = PyObject_GetAttrString(class_attr, "__name__");
if (name_attr == NULL) {
Py_DECREF(class_attr);
return false;
}
assert(strncmp("@(full_classname)", full_classname_dest, @(len(full_classname))) == 0);
PyObject * module_attr = PyObject_GetAttrString(class_attr, "__module__");
if (module_attr == NULL) {
Py_DECREF(name_attr);
Py_DECREF(class_attr);
return false;
}

// PyUnicode_1BYTE_DATA is just a cast
assert(strncmp("@(class_module)", (char *)PyUnicode_1BYTE_DATA(module_attr), @(len(class_module))) == 0);
assert(strncmp("@(namespaced_type)", (char *)PyUnicode_1BYTE_DATA(name_attr), @(len(namespaced_type))) == 0);

Py_DECREF(module_attr);
Py_DECREF(name_attr);
Py_DECREF(class_attr);
}
@(msg_typename) * ros_message = _ros_message;
@[for member in message.structure.members]@
Expand Down

0 comments on commit 7077033

Please sign in to comment.