Skip to content

[fault-injection] Unprotected access to JVM class loader data mutex and method list - #779

Open
zhengyu123 wants to merge 8 commits into
mainfrom
zgu/jdk8_patchClassLoaderData
Open

zhengyu123 wants to merge 8 commits into
mainfrom
zgu/jdk8_patchClassLoaderData

Conversation

@zhengyu123

@zhengyu123 zhengyu123 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?:
Hotspot JDK8 specific.

patchClassLoaderData() prepends MethodList blocks onto a class's ClassLoaderData to work around a JDK 8 jmethodID layout bug. This PR hardens that path:

  • Guards the cld->lock()/methodList() mutation and its matching cld->unlock() with the profiler's signal/crash-protection machinery (ProfiledThread, JmpCtxScope, sigsetjmp/SIGNAL_HANDLER_UNWIND_AFTER_LONGJMP), via the new LockState RAII helper, so a crash while the classloader-data mutex is held during a signal-unsafe window unlocks it instead of deadlocking the JVM.
  • Tags each patched jclass (via JVMTI Get/SetTag) with the method_count already prepended, so repeated calls for the same class (profiler restart replay, RedefineClasses/RetransformClasses) only prepend the delta instead of leaking another full set of MethodList blocks on every re-run.
  • Releases the classloader-data lock before calling the JVMTI tag API, since cld->lock() suppresses safepoint checks while Get/SetTag are safepoint-polling JVMTI entry points.

Motivation:
Fault injection testing found that unprotected access to the JVM class loader data mutex and method list in patchClassLoaderData() could crash or deadlock the JVM.

Additional Notes:
The SetTag() call is not serialized against a concurrent patchClassLoaderData() call for the same class, so two racing callers can both observe a stale tag and both patch. This only wastes one extra round of preallocated blocks in that rare case; unlike the original unguarded code, it can no longer grow unboundedly.

How to test the change?:
Added unit tests in ddprof-lib/src/test/cpp/hotspotSupport_ut.cpp covering the locking/crash-protection and idempotent-tagging behavior of patchClassLoaderData().

For Datadog employees:

  • If this PR touches code that signs or publishes builds or packages, or handles
    credentials of any kind, I've requested a security review (run the dd:platform-security-review
    skill, or file a request via the PSEC review form).
    bewaire also runs automatically on every PR.
  • This PR doesn't touch any of that.
  • JIRA: PROF-15462

Unsure? Have a question? Request a review!

@dd-octo-sts

dd-octo-sts Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Scan-Build Report

User:runner@runnervmlun5p
Working Directory:/home/runner/work/java-profiler/java-profiler/ddprof-lib/src/test/make
Command Line:make -j4 all
Clang Version:Ubuntu clang version 18.1.3 (1ubuntu1)
Date:Thu Sep 17 11:03:01 2026

Bug Summary

Bug TypeQuantityDisplay?
All Bugs1
Logic error
Dereference of null pointer1

Reports

Bug Group Bug Type ▾ File Function/Method Line Path Length
Logic errorDereference of null pointerfaultInjection.cppcrashNow242

@dd-octo-sts

dd-octo-sts Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

CI Test Results

Run: #35372751835 | Commit: 529f836 | Duration: 15m 11s (longest job)

All 32 test jobs passed

Status Overview

JDK glibc-aarch64/debug 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

Summary: Total: 32 | Passed: 32 | Failed: 0


Updated: 2026-09-18 17:31:39 UTC

@dd-octo-sts

dd-octo-sts Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

All 40 integration tests passed

📊 Dashboard · 👷 Pipeline · 📦 ac5ae414

@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented Sep 14, 2026

Copy link
Copy Markdown

Pipelines

Unblock PR with BitsAI

❌ Errors

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 4 Pipeline jobs failed

DataDog/java-profiler | gtest-asan-amd64 — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

DataDog/java-profiler | gtest-asan-arm64 — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

DataDog/java-profiler | gtest-tsan-amd64 — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

View all 4 failed jobs.

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 08ef73b | Docs | View more details | Give us feedback!

@zhengyu123
zhengyu123 marked this pull request as ready for review September 17, 2026 19:43
@zhengyu123
zhengyu123 requested a review from a team as a code owner September 17, 2026 19:43

@datadog-prod-us1-6 datadog-prod-us1-6 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.

Datadog Autotest: PASS

More details

The static review finds no defect in the JDK 8 lock recovery or per-class delta tag paths.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Datadog Autotest · Commit 2ba3f13 · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@zhengyu123
zhengyu123 marked this pull request as draft September 18, 2026 00:40
@zhengyu123
zhengyu123 marked this pull request as ready for review September 18, 2026 17:14

@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: 08ef73bae8

ℹ️ 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 on lines +1413 to +1414
if (method_count <= already_patched) {
return -1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Re-prime redefined classes on JDK 8

On JDK 8, after a class whose prior MethodList capacity was exhausted (for example, an 8-method class) is redefined or retransformed, its jclass tag and method count remain unchanged, so this branch skips the preallocation entirely. The hooks in vmEntry.cpp:671-692 explicitly reload jmethodIDs after those operations invalidate them; the subsequent GetClassMethods can therefore allocate through the original tail layout that the JDK-8062116 workaround is intended to avoid. Clear or version the recorded tag for redefinition/retransformation rather than treating an unchanged count as already primed.

Useful? React with 👍 / 👎.

@datadog-prod-us1-6 datadog-prod-us1-6 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.

Datadog Autotest: FAIL

A JDK 8 class transformation keeps the old tag. The next method reload skips the required MethodList preallocation when the method count stays the same.

Open Bits AI session

🤖 Datadog Autotest · Commit 08ef73b · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

if (jvmti == nullptr || jvmti->GetTag(klass, &already_patched) != JVMTI_ERROR_NONE) {
already_patched = 0;
}
if (method_count <= already_patched) {

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 Keep preallocation after class transformation

JDK 8 class transformations can use the slow HotSpot list path that the JDK-8062116 workaround prevents.

Assertion details
  • Input: A tagged JDK 8 class completes RedefineClasses or RetransformClasses without a method-count change.
  • Expected: Class redefinition and retransformation must add fresh MethodList capacity before they reload invalid jmethodIDs.
  • Actual: The old tag makes patchClassLoaderData return before it adds new MethodList capacity. GetClassMethods then reloads invalid jmethodIDs without the JDK 8 workaround.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest · Open Bits AI session

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.

2 participants