Skip to content

concurrent accesses well-defined - #231

Merged
ahcorde merged 4 commits into
rollingfrom
ahcorde/rolling/data_race
Jul 9, 2026
Merged

ahcorde merged 4 commits into
rollingfrom
ahcorde/rolling/data_race

Conversation

@ahcorde

@ahcorde ahcorde commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

has_unmanaged_instance_been_created_ flag std::atomic to fix a real data race (unsynchronized read/write across per-loader mutexes) that could prematurely dlclose an in-use library.

@asymingt FYI

Claude Opus 4.7

ahcorde added 4 commits June 12, 2026 10:58
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
@ahcorde ahcorde self-assigned this Jun 12, 2026

@asymingt asymingt left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM

@mergify

mergify Bot commented Jun 26, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Base automatically changed from ahcorde/rolling/cpp20_part3 to rolling July 8, 2026 08:16
@ahcorde

ahcorde commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Pulls: #231
Gist: https://gist.githubusercontent.com/ahcorde/12466381bbadc43c0450fba81b1ab2f6/raw/9906b54e545df222ee88ade592c13db9bd368bb6/ros2.repos
BUILD args: --packages-above-and-dependencies class_loader
TEST args: --packages-above class_loader
ROS Distro: rolling
Job: ci_launcher
ci_launcher ran: https://ci.ros2.org/job/ci_launcher/19790

  • Linux Build Status
  • Linux-aarch64 Build Status
  • Linux-rhel Build Status
  • Windows Build Status

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I had no idea the if with initializer existed. TIL.

@asymingt asymingt left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM

@ahcorde
ahcorde merged commit ae7ea8a into rolling Jul 9, 2026
5 checks passed
@ahcorde
ahcorde deleted the ahcorde/rolling/data_race branch July 9, 2026 08:30
thomasmoore-torc added a commit to thomasmoore-torc/class_loader that referenced this pull request Sep 22, 2026
AbstractMetaObjectBase::addOwningClassLoader()/removeOwningClassLoader()/
isOwnedBy() (and the other accessors of associated_class_loaders_) took no
lock of their own. createInstance() in class_loader_core.hpp released
getPluginBaseToFactoryMapMapMutex() before reading factory->isOwnedBy(loader),
so a concurrent addOwningClassLoader()/removeOwningClassLoader() on another
thread (e.g. from loadLibrary()'s already-loaded branch, or from
onPluginDeletion()) could race with that read - and, since it's a std::vector,
with any other concurrent read/write of the same metaobject's owner list.

Reported by ThreadSanitizer as a data race on std::vector<ClassLoader *>'s
push_back()/erase() (via vector's internal reallocation), hit by constructing
many independent ClassLoader instances for the same library concurrently -
e.g. one rosbag2_cpp::Writer per thread, each internally constructing its own
pluginlib::ClassLoader for the serialization format converter.

Give AbstractMetaObjectBaseImpl its own recursive_mutex guarding
associated_class_loaders_, so every accessor is self-contained and safe
regardless of what lock (if any) the caller happens to be holding. Also
extend createInstance()'s existing getPluginBaseToFactoryMapMapMutex() scope
to cover the isOwnedBy() checks themselves, since between releasing that
mutex and reading isOwnedBy(), the factory pointer looked up under it could
in principle be invalidated by a concurrent destroyMetaObjectsForLibrary()
on another thread.

This is separate from ros#234 (loadLibrary()/unloadLibrary() overlap) and ros#231
(has_unmanaged_instance_been_created_): those fixed different unsynchronized
globals in this same area.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: thomasmoore-torc <thomas.moore@torc.ai>
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.

2 participants