-
Notifications
You must be signed in to change notification settings - Fork 501
Description
Using the default RuntimeContextStorage (ThreadLocalContextStorage) causes a segfault when a span is made active in an exit handler registered with atexit()
. This is due to thread_local
storage being cleaned up before exit handlers are called, destroying the context storage Stack
and causing the next Context
push (in the exit handler) to segfault.
A lightly modified version of otel's simple example demonstrates this:
#include <iostream>
#include "opentelemetry/exporters/ostream/span_exporter_factory.h"
#include "opentelemetry/sdk/trace/exporter.h"
#include "opentelemetry/sdk/trace/processor.h"
#include "opentelemetry/sdk/trace/provider.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/tracer_provider.h"
#include "opentelemetry/trace/provider.h"
namespace trace_api = opentelemetry::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace trace_exporter = opentelemetry::exporter::trace;
namespace
{
void InitTracer()
{
auto exporter = trace_exporter::OStreamSpanExporterFactory::Create();
auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter));
std::shared_ptr<opentelemetry::sdk::trace::TracerProvider> sdk_provider =
trace_sdk::TracerProviderFactory::Create(std::move(processor));
const std::shared_ptr<opentelemetry::trace::TracerProvider> &api_provider = sdk_provider;
trace_sdk::Provider::SetTracerProvider(api_provider);
}
void CleanupTracer()
{
std::shared_ptr<opentelemetry::trace::TracerProvider> noop;
trace_sdk::Provider::SetTracerProvider(noop);
}
void tracedFunction() {
auto tracer = opentelemetry::trace::Provider::GetTracerProvider()->GetTracer("simpleTest");
auto span = tracer->StartSpan("testSpan");
auto scope = tracer->WithActiveSpan(span);
}
void exitHandler() {
std::cout << "Exit handler" << std::endl;
tracedFunction(); // THIS WILL CAUSE A SEGFAULT
CleanupTracer();
}
} // namespace
int main()
{
InitTracer();
tracedFunction();
atexit(exitHandler);
tracedFunction();
}
This is seen using otel 1.19.0 with g++ 13.3.0. Is opentelemetry expected to crash a program if an exit handler is registered that happens to do something that activates a span? One work around we're considering (to avoid the segfault) is using a sentinel thread_local bool
that is set when the Stack
is destructed to signal the end of thread_local storage (and then either create ad hoc storage or stop trying to interact with the Stack; it's not clear we'll be able to collect any meaningful trace information at this point anyways).