Skip to content

add Blackboard::getKeyNames() and deprecate getKeys() (dangling StringViews) - #1203

Merged
facontidavide merged 1 commit into
masterfrom
fix-getkeys-dangling-views
Sep 20, 2026
Merged

facontidavide merged 1 commit into
masterfrom
fix-getkeys-dangling-views

Conversation

@facontidavide

@facontidavide facontidavide commented Sep 20, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up of #1202 (merged); rebased onto master.

Bug

Blackboard::getKeys() returns std::vector<StringView> pointing into the keys of storage_. The shared lock taken inside only protects the iteration: once the function returns, a concurrent unset() frees the key and the views dangle.

The library itself was bitten by this: ExportBlackboardToJSON built a std::string from each view, so the Groot2 publisher thread could read freed memory while the tick thread runs UnsetBlackboard. ASan on the new test, before the fix:

heap-use-after-free ... basic_string(basic_string_view) 
    in BT::ExportBlackboardToJSON  src/blackboard.cpp
freed by ... BT::Blackboard::unset

It was found while reviewing #1181 / #1202 and is independent of the entry-lifetime bug fixed there.

Fix (additive, no API/ABI break)

  • New std::vector<std::string> Blackboard::getKeyNames() const: copies made under the storage lock. New non-virtual member, no layout change.
  • getKeys() keeps its signature and behaviour but is marked [[deprecated]] (its return type can not be changed compatibly: it is not part of the mangled name).
  • ExportBlackboardToJSON and the tests use getKeyNames().

Test

BlackboardThreadSafety.ExportToJsonWhileKeysAreRemoved: one thread exports to JSON in a loop while another sets/unsets heap-allocated keys. Fails with the ASan report above before the fix, passes after. It relies on #1202 (merged): without it the same interleaving also hits the entry use-after-free.

ASan+UBSan 81/81 (Blackboard, JSON, Groot2, parser suites), TSan 36/36, full Debug suite 529/529, pre-commit/clang-tidy clean.

🤖 Generated with Claude Code

Base automatically changed from fix-blackboard-entry-lifetime to master September 20, 2026 13:16
getKeys() returns StringViews into the keys of the storage map, valid only
while the storage lock is held, i.e. never for the caller. ExportBlackboardToJSON
built a std::string from them while another thread could unset() the entry:
heap-use-after-free (Groot2 thread vs UnsetBlackboard on the tick thread).

getKeyNames() returns copies made under the lock. getKeys() is unchanged but
deprecated, so the change is purely additive (no ABI/API break).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@facontidavide
facontidavide force-pushed the fix-getkeys-dangling-views branch from ed92f32 to d1d5ecf Compare September 20, 2026 13:18
@facontidavide
facontidavide merged commit 1be0313 into master Sep 20, 2026
15 checks passed
@facontidavide
facontidavide deleted the fix-getkeys-dangling-views branch September 20, 2026 13:24
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
D Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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.

1 participant