Skip to content

Fix GCC 15 -Wnull-dereference in public headers; always build with -Werror - #1290

Merged
facontidavide merged 6 commits into
masterfrom
fix/werror-null-deref-1288
Nov 12, 2026
Merged

facontidavide merged 6 commits into
masterfrom
fix/werror-null-deref-1288

Conversation

@facontidavide

@facontidavide facontidavide commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1288. Supersedes #1287 (same ThreadSafeSignal fix, credited as co-author).

Problem

Downstream packages (Nav2, ROS Lyrical) compile our public headers with -Werror. With GCC 15 at -O2, -Wnull-dereference fires in:

  • utils/thread_safe_signal.h:52 (the reported error). This is a GCC false positive in std::vector<std::weak_ptr> copy-assignment.
  • json_export.h (not reported yet). *castPtr<T>() was dereferenced without a null check, and castPtr returns nullptr when the Any is empty or holds another type.

Our CI never caught it: the GCC 15 job (ros2-lyrical) builds without optimization, and tests/examples were never built with -Werror.

Fix

  • ThreadSafeSignal::notify() copy-constructs the subscriber snapshot instead of copy-assigning it.
  • The JSON converters go through a checked details::anyRef<T>(). Behavior change: an empty or mismatched Any now throws LogicError. Before, it was undefined behavior. A unit test covers the new branch.
  • The non-plugin BT_REGISTER_NODES is now [[maybe_unused]] static, and PLUGIN_SYMBOL is now inline constexpr.
  • contrib/expected.hpp: upstream's own C4702 suppression is extended to the && overloads of value().

Prevent regressions

  • The library and every in-tree consumer of its headers (sample_nodes, tests, tools, examples, fuzzers) now always build with:

    • GCC/Clang: -Wall -Wextra -Wpedantic -Wnull-dereference -Werror
    • MSVC: /W4 /WX /permissive- /wd4702. C4702 (unreachable code) is a code-generation warning that fires on instantiation-dependent if constexpr tails, and GCC/Clang -Wall -Wextra has no counterpart.

    Vendored 3rdparty code is not affected.

  • ros2-lyrical (GCC 15) now builds in Release, so -Wnull-dereference is active there.

  • Existing warnings in the library, tests, examples and fuzzers are fixed, mostly at the root:

    • a stray #pragma GCC diagnostic pop in xml_parsing.cpp;
    • narrowing conversions in the loggers and ConvertWithBoundCheck;
    • a potentially uninitialized timestamp in StatusChangeLogger;
    • unchecked get_if / dynamic_cast results in tests;
    • the deprecated TestNode constructor in gtest_parallel;
    • a GCC 13 -Wnull-dereference false positive in gtest_loggers.

    Discarded [[nodiscard]] results use std::ignore =.

No ABI change: only inline templates, a macro and a constant are touched in the headers.

Verified

  • Reverting only the thread_safe_signal.h fix reproduces the exact error from New BT.CPP Build Errors with -Werror #1288.
  • Locally: GCC 15 Release/Debug-coverage/ASan+UBSan, clang-21 Release and fuzzing, and a Lyrical colcon Release build.
  • CI: green on GCC 11/13/15, AppleClang and MSVC (conan and pixi).
  • Coveralls diff coverage is 100% (16/16). The -0.05% overall delta comes from lines this PR doesn't touch.

🤖 Generated with Claude Code

…1288)

Downstream packages (e.g. Nav2) compile BT.CPP headers with -Werror. GCC 15
at -O2 reports -Wnull-dereference in:

- ThreadSafeSignal::notify(): false positive in vector<weak_ptr>
  copy-assignment; copy-construct the snapshot instead.
- JsonExporter converters: *castPtr<T>() dereferenced without a null check;
  throw LogicError on an empty / mismatched Any instead of UB.

Also mark the static BT_RegisterNodesFromPlugin [[maybe_unused]] for
non-plugin builds.

To keep this from regressing, the library and every target that consumes its
headers (sample_nodes, tests, tools, examples, fuzzers) now always build with
-Wall -Wextra -Wpedantic -Wnull-dereference -Werror (MSVC: /W4 /WX
/permissive-). Vendored 3rdparty code is not affected. Fix the existing
warnings in tests, examples and fuzzers, including a stray
"#pragma GCC diagnostic pop" in xml_parsing.cpp and unchecked
get_if/dynamic_cast results in tests.

CI: ros2-lyrical (GCC 15) now builds in Release, so -Wnull-dereference is
active there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@facontidavide
facontidavide marked this pull request as ready for review November 12, 2026 19:11
facontidavide and others added 5 commits November 12, 2026 20:18
- MSVC: unreachable tail in ValidCast (int->float branch now falls through to
  the common round-trip check), int64_t narrowing in ConvertWithBoundCheck,
  potentially uninitialized timestamp in StatusChangeLogger, uint8_t status in
  FileLogger2, int64_t elapsed time in SqliteLogger, unused catch variable.
- GCC 13: read the minitrace output with rdbuf() instead of
  istreambuf_iterator, which trips -Wnull-dereference in libstdc++ 13.
- clangd: PLUGIN_SYMBOL is now an inline constexpr variable.
- Use std::ignore instead of (void) to discard [[nodiscard]] results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MSVC /W4 reports C4702 in the && overloads of expected::value(); upstream
already disables it for the & overloads, so move the restore below them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
C4702 (unreachable code) fires on instantiation-dependent if-constexpr
tails and has no counterpart in GCC/Clang -Wall -Wextra.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MSVC requires capturing a const int that clang flags as unneeded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gtest_parallel no longer uses it (deprecation warnings are now errors), so
cover it explicitly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@facontidavide
facontidavide merged commit 9174257 into master Nov 12, 2026
18 checks passed
@facontidavide
facontidavide deleted the fix/werror-null-deref-1288 branch November 12, 2026 20:12
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.

New BT.CPP Build Errors with -Werror

1 participant