ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Is it possible to receive messages on a topic which contain out-of-bound values in message fields?

asked 2018-06-01 13:30:53 -0500

thinwybk gravatar image

updated 2018-06-02 04:00:36 -0500

As far as I know it is not possible to publish out-of-bound values for message fields with ROS nodes/nodelets. E.g. the only possible publish-able range for uint8 message field values is in the range between 0 and 2^8-1. But is it possible to inject out-of-bound values in the full data range of the underlying data type of the ROS client implementation into a message published on a topic? That a subscriber (ROS Python client) to a topic would receive messages with e.g. a message field type of uint8 in the full range of integer data type. Or do clients silently validate and drop such messages if received?

edit retag flag offensive close merge delete

Comments

Just a pedantic nitpick, but the range for uint8 is actually 2^8 - 1 = 255, while 2*8 - 1 = 31. So, either this is a typo or if you're publishing values in the range [32, 255] you're actually still in range for uint8.

jayess gravatar image jayess  ( 2018-06-01 15:10:45 -0500 )edit

Right. Python 2**8-1. fixed

thinwybk gravatar image thinwybk  ( 2018-06-01 16:12:46 -0500 )edit

Another nitpick: are we mixing up the concepts "out of band messaging" and an "out of bounds" problem when representing a value? The former may be possible, depending on how strict you define it and map that to ROS infrastructure. The latter makes a little less sense to me in this context.

gvdhoorn gravatar image gvdhoorn  ( 2018-06-02 02:04:43 -0500 )edit

I am not sure if I understand "out of band messaging" in the ROS context. It is about message field values which are inside the range of the underlying Python data type (e.g. Python int) but outside the corresponding ROS data type (e.g. ROS uint8). (E.g. here int with wider value range as uint8).

thinwybk gravatar image thinwybk  ( 2018-06-02 03:52:21 -0500 )edit

Your question title says "receive messages [..] which are out-of-bound". That doesn't make sense to me. Fields could potentially have values in the serialised bytestream that are out-of-bounds for their specced types, but this statement cannot apply to complete messages ..

gvdhoorn gravatar image gvdhoorn  ( 2018-06-02 03:53:56 -0500 )edit

You are right. I adjusted the question accordingly. :) Sry for the confusion.

thinwybk gravatar image thinwybk  ( 2018-06-02 04:01:12 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted
2

answered 2018-06-02 01:57:26 -0500

gvdhoorn gravatar image

updated 2018-06-02 02:02:21 -0500

(this is more of an addition to @ahendrix's answer (but I didn't want to edit his))

See the (de)serialisation code for UInt8.msg for how this works in Python fi (taken from /opt/ros/kinetic/lib/python2.7/dist-packages/std_msgs/msg/_UInt8.py):

  def serialize(self, buff):
    """
    serialize message into buffer
    :param buff: buffer, ``StringIO``
    """
    try:
      buff.write(_get_struct_B().pack(self.data))
    except struct.error as se: self._check_types(struct.error("%s: '%s' when writing '%s'" % (type(se), str(se), str(locals().get('_x', self)))))
    except TypeError as te: self._check_types(ValueError("%s: '%s' when writing '%s'" % (type(te), str(te), str(locals().get('_x', self)))))

  def deserialize(self, str):
    """
    unpack serialized message in str into this message instance
    :param str: byte array of serialized message, ``str``
    """
    try:
      end = 0
      start = end
      end += 1
      (self.data,) = _get_struct_B().unpack(str[start:end])
      return self
    except struct.error as e:
      raise genpy.DeserializationError(e) #most likely buffer underfill

At least at this level (and this is the ony place message content is actually (de)serialised, called from here and here), values that are unrepresentable by the type that was specced for a field in a message will result in exceptions being thrown.

@ahendrix wrote:

I believe Python is using the struct library to pack objects into the serialization format, so you will get an exception if the value in that message field is outside of the allowed bounds.

Exactly: _get_struct_B() essentially just returns an instance of struct.Struct("B"):

def _get_struct_B():
    global _struct_B
    if _struct_B is None:
        _struct_B = struct.Struct("<B")
    return _struct_B

Note also the endianness specification there.

edit flag offensive delete link more

Comments

Thx. My question is about the deserialization part. Sry. I modified the question accordingly. About the background of the question: hypothesis-ros review issue 48

thinwybk gravatar image thinwybk  ( 2018-06-02 03:45:41 -0500 )edit

I'm confused: the code snippets I copied show both serialisation as well as deserialisation. The same comments apply to both of them.

gvdhoorn gravatar image gvdhoorn  ( 2018-06-02 03:47:29 -0500 )edit

Right now it is not clear to me if a topic subscriber implemented in Python could deserialize a message with a "hacked" message field of ROS uint8 which has a value in it which is > 2^8-1 (within the Python int value range). I could not find where the deserialize function validates this...

thinwybk gravatar image thinwybk  ( 2018-06-02 03:58:21 -0500 )edit
1

I could not find where the deserialize function validates this...

It doesn't. See the lines in deserialize(..). The only error that can occur is if there are not enough bytes for struct to unpack.

This is all the code there is (at least for Python).

gvdhoorn gravatar image gvdhoorn  ( 2018-06-02 04:01:19 -0500 )edit

@gvdhoorn Thx a lot. And sorry for the confusion until here :)

thinwybk gravatar image thinwybk  ( 2018-06-02 04:03:04 -0500 )edit
3

answered 2018-06-02 01:49:58 -0500

ahendrix gravatar image

The ROS serialization format only allocates enough bits for the advertised data size, so there cannot be out-of-range values in a serialized message.

I believe C++ will either give you a compiler warning or silently truncate your integers if you assign from a larger variable into a message field with less precision (this depends on your compiler and which warnings you have enabled).

I believe Python is using the struct library to pack objects into the serialization format, so you will get an exception if the value in that message field is outside of the allowed bounds.

edit flag offensive delete link more

Question Tools

2 followers

Stats

Asked: 2018-06-01 13:30:53 -0500

Seen: 431 times

Last updated: Jun 02 '18