Skip to content

Address annotation gaps found by concurrency analysis#5151

Open
marta-lokhova wants to merge 2 commits intostellar:masterfrom
marta-lokhova:staticThreadSafety
Open

Address annotation gaps found by concurrency analysis#5151
marta-lokhova wants to merge 2 commits intostellar:masterfrom
marta-lokhova:staticThreadSafety

Conversation

@marta-lokhova
Copy link
Contributor

@marta-lokhova marta-lokhova commented Feb 20, 2026

No description provided.

Copilot AI review requested due to automatic review settings February 20, 2026 19:36
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses concurrency analysis gaps by adding thread safety annotations to various classes. The changes convert standard library mutex types to custom wrapper types that support Clang's thread safety analysis, add GUARDED_BY annotations to protected fields, and replace standard lock guards with macro-based equivalents that work with the thread safety analysis framework.

Changes:

  • Convert mutexes in VirtualClock, ProcessManagerImpl, and LiveBucketIndex to thread-safety-annotated wrapper types (Mutex, RecursiveMutex, SharedMutex)
  • Add GUARDED_BY annotations to fields protected by these mutexes
  • Replace std::lock_guard usages with LOCK_GUARD/RECURSIVE_LOCK_GUARD macros
  • Document lock ordering between Peer::mStateMutex and Hmac::mMutex using ACQUIRED_BEFORE annotation
  • Add thread assertion to LedgerManagerImpl::isApplying()

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/util/Timer.h Convert VirtualClock mutexes to Mutex type and add GUARDED_BY annotations
src/util/Timer.cpp Replace std::lock_guard with LOCK_GUARD macro
src/process/ProcessManagerImpl.h Convert mProcessesMutex to RecursiveMutex and add GUARDED_BY annotations
src/process/ProcessManagerImpl.cpp Replace std::lock_guard with RECURSIVE_LOCK_GUARD macro
src/overlay/Peer.h Add ACQUIRED_BEFORE annotation to document lock ordering with Hmac::mMutex
src/overlay/Hmac.h Expose mMutex as public under THREAD_SAFETY and add GUARDED_BY to fields
src/overlay/Hmac.cpp Add LOCK_GUARD to damageRecvMacKey test method
src/ledger/LedgerManagerImpl.h Add thread assertion to isApplying() getter
src/bucket/LiveBucketIndex.h Convert mCacheMutex to SharedMutex and add GUARDED_BY annotation
src/bucket/LiveBucketIndex.cpp Replace std::shared_lock/std::unique_lock with SharedLockShared/SharedLockExclusive

Copy link
Contributor

@SirTyson SirTyson left a comment

Choose a reason for hiding this comment

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

LGTM, but I think while we're here we can add much better tracy visibility into our locks.

@marta-lokhova marta-lokhova force-pushed the staticThreadSafety branch 3 times, most recently from 397bf2e to f448eb2 Compare March 4, 2026 13:51
AC_MSG_NOTICE([enabling thread safety static analysis, see https://clang.llvm.org/docs/ThreadSafetyAnalysis.html])
AS_CASE(["$CXX"],
[clang*], [CXXFLAGS="$CXXFLAGS -Wthread-safety -Werror=thread-safety -DTHREAD_SAFETY"],
[clang*], [CXXFLAGS="$CXXFLAGS -Wthread-safety -Werror=thread-safety -Wthread-safety-beta -Werror=thread-safety-beta -DTHREAD_SAFETY"],
Copy link
Contributor Author

@marta-lokhova marta-lokhova Mar 4, 2026

Choose a reason for hiding this comment

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

A slightly annoying discovery - some features like ACQUIRED_BEFORE/ACQUIRED_AFTER are not actually implemented in clang20 (as per llvm/llvm-project#51788). These are implemented in thread-safety-beta though, and newer clang versions properly promote them stable (see llvm/llvm-project#152853). Either way, I think it doesn't hurt to enable thread-safety-beta for more coverage.

Copy link
Contributor

@SirTyson SirTyson left a comment

Choose a reason for hiding this comment

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

LGTM overall! I think if we generate tracy graphs that are too large, we can do a followup where we narrow down our uses of the macro. Imo tracy graphs are already huge and I'd rather have larger traces with full visibility instead of having blind spots when possible. It's a micro-benchmarking tool anyway, so I think we should avoid optimizing for size/noise unless it's really necessary.

Couple small nits, and the macro accidentally upgraded some pre-existing mutexes to mutable. Probably not a big deal, but we can be a little more conservative.

// The annotations parameter can be empty or contain one or more annotations.
#ifndef USE_TRACY
#define ANNOTATED_MUTEX(VarName, ...) \
Mutex mutable VarName ANNOTATE_FOR_THREAD_SAFETY(__VA_ARGS__)
Copy link
Contributor

Choose a reason for hiding this comment

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

ProcessManagerImpl::mProcessesMutex was not mutable, but now is. Can we drop the mutable from the macro so we can maintain both mutable ANNOTATED_MUTEX and ANNOTATED_MUTEX? In practice it's probably fine for mutexes to always be mutable, but this is "downgrading" mutexes that were previously not mutable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ya I think it's harmless, but don't feel strongly

// https://clang.llvm.org/docs/ThreadSafetyAnalysis.html

#ifndef THREAD_ANNOTATIONS_H_
#define THREAD_ANNOTATIONS_H_
Copy link
Contributor

Choose a reason for hiding this comment

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

Get rid of THREAD_ANNOTATIONS_H_ since we already have #pragma once

Mutex mMutex;
#else
TracyLockable(std::mutex, mMutex);
#ifdef THREAD_SAFETY
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: This friend declaration is not intuitive, a short comment would be nice.

// When Tracy is enabled, we use TracyLockable for profiling visibility.
// Note: We still provide a wrapper class for consistency with non-Tracy builds.
// Users should access the underlying TracyLockable directly for profiling.
class Mutex : public stellar::NonMovableOrCopyable
Copy link
Contributor

Choose a reason for hiding this comment

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

This is now dead code since we have the maco. We never use the Mutex type when tracy is enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, see the comment - support is added for completeness (I don't mind removing it though if you feel strongly)

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.

3 participants