Skip to content

Conversation

@squizz617
Copy link
Contributor

@squizz617 squizz617 commented Mar 9, 2021

This pull request fixes the issue described below:
Floating-point types of different precision (float32/float64 in ROS, float/double in rclcpp and DDS), are not handled properly in rclpy (and corresponding rosidl_python intefaces), as the type checks rely solely on Python's built-in float type.

For example, when publishing a double-sized floating point value (e.g., 3.5e+100) as float32 type, the data goes through various type checks at different places:

  1. if type(3.5e+100) is float in rosidl_runtime_py/set_message.py,
  2. assert(isinstance(3.5e+100, float)) in the msg setter code automatically generated by rosidl,
    and these checks don't reject this value as 3.5e+100 is of float type in Python, even though it is too big for a 32-bit float.

Then, when converting this message to a C-compatible raw message before actually publishing the data, rosidl-generated conversion code casts the value to float, where it becomes inf:

// in build/proj_name/rosidl_generator_py/proj_name/msg/_type_name_s.c
ros_message->first = (float)PyFloat_AS_DOUBLE(field);

As a result, the receiving end (subscriber) receives inf.

To fix this issue, I suggest having rosidl's generator code emit boundary checks for float/double type variables, like what's done for integer types.

Copy link
Contributor

@clalancette clalancette left a comment

Choose a reason for hiding this comment

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

Could you please add some tests for these cases?

@squizz617
Copy link
Contributor Author

@clalancette Added tests for float/double boundaries in test/test_interfaces.py and pushed. Could you have a look?

@clalancette
Copy link
Contributor

It looks like the new tests are failing in CI, can you take a look?

@squizz617
Copy link
Contributor Author

I missed adding boundary checks for array members. Updated and passed CI tests.

@clalancette clalancette self-assigned this Apr 1, 2021
Copy link
Contributor

@clalancette clalancette left a comment

Choose a reason for hiding this comment

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

Sorry for the long delay on this. I've rebased it, and added one bugfix (to print out the bounds properly). So this is looking good to me; I'll run CI on it next.

I'm just slightly worried about this change, as it is a change in behavior. Code that used to be able to publish very large floats before will throw an exception that they never threw before. This seems OK to me, as they were publishing unexpected data, but I'd still like to get a second opinion on this before I merge it. @sloretz, what do you think?

@clalancette
Copy link
Contributor

CI:

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@oysstu
Copy link
Contributor

oysstu commented Jul 11, 2022

Please have a look at the discussion in #167. IEEE 754 mandates that a floating point number exceeding the bounds should be converted to an inf. I'm of the opinion that the behavior in python should mirror that of C/C++ if possible. At the very least I think that NaN and perhaps also Inf should pass through the bounds check without raising exceptions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants