Skip to content

fix UBSan false positives with captureless lambdas in C++20#666

Merged
kris-jusiak merged 1 commit into
boost-ext:masterfrom
PavelGuzenfeld:fix/ubsan-empty-type-reference-binding
May 23, 2026
Merged

fix UBSan false positives with captureless lambdas in C++20#666
kris-jusiak merged 1 commit into
boost-ext:masterfrom
PavelGuzenfeld:fix/ubsan-empty-type-reference-binding

Conversation

@PavelGuzenfeld
Copy link
Copy Markdown
Contributor

@PavelGuzenfeld PavelGuzenfeld commented May 22, 2026

Two sources of -fsanitize=undefined noise in C++20 builds:

1. zero_wrapper_impl::operator()
The existing implementation uses reinterpret_cast<const TExpr&>(*this) to call a captureless lambda stored in a zero-size wrapper. This violates strict aliasing and triggers UBSan "reference binding with insufficient space" because the wrapper has zero size (via __BOOST_SML_ZERO_SIZE_ARRAY).

In C++20, captureless lambdas are default-constructible, so TExpr{}(args...) works directly — no cast needed, no UBSan. The C++14/17 path is unchanged.

2. transition(always, ...) constructors
always{} temporaries passed as const always& trigger the same UBSan check when the optimizer recycles the stack slot. Since always is stateless, passing by value is equivalent and avoids the reference binding.

Reproducer: compile example/data.cpp with -std=c++20 -fsanitize=undefined -O1.

Fixes #627
Co-authored-by claude.

@tralamazza
Copy link
Copy Markdown

which AI agent are you using for these PRs?

@PavelGuzenfeld
Copy link
Copy Markdown
Contributor Author

which AI agent are you using for these PRs?

Claude.

@tralamazza
Copy link
Copy Markdown

Claude.

Might want to leave in the "Co-authored-by" for future ref.

@PavelGuzenfeld
Copy link
Copy Markdown
Contributor Author

PavelGuzenfeld commented May 22, 2026

Claude.

Might want to leave in the "Co-authored-by" for future ref.

We are using this library in production so it's my duty to make sure its well maintained.

Two changes:

1. zero_wrapper_impl::operator(): in C++20, captureless lambdas are
   default-constructible so we can call TExpr{}(args...) directly
   instead of the reinterpret_cast<const TExpr&>(*this) hack.
   The reinterpret_cast violates strict aliasing and triggers
   -fsanitize=undefined "insufficient space" when the wrapper has
   zero size (via __BOOST_SML_ZERO_SIZE_ARRAY). In C++14/17 the
   existing approach is preserved.

2. transition(always, ...): pass always by value instead of
   const-reference. always{} temporaries bound to const& trigger
   the same UBSan check when the optimizer recycles their stack slot.
   Since always has no state, passing by value is equivalent.

Fixes boost-ext#627
@PavelGuzenfeld PavelGuzenfeld force-pushed the fix/ubsan-empty-type-reference-binding branch from 05a7487 to b2a8b9f Compare May 22, 2026 16:20
@kris-jusiak kris-jusiak merged commit 8330450 into boost-ext:master May 23, 2026
5 checks passed
@PavelGuzenfeld PavelGuzenfeld deleted the fix/ubsan-empty-type-reference-binding branch May 27, 2026 13:58
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.

runtime error: reference binding to address 0x7ffec1ae3d54 with insufficient space for an object of type 'const always'

3 participants