Skip to content

Fix[bmqp::RequestManager]: unsafe read without mutex - #1713

Open
678098 wants to merge 3 commits into
bloomberg:mainfrom
678098:260814_bmqp_fixes
Open

Fix[bmqp::RequestManager]: unsafe read without mutex#1713
678098 wants to merge 3 commits into
bloomberg:mainfrom
678098:260814_bmqp_fixes

Conversation

@678098

@678098 678098 commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator
  • Remove reinterpret_cast
  • Add a UT to verify request cancellation order
  • Fix unsafe field access without mutex
  • Use vector, not the map, to iterate through the requests that has to be cancelled

678098 added 3 commits August 14, 2026 14:24
The justification to use reinterpret_cast used in bmqp::RequestManager
is incorrect now, possible to simplify and remove it.

Signed-off-by: Evgeny Malygin <emalygin@bloomberg.net>
bmqp::RequestManager docs mention invariant: all requests must be cancelled
in the same order as they recorded. This commit adds a test for it.

Signed-off-by: Evgeny Malygin <emalygin@bloomberg.net>
The existing code reads map bucket count without holding a mutex.
Other thread might cause rehashing as we are reading this value,
leading to UB.

Signed-off-by: Evgeny Malygin <emalygin@bloomberg.net>
@678098
678098 requested a review from a team as a code owner August 14, 2026 18:55
BSLA_MAYBE_UNUSED bsl::pair<RequestMapIter, bool>
insertRC = requestsCopy.insert(
bsl::make_pair(it->first, it->second));
BSLS_ASSERT_SAFE(insertRC.second);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We iterate through bmqc::OrderedHashMap so we have guarantee that keys in this map are unique. Due to this, insert return codes checks are redundant. Moreover, we don't need a second map here and can use a vector


// Create a new map so we can work on it outside the mutex
RequestMap requestsCopy(d_requests.bucket_count(),
d_requests.get_allocator());

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

d_requests.bucket_count() is not thread-safe: this call here was a bug

{
bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex); // MUTEX LOCKED

requestsCopy.reserve(d_requests.size());

@678098 678098 Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This reserve might over-reserve memory, if we are cancelling only a small part of all requests. This raises a question what is better: dynamic resizes or one resize for a possibly big chunk of memory.
I think one allocation is better here

@678098
678098 requested a review from hallfox August 14, 2026 19:00
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