Skip to content

Avoid GCC 15 null-dereference warning in ThreadSafeSignal - #1287

Closed
nirwester wants to merge 1 commit into
BehaviorTree:masterfrom
nirwester:fix/gcc15-thread-safe-signal-warning
Closed

nirwester wants to merge 1 commit into
BehaviorTree:masterfrom
nirwester:fix/gcc15-thread-safe-signal-warning

Conversation

@nirwester

Copy link
Copy Markdown
Contributor

GCC 15 emits a (I think) false positive -Wnull-dereference when copying the subscriber vector in ThreadSafeSignal::notify(), breaking downstream builds that enable -Werror, including Nav2 (an example is here).

Copy-constructing the snapshot before moving it into the local vector should avoid the problematic assignment path. Locking, callback behavior, and API/ABI remain unchanged.

Validated with GCC 15.2 at -O2 and -O3, on existing callback and blackboard tests, and ASan/UBSan checks.
If I get a bit of time I can add a report for GCC too.

@facontidavide

Copy link
Copy Markdown
Collaborator

CI is unhappy

@nirwester

Copy link
Copy Markdown
Contributor Author

Seem race conditions unrelated from the change. According to Claudio (I didn't have time to try to follow the flow myself):

  1. The test signals startup too early. starts++ happens inside onStart(), before executeTick() publishes RUNNING. The main thread can halt the still-IDLE node, then the in-flight tick overwrites that halt with RUNNING. Forcing this ordering reproduces the failure consistently.
  2. The worker can restart an already halted tree. A diagnostic run captured:
    before_halt=RUNNING after_halt=IDLE at_timeout=RUNNING starts=2
    In tickRoot(), the halt check precedes the wake-up poll. A halt arriving between those operations can be consumed as an ordinary wake-up, causing another tick and restarting the root.
  3. The condition variable can miss a notification. WakeUpSignal::emitSignal() updates its predicate without holding the waiter’s mutex. Notification can arrive between the predicate check and entering the wait. I reproduced the waiter sleeping until its timeout despite receiving a signal; locking the producer’s predicate update prevented that failure.

I also tried to have him propose patches for these, but they looked quite invasive, and I don't want to PR AI rubbish :)

@SteveMacenski

Copy link
Copy Markdown
Contributor

BTW I filed a ticket this would resolve: #1288

facontidavide added a commit that referenced this pull request Nov 12, 2026
…error (#1290)

Downstream packages (Nav2, ROS Lyrical) compile our public headers with
-Werror; GCC 15 at -O2 reported -Wnull-dereference in ThreadSafeSignal::notify()
(false positive in vector<weak_ptr> copy-assignment) and in the JsonExporter
converters (unchecked *castPtr<T>(), now a LogicError instead of UB).

To keep this from regressing, the library and every in-tree consumer of its
headers now always build with -Wall -Wextra -Wpedantic -Wnull-dereference
-Werror (MSVC: /W4 /WX /permissive- /wd4702), and the GCC 15 ros2-lyrical job
builds in Release. Existing warnings across GCC 11/13/15, Clang, AppleClang and
MSVC are fixed.

Fixes #1288. Supersedes #1287.

Co-authored-by: Marco Matteo Bassa <bassamarco91@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@facontidavide

Copy link
Copy Markdown
Collaborator

fixed slightly differently, thanks

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