lambdaprime / jros2client

Java module to interact with ROS2 (Robot Operating System)
5 stars 3 forks source link

Unable to deserialize empty string #9

Closed marlow-fawn closed 8 months ago

marlow-fawn commented 9 months ago

Hello! First of, wanted to say thanks for all your work on the project and for your responsiveness. I've got a bug as follows:

 java.lang.RuntimeException: Problem reading com.ros2.ros2jrosclient.generated.vision.Detection3DArrayMessage
...
Caused by: java.lang.StringIndexOutOfBoundsException: offset 0, count -1, length 0

It appears to be when reading in the id string field via DdsDataInput::readString, where readLen() is 0. There appears to be two issues here? 1 is that it should be able to handle an empty id, and the other is that in the actual message, the id isn't empty. Let me know if you need any more details

lambdaprime commented 9 months ago

Hi @marlow-fawn ,

Thanks for trying jrosclient

We could not reproduce the problem using SubscriberApp. With following command to publish empty string:

ros2 topic pub -r 10 helloRos std_msgs/String 'data: "" '

The result is :

{ "data": "" }
{ "data": "" }
{ "data": "" }
{ "data": "" }
{ "data": "" }

It means that problem possibly happens due to invalid message layout which leads to DdsDataInput::readString be called on a wrong offset.

Could you please:

Regards,

marlow-fawn commented 9 months ago

The message classes were generated by the newest version of msgmonster.

Here are the attached messages, with some slight simplifications to the file made during debugging (removing toString, hash, equals etc). Detection3DMessages.zip

Here's the stacktrace:

     [java] 10:42:25.924 [pool-4-thread-5] ERROR com.ros2.ros2jrosclient.JRosClientSubscriber -- Error in subscriber
     [java] java.lang.RuntimeException: Problem reading com.ros2.ros2jrosclient.generated.vision.Detection3DArrayMessage
     [java]     at id.jros2messages.MessageSerializationUtils.read(MessageSerializationUtils.java:76)
     [java]     at id.jros2client.impl.MessageUtils.lambda$deserializer$1(MessageUtils.java:52)
     [java]     at id.xfunction.concurrent.flow.TransformSubscriber.onNext(TransformSubscriber.java:61)
     [java]     at java.base/java.util.concurrent.SubmissionPublisher$BufferedSubscription.consumeNext(SubmissionPublisher.java:1354)
     [java]     at java.base/java.util.concurrent.SubmissionPublisher$BufferedSubscription.takeItems(SubmissionPublisher.java:1343)
     [java]     at java.base/java.util.concurrent.SubmissionPublisher$BufferedSubscription.consume(SubmissionPublisher.java:1300)
     [java]     at java.base/java.util.concurrent.SubmissionPublisher$ConsumerTask.run(SubmissionPublisher.java:978)
     [java]     at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
     [java]     at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
     [java]     at java.base/java.lang.Thread.run(Thread.java:840)
     [java] Caused by: java.lang.StringIndexOutOfBoundsException: offset 0, count -1, length 0
     [java]     at java.base/java.lang.String.checkBoundsOffCount(String.java:4591)
     [java]     at java.base/java.lang.String.<init>(String.java:523)
     [java]     at java.base/java.lang.String.<init>(String.java:1417)
     [java]     at id.jros2messages.impl.DdsDataInput.readString(DdsDataInput.java:62)
     [java]     at id.kineticstreamer.KineticStreamReader.read(KineticStreamReader.java:82)
     [java]     at id.kineticstreamer.KineticStreamReader.readComplexField(KineticStreamReader.java:133)
     [java]     at id.kineticstreamer.KineticStreamReader.read(KineticStreamReader.java:75)
     [java]     at id.kineticstreamer.KineticStreamReader.readInternal(KineticStreamReader.java:65)
     [java]     at id.kineticstreamer.KineticStreamReader.read(KineticStreamReader.java:57)
     [java]     at id.jros2messages.impl.DdsDataInput.readArray(DdsDataInput.java:103)
     [java]     at id.kineticstreamer.KineticStreamReader.readArray(KineticStreamReader.java:145)
     [java]     at id.kineticstreamer.KineticStreamReader.readComplexField(KineticStreamReader.java:126)
     [java]     at id.kineticstreamer.KineticStreamReader.read(KineticStreamReader.java:75)
     [java]     at id.kineticstreamer.KineticStreamReader.readInternal(KineticStreamReader.java:65)
     [java]     at id.kineticstreamer.KineticStreamReader.read(KineticStreamReader.java:57)
     [java]     at id.jros2messages.MessageSerializationUtils.read(MessageSerializationUtils.java:73)
     [java]     ... 9 common frames omitted
lambdaprime commented 9 months ago

Hi @marlow-fawn ,

We generated classes for vision_msgs attached above (they will be included into next version of jrosclient as well)

Please try to use them and see if it helps.

For testing we used following command to publish the messages

ros2 topic pub -r 10 helloRos vision_msgs/Detection3D '
header:
 stamp:
  sec: 123
  nanosec: 0
 frame_id: "frameid"
id: ""
'

As you mentioned we set id field to empty string. The jrosclient output is as expected:

{ "header": { "stamp": { "sec": "123", "nsec": "0" }, "frame_id": "frameid" }, "results": [], "bbox": { "center": { "position": { "x": 0, "y": 0, "z": 0 }, "orientation": { "x": 0, "y": 0, "z": 0, "w": 1 } }, "size": { "x": 0, "y": 0, "z": 0 } }, "id": { "data": "" } }
...
marlow-fawn commented 9 months ago

Same issue, unfortunately. Here's as far as the deserialization gets:

{
  "header": {
    "stamp": {
      "sec": "0",
      "nsec": "0"
    },
    "frame_id": ""
  },
  "results": [
    {
      "hypothesis": {
        "class_id": {
          "data": "europalette0"
        },
        "score": 1
      },
      "pose": {
        "pose": {
          "position": {
            "x": -4.9999998466,
            "y": 19.9999995203,
            "z": -0.000058045
          },
          "orientation": {
            "x": 1.43e-8,
            "y": 0.0000483708,
            "z": 6.265e-7,
            "w": 0.9999999988
          }
        },
        "covariance": "[]"
      }
    }
  ],
  "bbox": {
    "center": {
      "position": {
        "x": 0,
        "y": 0,
        "z": 0
      },
      "orientation": {
        "x": 0,
        "y": 0,
        "z": 0,
        "w": 0
      }
    },
    "size": {
      "x": 0,
      "y": 0,
      "z": 0
    }
  },
  "id": ""
}

And here's the original message:

- header:
    stamp:
      sec: 0
      nanosec: 0
    frame_id: ''
  results:
  - hypothesis:
      class_id: europalette0
      score: 1.0
    pose:
      pose:
        position:
          x: -4.9999998465703515
          y: 19.999999520345533
          z: -5.804495019624462e-05
        orientation:
          x: 1.4323905594057895e-08
          y: 4.837080148732906e-05
          z: 6.265022554075017e-07
          w: 0.9999999988299365
      covariance:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
  bbox:
    center:
      position:
        x: 0.0
        y: 0.0
        z: 0.072
      orientation:
        x: 0.0
        y: 0.0
        z: 0.0
        w: 1.0
    size:
      x: 1.2
      y: 0.8
      z: 0.144
  id: europalette0
lambdaprime commented 9 months ago

Hi @marlow-fawn ,

We could reproduce the problem and working on the fix

ETA is next week.

Regards,

lambdaprime commented 9 months ago

Hi @marlow-fawn ,

Please try new version:

dependencies {
  implementation 'io.github.lambdaprime:jros2client:5.0'
}

All vision_msgs are available now in jros2messages by default. Please use them instead of your own definitions.

Make sure to update msgmonster if you need to generate custom messages.

Regards,

marlow-fawn commented 8 months ago

Thanks for all your hard work! The good news is that it works - I'm successfully getting messages. Unfortunately, it is also throwing an error on every cycle.

This DOESN'T happen when creating a publisher node in the same process as the subscriber, so it doesn't seem to be an issue with the datatype any more. I can move this to another issue if you'd prefer.

     [java] Feb 01, 2024 12:51:52 PM pinorobotics.rtpstalk.impl.spec.userdata.DataReader#967576586-00000104
     [java] SEVERE: Cannot open connection to remote writer on { "transportType": "LOCATOR_KIND_INVALID", "port": "0", "address": "/0.0.0.0" }
     [java] java.lang.RuntimeException: Cannot open connection to remote writer on { "transportType": "LOCATOR_KIND_INVALID", "port": "0", "address": "/0.0.0.0" }
     [java]     at pinorobotics.rtpstalk.impl.spec.behavior.reader.WriterProxy.getDataChannel(WriterProxy.java:179)
     [java]     at pinorobotics.rtpstalk.impl.behavior.reader.WriterHeartbeatProcessor.lambda$ack$0(WriterHeartbeatProcessor.java:115)
     [java]     at java.base/java.util.Optional.ifPresent(Optional.java:178)
     [java]     at pinorobotics.rtpstalk.impl.behavior.reader.WriterHeartbeatProcessor.ack(WriterHeartbeatProcessor.java:115)
     [java]     at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
     [java]     at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
     [java]     at java.base/java.util.concurrent.ConcurrentHashMap$ValueSpliterator.forEachRemaining(ConcurrentHashMap.java:3612)
     [java]     at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
     [java]     at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
     [java]     at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
     [java]     at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
     [java]     at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
     [java]     at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
     [java]     at pinorobotics.rtpstalk.impl.spec.behavior.reader.StatefullReliableRtpsReader.process(StatefullReliableRtpsReader.java:221)
     [java]     at pinorobotics.rtpstalk.impl.spec.behavior.reader.RtpsReader.onNext(RtpsReader.java:241)
     [java]     at pinorobotics.rtpstalk.impl.spec.behavior.reader.RtpsReader.onNext(RtpsReader.java:80)
     [java]     at java.base/java.util.concurrent.SubmissionPublisher$BufferedSubscription.consumeNext(SubmissionPublisher.java:1354)
     [java]     at java.base/java.util.concurrent.SubmissionPublisher$BufferedSubscription.takeItems(SubmissionPublisher.java:1343)
     [java]     at java.base/java.util.concurrent.SubmissionPublisher$BufferedSubscription.consume(SubmissionPublisher.java:1300)
     [java]     at java.base/java.util.concurrent.SubmissionPublisher$ConsumerTask.run(SubmissionPublisher.java:978)
     [java]     at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
     [java]     at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
     [java]     at java.base/java.lang.Thread.run(Thread.java:840)
     [java] Caused by: java.net.SocketException: Can't connect to port 0
     [java]     at java.base/sun.nio.ch.DatagramChannelImpl.connect(DatagramChannelImpl.java:1239)
     [java]     at java.base/sun.nio.ch.DatagramChannelImpl.connect(DatagramChannelImpl.java:1207)
     [java]     at pinorobotics.rtpstalk.impl.spec.transport.DataChannelFactory.connect(DataChannelFactory.java:124)
     [java]     at pinorobotics.rtpstalk.impl.spec.behavior.reader.WriterProxy.getDataChannel(WriterProxy.java:177)
     [java]     ... 22 more
     [java] 
lambdaprime commented 8 months ago

Hi @marlow-fawn

Good to hear.

We moved it to separate issue #10 and will close this one