Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix odr violation for std::format with single argument std::chrono::duration #25135

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from

Conversation

nvartolomei
Copy link
Contributor

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v24.3.x
  • v24.2.x
  • v24.1.x

Release Notes

  • none

We have discovered an ODR violation which causes a ducktape test failure
when running them with a bazel build but not with a cmake build.

Test I tried:
`tests/rptest/tests/cluster_config_test.py::ClusterConfigTest.test_valid_settings`

Errors I get:
`Invalid cpu_profiler_sample_period_ms: '"100ms"' (YAML::TypedBadConversion<std::__2::chrono::duration<long long, std::__2::ratio<1l, 1000l>>> (yaml-cpp: error at line 1, column 1: bad conversion))`

With bazel build the property is rendered as "100ms" while with cmake
build as "100".

Under cmake, the formatting is done by the ostream insertion operator
overload in `src/v/utils/to_string.h`:

```cpp
template<typename Rep, typename Period>
inline std::ostream&
operator<<(std::ostream& o, const std::chrono::duration<Rep, Period>& d) {
    fmt::print(
      o,
      "{}",
      std::chrono::duration_cast<std::chrono::milliseconds>(d).count());
    return o;
}
```

Under bazel build, formatting is handled by formatter specializations of
libfmt "fmt/chrono.h".

The behavior is influenced by the linking order. Godbolt repro
https://godbolt.org/z/EbPEx7n58

In a later commit we'll get rid of the ODR violation but before that we
need to ensure example formatting stays as it was in the binaries we
are currently shipping with cmake to avoid breaking changes and to fix
ducktape tests.

Fortunately, bounded property is used only with a reduced number of
types so we can add handling for them in a relatively simple way.
@vbotbuildovich

This comment was marked as outdated.

@vbotbuildovich

This comment was marked as outdated.

Redpanda for a long time had it's own formatting for
std::chrono::millisecond via ostream insertion operator overload which
fmtlib used. Now fmt ships with its own implementation for formatting
chrono types (fmt/chrono.h) and end behavior depends on linking order.

In this test we either hard code the strings or call count() on duration
to get a numeric value the formatting of which I don't expect to change.
See previous commits in the series for details.
1. This results in ODR violation for fmt since through multiple layers
   of template instantiation it ends up with 2 implementation for
   printing std::chrono::duration. One is this with implicit
    fmt/ostream.h support and the other is provided by fmt/chrono.h.

2. The implementation is garbage. It always prints any durations as
   milliseconds.
@nvartolomei nvartolomei force-pushed the nv/remove-ostream-ins-chrono-duration branch from 13ec539 to c8ed64d Compare February 22, 2025 09:53
@dotnwat dotnwat requested a review from bashtanov February 23, 2025 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants