Skip to content

Conversation

@zhexuany
Copy link
Contributor

@zhexuany zhexuany commented Feb 1, 2026

Problem

The previous fix (d198484) changed from decode_ros1 to decode_headerless to avoid skipping 16 bytes of message data. However, decode_headerless sets is_ros1=false, which causes the decoder to use ROS2-style alignment for primitive arrays.

This caused decoding failures for ROS1 BAG files with messages containing primitive arrays (e.g., kuavo_msgs/sensorsData), resulting in errors like:

Array length 756369941 exceeds maximum allowed 10000000

Root Cause

The is_ros1 flag controls alignment behavior for primitive arrays:

  • ROS2: Primitive array elements are aligned to their size
  • ROS1: Primitive array elements are stored contiguously without alignment

When is_ros1=false, the decoder applies ROS2-style alignment, which causes it to read garbage values as array lengths when processing ROS1 BAG data.

Solution

Added a new decode_headerless_ros1 function that:

  • Starts from byte 0 (no header skip)
  • Uses ROS1 alignment rules (is_ros1=true)

This ensures primitive arrays are decoded correctly for ROS1 BAG messages.

Changes

  • Added CdrCursor::new_headerless_ros1() - creates cursor with is_ros1=true
  • Added CdrDecoder::decode_headerless_ros1() - uses ROS1 alignment for decoding
  • Updated BagDecodedMessageStream to use decode_headerless_ros1()

Testing

Tested with Leju robot BAG file (Rubbish_sorting_P4-278_20250830101814.bag) which contains ~487K messages with complex nested types including primitive arrays.

Fixes #26

The previous fix (d198484) changed from decode_ros1 to decode_headerless
to avoid skipping 16 bytes of message data. However, decode_headerless
sets is_ros1=false, which causes the decoder to use ROS2-style alignment
for primitive arrays.

This caused decoding failures for ROS1 BAG files with messages containing
primitive arrays (e.g., kuavo_msgs/sensorsData), resulting in errors like:
"Array length 756369941 exceeds maximum allowed 10000000"

The fix adds a new decode_headerless_ros1 function that:
- Starts from byte 0 (no header skip)
- Uses ROS1 alignment rules (is_ros1=true)

This ensures primitive arrays are decoded correctly for ROS1 BAG messages.

Fixes #26
@codecov
Copy link

codecov bot commented Feb 1, 2026

Codecov Report

❌ Patch coverage is 90.41096% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/bin/cmd/rewrite.rs 82.92% 7 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps
Copy link

greptile-apps bot commented Feb 1, 2026

Greptile Overview

Greptile Summary

This PR correctly fixes ROS1 BAG message decoding by introducing a new decode_headerless_ros1() function that uses ROS1 alignment rules for primitive arrays.

Key Changes:

  • Added CdrCursor::new_headerless_ros1() that sets is_ros1=true
  • Added CdrDecoder::decode_headerless_ros1() that uses the new cursor constructor
  • Updated BagDecodedMessageStream to call decode_headerless_ros1() instead of decode_headerless()

Technical Context:
The previous fix (PR #27) changed from decode_ros1 to decode_headerless to avoid skipping 16 bytes of message data. However, decode_headerless defaulted to is_ros1=false, causing the decoder to apply ROS2-style alignment where primitive array elements are aligned to their size. ROS1 stores primitive array elements contiguously without alignment, so applying ROS2 alignment caused misalignment and resulted in reading garbage values as array lengths.

The Fix:
By setting is_ros1=true, the decoder skips the alignment step for primitive arrays (line 751 in decoder.rs), ensuring elements are read contiguously as ROS1 expects.

Confidence Score: 5/5

  • This PR is safe to merge - it's a targeted fix for a specific alignment issue
  • The implementation correctly addresses the root cause by adding a dedicated function for ROS1 headerless decoding. The changes are minimal, well-documented, and follow the existing pattern. The fix has been tested with real BAG files containing ~487K messages.
  • No files require special attention

Important Files Changed

Filename Overview
src/encoding/cdr/cursor.rs added new_headerless_ros1() constructor with is_ros1=true flag for ROS1 alignment
src/encoding/cdr/decoder.rs added decode_headerless_ros1() method that creates cursor with ROS1 alignment flag
src/io/formats/bag/parallel.rs updated to call decode_headerless_ros1() instead of decode_headerless() for correct alignment

Sequence Diagram

sequenceDiagram
    participant BAG as BagDecodedMessageStream
    participant DEC as CdrDecoder
    participant CUR as CdrCursor
    
    Note over BAG,CUR: ROS1 BAG Message Decoding Flow
    
    BAG->>BAG: next() - get raw message
    Note over BAG: BAG parser extracts CDR data<br/>(no headers, just message bytes)
    
    BAG->>DEC: decode_headerless_ros1(schema, data, type)
    Note over DEC: Use ROS1 alignment rules
    
    DEC->>CUR: new_headerless_ros1(data, little_endian=true)
    Note over CUR: Create cursor with:<br/>- offset=0, origin=0<br/>- is_ros1=true
    
    CUR-->>DEC: cursor
    
    DEC->>DEC: execute_plan(plan, cursor, schema)
    
    loop For each primitive array
        DEC->>DEC: read_array(cursor, element_type, count)
        
        alt is_ros1 == true
            Note over DEC,CUR: ROS1: Skip alignment<br/>(contiguous storage)
            DEC->>CUR: read elements without alignment
        else is_ros1 == false
            Note over DEC,CUR: ROS2: Apply alignment<br/>(aligned to element size)
            DEC->>CUR: align(elem_size)
            DEC->>CUR: read elements with alignment
        end
    end
    
    DEC-->>BAG: DecodedMessage
    
    Note over BAG,CUR: Key Fix: is_ros1=true prevents<br/>incorrect ROS2 alignment in<br/>ROS1 primitive arrays
Loading

…vior

- Rename \`convert\` command to \`rewrite\` to clarify it doesn't change formats
- Simplify CLI interface: \`rewrite <input> <output>\` (no subcommands)
- Keep cross-format protection with helpful error message

The \`convert to-mcap\` and \`convert to-bag\` commands were misleading as
they suggested format conversion capability that doesn't exist. The
new \`rewrite\` command accurately describes what it does: rewrites a
file in the same format.

Fixes #33
Since cursor.align() already handles the ROS1 check internally,
the wrapper checks in execute_plan(), read_time(), and read_duration()
were redundant. Removed them for cleaner, more maintainable code.
- Remove unused parse_schema and FormatReader imports
- Use for loop instead of while let on iterator
@zhexuany zhexuany merged commit a949f36 into main Feb 1, 2026
14 checks passed
@zhexuany zhexuany deleted the fix/bag-decode-ros1-alignment branch February 8, 2026 17:53
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.

Bag decoder fails to handle corrupted messages with invalid array lengths

1 participant