@@ -43,29 +43,48 @@ class FakeFormatBuilder final : public BaseFormatBuilder {
4343 void HandleMetric (std::string_view, LabelsSpan, const MetricValue&) override {}
4444};
4545
46+ void WriteWithFakeFormat (impl::MetricsSource& source)
47+ {
48+ static constexpr std::string_view fake_prefix = " fake_prefix" ;
49+ if (source.writer ) {
50+ FakeFormatBuilder builder;
51+ const Request request;
52+ impl::WriterState state{builder, request, {}, {}};
53+ auto writer = Writer{&state}[fake_prefix];
54+ source.writer (writer);
55+ }
56+ if (source.extender ) {
57+ source.extender (StatisticsRequest{});
58+ }
59+ }
60+
61+ [[maybe_unused]] void CheckDataUsedByCallbackIsValidBeforeRegistering (impl::MetricsSource& source) noexcept {
62+ try {
63+ WriteWithFakeFormat (source);
64+ } catch (const std::exception& e) {
65+ utils::AbortWithStacktrace (fmt::format (
66+ " Unhandled exception while statistics holder {} is registering: {}" ,
67+ source.prefix_path ,
68+ e.what ()
69+ ));
70+ }
71+ }
72+
4673// During the `Entry::Unregister` call or destruction of `Entry`, all variables
4774// used by the writer or extender callback must be valid (must not be
4875// destroyed). A common cause of crashes in this place: there is no manual call
4976// to `Unregister`. In this case, check the lifetime of the data used by the
5077// callback.
5178[[maybe_unused]] void CheckDataUsedByCallbackHasNotBeenDestroyedBeforeUnregistering (impl::MetricsSource& source
5279) noexcept {
53- static constexpr std::string_view fake_prefix = " fake_prefix" ;
5480 try {
55- if (source.writer ) {
56- FakeFormatBuilder builder;
57- const Request request;
58- impl::WriterState state{builder, request, {}, {}};
59- auto writer = Writer{&state}[fake_prefix];
60- source.writer (writer);
61- }
62- if (source.extender ) {
63- source.extender (StatisticsRequest{});
64- }
81+ WriteWithFakeFormat (source);
6582 } catch (const std::exception& e) {
66- LOG_ERROR ()
67- << " Unhandled exception while statistics holder " << source.prefix_path
68- << " is unregistering automatically: " << e.what ();
83+ utils::AbortWithStacktrace (fmt::format (
84+ " Unhandled exception while statistics holder {} is unregistering automatically: {}" ,
85+ source.prefix_path ,
86+ e.what ()
87+ ));
6988 }
7089}
7190
@@ -185,6 +204,9 @@ Entry Storage::DoRegisterExtender(impl::MetricsSource&& source) {
185204 );
186205
187206 const std::lock_guard lock (mutex_);
207+ if constexpr (impl::kCheckSubscriptionUB ) {
208+ CheckDataUsedByCallbackIsValidBeforeRegistering (source);
209+ }
188210 const auto res = metrics_sources_.insert (metrics_sources_.end (), std::move (source));
189211 return Entry (Entry::Impl{this , res});
190212}
0 commit comments