Skip to content

refactor(otel-thread-ctx): use inline assembly instead of C shim#2197

Open
yannham wants to merge 11 commits into
mainfrom
yannham/thread-ctx-inline-asm
Open

refactor(otel-thread-ctx): use inline assembly instead of C shim#2197
yannham wants to merge 11 commits into
mainfrom
yannham/thread-ctx-inline-asm

Conversation

@yannham

@yannham yannham commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

This revives #2129, which has been merged in a different branch than main. Uses inline assembly instead of a C shim to enable TLSDESC access from Rust.

Motivation

This get rids of all toolchain-related issues, at the cost of some inline ASM. See the original PR for more discussion.

cataphract and others added 6 commits July 6, 2026 10:56
Co-authored-by: Yann Hamdaoui <yann.hamdaoui@gmail.com>
The libdd-otel-thread-ctx build script only validated the target OS/arch and
panicked on unsupported Linux architectures. Move that into a compile_error!
gated on cfg and drop the build script entirely. The linux module is now also
gated on x86_64/aarch64 so an unsupported Linux arch produces a single clean
error instead of a cascade from the module body.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yannham yannham requested review from a team as code owners July 6, 2026 09:22
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation Check Results

⚠️ 281 documentation warning(s) found

📦 libdd-otel-thread-ctx-ffi - 280 warning(s)

📦 libdd-otel-thread-ctx - 1 warning(s)


Updated: 2026-07-06 15:55:41 UTC | Commit: e9e4f6c | missing-docs job results

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Clippy Allow Annotation Report

Comparing clippy allow annotations between branches:

  • Base Branch: origin/main
  • PR Branch: origin/yannham/thread-ctx-inline-asm

Summary by Rule

Rule Base Branch PR Branch Change

Annotation Counts by File

File Base Branch PR Branch Change

Annotation Stats by Crate

Crate Base Branch PR Branch Change
clippy-annotation-reporter 5 5 No change (0%)
datadog-ffe-ffi 1 1 No change (0%)
datadog-ipc 22 22 No change (0%)
datadog-live-debugger 4 4 No change (0%)
datadog-live-debugger-ffi 10 10 No change (0%)
datadog-profiling-replayer 4 4 No change (0%)
datadog-sidecar 45 45 No change (0%)
libdd-common 13 13 No change (0%)
libdd-common-ffi 12 12 No change (0%)
libdd-data-pipeline 6 6 No change (0%)
libdd-ddsketch 2 2 No change (0%)
libdd-dogstatsd-client 1 1 No change (0%)
libdd-profiling 13 13 No change (0%)
libdd-remote-config 3 3 No change (0%)
libdd-telemetry 20 20 No change (0%)
libdd-tinybytes 4 4 No change (0%)
libdd-trace-normalization 2 2 No change (0%)
libdd-trace-obfuscation 3 3 No change (0%)
libdd-trace-stats 1 1 No change (0%)
libdd-trace-utils 11 11 No change (0%)
Total 182 182 No change (0%)

About This Report

This report tracks Clippy allow annotations for specific rules, showing how they've changed in this PR. Decreasing the number of these annotations generally improves code quality.

compile_object.args(["-O2", "-fPIC", "-fomit-frame-pointer", "-c"]);

#[cfg(target_arch = "x86_64")]
compile_object.arg("-mtls-dialect=gnu2");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fear this brings back some toolchain constraints (basically that -mtls-dialect=gnu2 is available), just moving them from the main crate to tests. I wonder if we should just eschew the test if the compiler doesn't support the GNU2 dialect? After all, what we need is that somewhere in CI there's at least one amd64 target where this tests is run (which is currently the case).

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

🔒 Cargo Deny Results

⚠️ 1 issue(s) found, showing only errors (advisories, bans, sources)

📦 libdd-otel-thread-ctx-ffi - 1 error(s)

Show output
error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:110:1
    │
110 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
    ├ rand v0.8.5
      └── (dev) libdd-common v5.0.0
          └── libdd-common-ffi v37.0.0
              └── libdd-otel-thread-ctx-ffi v1.0.0

advisories FAILED, bans ok, sources ok

📦 libdd-otel-thread-ctx - ✅ No issues


Updated: 2026-07-06 15:57:17 UTC | Commit: e9e4f6c | dependency-check job results

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d726f8d89d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread libdd-otel-thread-ctx/src/lib.rs Outdated
Comment on lines +145 to +147
// x1 is guaranteed not to be clobbered by the call
"blr x2",
"add x0, x1, x0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Re-read TP after the AArch64 TLSDESC resolver

On AArch64 this keeps the thread pointer in x1 across blr x2, but the TLSDESC resolver calling convention allows the resolver to clobber x1 (only registers other than x0, x1, x30, and flags must be saved). On loaders/resolvers that use that freedom, add x0, x1, x0 computes the TLS slot from a trashed register, so attach/update/detach can read or write an invalid address; read tpidr_el0 after the TLSDESC call or preserve the TP somewhere the resolver must not clobber.

Useful? React with 👍 / 👎.

@yannham yannham Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, and what's more ARM ABI actually mandates the exact uses of register as well, and we should use x1 instead of x2. Swapping the two in dbb0eeb.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though it's surprising that the check for the exact sequence of instructions succeeded in the CI before 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so after investigation, the previous sequence was the exact one generated by a relatively oldish GCC version (the one we have on CI basically on Alpine and CentOS). The new one is the clang version, exactly. Some GCC versions also move the TP offset calculation around a bit.

For now I've rooted for the clang version, because Rust uses LLVM under the hood, it clobbers one less register, and respect the ABI described above byte per byte. However cc is often gcc in the test, so I've extended the test to make it a bit more lax and accommodate for different compilers.

But it starts to be a lot of code, just for testing something "static" (and just because it's annoying to ensure clang in the CI). I start to question the usefulness of this check: somehow it only has to be tested "once".

@ivoanjo ivoanjo Jul 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I wouldn't go too much into "try to support all compilers in CI"; I would instead suggest going the "gold/known version" approach, e.g. something like:

  • In CI we only assert that "assembly -> matches some known hash". If you change the assembly, you need to update the "some known hash"

  • And then we have some script/test that can recalculate the hash; and next to it is a comment saying "To get the latest assembly hash, we ran this on some standard docker image (ubuntu 26.06 with clang XX)"

Comment thread libdd-otel-thread-ctx-ffi/tests/elf_properties.rs Outdated
@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Jul 6, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 74.42% (-0.02%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 744c7f1 | Docs | Datadog PR Page | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Artifact Size Benchmark Report

aarch64-alpine-linux-musl
Artifact Baseline Commit Change
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 7.88 MB 7.88 MB 0% (0 B) 👌
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.a 85.91 MB 85.91 MB 0% (0 B) 👌
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.61 MB 10.61 MB 0% (0 B) 👌
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 97.11 MB 97.11 MB 0% (0 B) 👌
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 25.46 MB 25.46 MB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.lib 88.44 KB 88.44 KB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.pdb 184.60 MB 184.59 MB -0% (-8.00 KB) 👌
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 946.34 MB 946.34 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 8.32 MB 8.32 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.lib 88.44 KB 88.44 KB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.pdb 24.62 MB 24.62 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 49.04 MB 49.04 MB 0% (0 B) 👌
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 22.06 MB 22.06 MB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.lib 89.82 KB 89.82 KB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.pdb 188.62 MB 188.62 MB 0% (0 B) 👌
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 935.31 MB 935.31 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 6.43 MB 6.43 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.lib 89.82 KB 89.82 KB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.pdb 26.43 MB 26.43 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 46.65 MB 46.65 MB 0% (0 B) 👌
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 76.59 MB 76.59 MB 0% (0 B) 👌
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 8.78 MB 8.78 MB 0% (0 B) 👌
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 92.11 MB 92.11 MB 0% (0 B) 👌
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.69 MB 10.69 MB 0% (0 B) 👌

@pawelchcki pawelchcki left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive By review

Looks good. I looked for some alternatives and this seems like a solid option

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.

4 participants