Skip to content

fix(fuzzer): fix link failure, UBSan in fuzz targets, add ASan log capture#597

Merged
jbachorik merged 3 commits into
mainfrom
fix/fuzzer-issues
Jun 15, 2026
Merged

fix(fuzzer): fix link failure, UBSan in fuzz targets, add ASan log capture#597
jbachorik merged 3 commits into
mainfrom
fix/fuzzer-issues

Conversation

@jbachorik

@jbachorik jbachorik commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?:
Fixes fuzz-CI failures and the JDK 25 ASan shadow-memory conflict.

  1. callTraceStorage.hstatic const u64 DROPPED_TRACE_ID changed to static constexpr. The fuzz target passes it by const u64& to unordered_set::find, which ODR-uses it. static const (non-constexpr) requires an out-of-class definition in that case; static constexpr is implicitly inline in C++17 and needs none. The linker error was: undefined reference to CallTraceStorage::DROPPED_TRACE_ID.

  2. buffers.h — Added __attribute__((no_sanitize("undefined"))) to put16. It does an unaligned short* store to a byte array (same pattern as put32, which already carries this annotation with a comment). UBSan reported: store to misaligned address for type 'short', which requires 2 byte alignment.

  3. ConfigurationPresets.kt — Added log_path=/tmp/asan.log to ASAN_OPTIONS for the asan config. ASan writes one file per PID (/tmp/asan.log.<pid>), preserving output even when the JVM exits abruptly before Gradle captures stderr.

  4. test_workflow.yml — Added Upload ASan logs artifact steps to all four test jobs (glibc/musl × amd64/aarch64), conditioned on failure() && matrix.config == 'asan' with if-no-files-found: ignore. This makes the actual ASan report available as a downloadable artifact on testAsan failures.

  5. JDK 25 ASan shadow-memory conflict — The ASan log captured by change 4 revealed that JDK 25's G1GC reserves heap virtual address space starting just below 2 GB (0x7fff7000), which is exactly where ASan needs to mmap its shadow bytes [0x7fff7000–0x10007fff7fff]. ASan aborts with "Shadow memory range interleaves with an existing memory mapping" before any test runs.

    Fix: for JDK ≥ 25 ASan tests, add JVM flags that force the heap to a low base address so the entire JVM footprint stays below the shadow range:

    • -XX:HeapBaseMinAddress=0x4000000 (64 MB) — moves G1GC's heap reservation far below 2 GB
    • -Xmx512m — bounds total heap size so it doesn't grow back into the shadow range
    • -XX:CompressedClassSpaceSize=256m — keeps class space from pushing the total over 2 GB

    Infrastructure: added testJvmArgs: ListProperty<String> to BuildConfiguration, a testJvmMajorVersion() helper to PlatformUtils, and wiring through ProfilerTestPlugin so both the Test task and the musl Exec task paths pick up the args. Detection runs once at Gradle configuration time via java -version.

Motivation:
The fuzz CI job was failing with a linker error. The buffers fuzzer was hitting a UBSan error. The testAsan job on JDK 25 was aborting before any test ran because ASan could not initialise its shadow memory — a JDK 25-specific regression introduced by G1GC's new heap placement strategy.

How to test the change?:

  • CI: the fuzz job should link and run both fuzz targets without UBSan errors.
  • CI: test-linux-glibc-amd64 (25, asan) and test-linux-glibc-aarch64 (25, asan) pass (previously failing with shadow-memory abort, now green).
  • CI: on any future testAsan failure, an asan-logs-* artifact will appear in the run.

For Datadog employees:

  • This PR doesn't touch any of that.
  • JIRA: [JIRA-XXXX]

… capture

- callTraceStorage.h: static const -> static constexpr for DROPPED_TRACE_ID
  to satisfy ODR when passed by const-ref to unordered_set::find
- buffers.h: add no_sanitize("undefined") to put16, same as put32
- ConfigurationPresets.kt: add log_path=/tmp/asan.log to ASAN_OPTIONS
- test_workflow.yml: upload /tmp/asan.log.* on asan failure (all 4 jobs)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@jbachorik jbachorik added the AI label Jun 12, 2026
@jbachorik jbachorik marked this pull request as ready for review June 12, 2026 15:01
@jbachorik jbachorik requested a review from a team as a code owner June 12, 2026 15:01
@dd-octo-sts

dd-octo-sts Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

CI Test Results

Run: #27546423637 | Commit: fcf0183 | Duration: 13m 52s (longest job)

1 of 54 test jobs failed

Status Overview

JDK glibc-aarch64/asan glibc-aarch64/debug glibc-amd64/asan glibc-amd64/debug musl-aarch64/debug musl-amd64/debug
8 - - - -
8-ibm - - - -
8-j9 - -
8-librca - - - -
8-orcl - - - -
11 - - - -
11-j9 - -
11-librca - - - -
17 - -
17-graal - -
17-j9 - -
17-librca - - - -
21 - -
21-graal - -
21-librca - - - -
25 - -
25-graal - -
25-librca - - - -

Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled

Failed Tests

glibc-amd64/asan / 17

Job: View logs

No detailed failure information available. Check the job logs.

Summary: Total: 54 | Passed: 53 | Failed: 1


Updated: 2026-06-15 12:49:50 UTC

@jbachorik jbachorik added test:asan Run CI tests with AddressSanitizer configuration test:fuzz labels Jun 15, 2026
@datadog-prod-us1-4

datadog-prod-us1-4 Bot commented Jun 15, 2026

Copy link
Copy Markdown

Pipelines

Fix all issues with BitsAI

⚠️ Warnings

🚦 40 Pipeline jobs failed

DataDog/java-profiler | integration-test-arm64-glibc: [hotspot, 17]   View in Datadog   GitLab

DataDog/java-profiler | integration-test-arm64-glibc: [hotspot, 21]   View in Datadog   GitLab

DataDog/java-profiler | integration-test-arm64-glibc: [openj9, 25]   View in Datadog   GitLab

View all 40 failed jobs.

Useful? React with 👍 / 👎

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

jbachorik and others added 2 commits June 15, 2026 11:55
JDK 25's G1GC reserves heap VA starting just below 2 GB (0x7fff7000),
which is exactly where ASan maps its shadow bytes [0x7fff7000-0x10007fff7fff].
For JDK >= 25 ASan tests, force the heap to a low base address
(-XX:HeapBaseMinAddress=0x4000000 -Xmx512m -XX:CompressedClassSpaceSize=256m)
so the entire JVM footprint stays below the shadow range.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@jbachorik jbachorik requested a review from Copilot June 15, 2026 12:31
@jbachorik jbachorik merged commit 0738808 into main Jun 15, 2026
171 checks passed
@jbachorik jbachorik deleted the fix/fuzzer-issues branch June 15, 2026 12:34
@github-actions github-actions Bot added this to the 1.45.0 milestone Jun 15, 2026

Copilot AI 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.

Pull request overview

This PR addresses sanitizer-related CI failures and improves diagnostics for ASan test crashes by fixing a C++ ODR/link issue, suppressing/handling sanitizer reports in fuzz targets, and capturing ASan output as CI artifacts. It also introduces per-configuration JVM args for tests (used to work around an ASan vs JDK 25 address-space conflict).

Changes:

  • Fix C++ link failure by making CallTraceStorage::DROPPED_TRACE_ID constexpr (inline in headers).
  • Add per-build-configuration JVM args plumbing and apply JDK 25 ASan workaround JVM flags.
  • Persist ASan output via ASAN_OPTIONS=log_path=... and upload /tmp/asan.log.* artifacts on testAsan failures.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
ddprof-lib/src/main/cpp/callTraceStorage.h Makes DROPPED_TRACE_ID constexpr to avoid ODR-use link failure in fuzz target.
ddprof-lib/src/main/cpp/buffers.h Adds UBSan suppression for put16 misaligned store (review suggests switching to memcpy to avoid UB).
build-logic/conventions/src/main/kotlin/com/datadoghq/profiler/ProfilerTestPlugin.kt Plumbs BuildConfiguration.testJvmArgs into both Test and Exec-based test runners.
build-logic/conventions/src/main/kotlin/com/datadoghq/native/util/PlatformUtils.kt Adds testJvmMajorVersion() helper for JDK-specific test configuration (bug found in timeout handling).
build-logic/conventions/src/main/kotlin/com/datadoghq/native/model/BuildConfiguration.kt Adds testJvmArgs property with default empty list.
build-logic/conventions/src/main/kotlin/com/datadoghq/native/config/ConfigurationPresets.kt Adds ASan log_path and applies JDK 25 ASan heap-base workaround via testJvmArgs.
.github/workflows/test_workflow.yml Uploads ASan logs as artifacts on ASan test failures across Linux jobs.
Comments suppressed due to low confidence (1)

ddprof-lib/src/main/cpp/buffers.h:87

  • put16 currently writes to char[] via a potentially unaligned short* store and then suppresses UBSan with no_sanitize("undefined"). This still relies on undefined behavior on some architectures and can mask real bugs. Prefer a byte-wise/copy write (e.g., memcpy) so the code is well-defined and the extra UBSan suppression is unnecessary.
  __attribute__((no_sanitize("undefined")))
  __attribute__((no_sanitize("bounds")))
  void put16(short v) {
    assert(_offset + 2 < limit());
    *(short *)(_data + _offset) = htons(v);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +378 to +385
val process = ProcessBuilder("$javaHome/bin/java", "-version")
.redirectErrorStream(true)
.start()
val output = process.inputStream.bufferedReader().readText()
process.waitFor(10, TimeUnit.SECONDS)
// version line: java version "1.8.0_xxx" or java version "21.0.x" etc.
val match = Regex("""version "(?:1\.)?(\d+)""").find(output)
match?.groupValues?.get(1)?.toIntOrNull() ?: 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI test:asan Run CI tests with AddressSanitizer configuration test:fuzz trivial

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants