Skip to content

diagnostic_updater 4.2.7 breaks ABI within Jazzy #663

Description

@BrianSidebotham

Summary

diagnostic_updater 4.2.7 changed the signature of the exported Updater constructor within the Jazzy distribution, released as a patch bump over 4.2.6. Any downstream shared object compiled against 4.2.6 fails at load time with undefined symbol after a routine apt upgrade pulls in ros-jazzy-diagnostic-updater 4.2.7. Because the change shipped as a patch release with no changelog entry, there was no signal to downstream packagers that a rebuild was required.

The change

#354 ("Add starting_up_state parameter to Updater") appends a trailing defaulted parameter to both Updater constructors and adds a new private member:

Updater(
  std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> base_interface,
  /* ... five more interface params ... */
  double period = 1.0,
  unsigned char starting_up_status = diagnostic_msgs::msg::DiagnosticStatus::OK);  // new
...
private:
  ...
  unsigned char starting_up_status_;  // new

It was auto-backported to ros2-jazzy by mergify as #584 (merged 2026-05-20) and released in 4.2.7 (2026-05-26). The same backport went to humble (#583) and kilted (#585), so those distro branches carry the same latent break.

The PR was assessed as non-breaking because the defaulted argument preserves source compatibility, but it is not binary compatible:

  1. The exported constructor symbol changed. The non-template Updater constructor is defined in diagnostic_updater.cpp and exported from libdiagnostic_updater.so. The trailing parameter changes the mangled name (the parameter list suffix moves from ...Ed to ...Edh), and no overload with the old signature was retained. Callers linked against 4.2.6 request a symbol 4.2.7 no longer exports.
  2. sizeof(Updater) changed. The new starting_up_status_ member grows the object, so any downstream code that embeds or derives from Updater has a stale layout even where linking succeeds.

Observable with:

$ nm -DC /opt/ros/jazzy/lib/libdiagnostic_updater.so | grep 'Updater::Updater'
# 4.2.6-1noble: ..., double)
# 4.2.7-1noble: ..., double, unsigned char)

Impact

We ship deployed robots (Ubuntu 24.04 / Jazzy) running composed containers whose components hold a diagnostic_updater::Updater. A routine apt upgrade moved ros-jazzy-diagnostic-updater from 4.2.6-1noble (built 2026-01) to 4.2.7-1noble (built 2026-06). Components built against 4.2.6 then fail at load with undefined symbol for the old constructor, which kills the composed container and takes unrelated components down with it.

There is also no clean rollback story: once some packages in an ecosystem are rebuilt against 4.2.7 and others remain on 4.2.6, no single installed version of diagnostic_updater satisfies both, and packages.ros.org only retains the newest build, so pinning back to 4.2.6 is fragile.

The 4.2.7 changelog for diagnostic_updater does not mention #354/#584 at all, so even a careful downstream reading the release notes would not have caught this.

Expected behaviour

Within a released, stable distribution, a patch-level bump of a binary-distributed C++ library should be ABI compatible — or the release should be versioned and documented so downstream consumers know a rebuild is required.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions