fix: promote loader symbols to global scope before loading embedded .so#521
Closed
xroche wants to merge 1 commit intoDataDog:mainfrom
Closed
fix: promote loader symbols to global scope before loading embedded .so#521xroche wants to merge 1 commit intoDataDog:mainfrom
xroche wants to merge 1 commit intoDataDog:mainfrom
Conversation
When an application loads libdd_profiling.so via dlopen with RTLD_GLOBAL, glibc does not add the library's symbols to the global scope until dlopen returns. The loader's constructor runs before that point and attempts to dlopen the embedded .so with RTLD_NOW. The embedded library references ddprof_lib_state (a TLS variable introduced in DataDog#490 for fork safety) as an extern symbol. Because the loader's symbols are not yet global, resolution fails: undefined symbol: ddprof_lib_state Fix: before loading the embedded .so, re-open the loader with RTLD_NOLOAD | RTLD_GLOBAL to promote its symbols into global scope. RTLD_NOLOAD prevents a second load; it only updates the visibility. A test exercises this exact pattern: dlopen the loader with RTLD_GLOBAL and verify the embedded library loads. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collaborator
|
Thanks for the proposal, I think this makes sense, it is not super easy to understand the dl_open of ourselves inside a dlopen. Some notes on why we need this: I'll put this in a branch and try things out 👍 |
Collaborator
|
delivering in #522 , thanks! |
r1viollet
added a commit
that referenced
this pull request
Mar 24, 2026
- Update loader_rtld_global_test.c comment to accurately describe both failure modes (glibc RTLD_GLOBAL timing and musl initial-exec TLS rejection) and the pthread_key_t fix - Add comment on kInvalidKey sentinel explaining the POSIX assumption - Add comment in free() explaining why pthread_key_delete is skipped (race with concurrent get_tl_state() callers) - Document why ensure_key_initialized() is public (fork test needs it without a full ring-buffer init) - Add BM_GetTlState microbenchmark to measure raw TLS access overhead (pthread_getspecific vs initial-exec __thread) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #520. When the loader is
dlopen'd withRTLD_GLOBAL, its constructor fails to load the embedded.sobecauseddprof_lib_stateis not yet in global scope.How
Before loading the embedded
.so, re-open the loader itself withRTLD_NOLOAD | RTLD_GLOBAL. This promotes the loader's symbols (includingddprof_lib_state) into global scope without loading it a second time.The call is harmless when the loader was not opened with
RTLD_GLOBAL(the commonLD_PRELOADcase):RTLD_NOLOADon an already-loaded library withRTLD_LOCALsimply returns the existing handle.Test
A new test (
loader_rtld_global) loadslibdd_profiling.soviadlopen(..., RTLD_GLOBAL)and callsddprof_start_profiling(). Without the fix it returns -1 (embedded library failed to load). With the fix it succeeds.