Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

wip: Use TheadLocal to setup protection longjmp buffer#615

Draft
zhengyu123 wants to merge 17 commits into
mainDataDog/java-profiler:mainfrom
zgu/objmonitor_deflationDataDog/java-profiler:zgu/objmonitor_deflationCopy head branch name to clipboard
Draft

wip: Use TheadLocal to setup protection longjmp buffer#615
zhengyu123 wants to merge 17 commits into
mainDataDog/java-profiler:mainfrom
zgu/objmonitor_deflationDataDog/java-profiler:zgu/objmonitor_deflationCopy head branch name to clipboard

Conversation

@zhengyu123

@zhengyu123 zhengyu123 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?:
This PR intents to resolve some of mysterious crashes seen in later releases, e.g. PROF-15206, although, it might not actually solve this particular problem, but I believe it should have positive impact - Cloude and I believe that overwriting JavaThread's exception field is dangerous, in fact, overwriting any JVM data structures are dangerous, because the writes can result in races and readers may see wrong values, that can lead to crashes.

Before introducing Thread Local Handshake in JVM, Thread object is usually only read by 'current` thread, so it is relative safe to alter, then restore values inside signal handler, but not any more - a thread may be able to read other thread's states, before it decides how to proceed the handshake, so it may read wrong values.

This PR introduces a thread local for storing longjmp buffer and eliminates the dependency on overwriting JavaThread's exception field, so

  • Avoiding other thread reads wrong value of the exception field.
  • longjmp now protects all threads, not just JavaThread - should improve stability.

Motivation:
Improve profiler's stability.

Additional Notes:
In additional, exception field only exists in JavaThread, but detection code in Profiler is somewhat questionable, especially, for the subclasses of JavaThread

How to test the change?:

  • CI tests
  • New unit tests

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-15206

Unsure? Have a question? Request a review!

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 a HotSpot JDK 25.0.2+ crash involving MonitorDeflationThread by tightening crash-protection setup in the VM stack walker and hardening a TOCTOU-prone monitor dereference. It also adds regression tests in both ddprof-test (Java) and ddprof-lib (gtest) to cover the new behavior.

Changes:

  • Gate walkVM() crash-protection setup (ThreadShadow::_exception_file / VMThread::exception()) to only apply to “real” Java application threads via VMThread::isJavaThread().
  • Harden VMKlass::fromOop() against concurrent monitor deflation by using SafeAccess::safeFetch64() for the monitor pointer dereference.
  • Add Java + C++ regression/unit tests targeting the MonitorDeflationThread crash scenario and the new gating logic.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
ddprof-test/src/test/java/com/datadoghq/profiler/cpu/MonitorDeflationThreadSafetyTest.java Adds a regression test intended to reproduce Monitor inflation/deflation while CPU profiling signals are active.
ddprof-lib/src/test/cpp/hotspot_crash_protection_ut.cpp Adds gtest coverage for ProfiledThread classification and vtable-vote behavior used by VMThread::isJavaThread().
ddprof-lib/src/main/cpp/hotspot/vmStructs.h Uses safeFetch64 to avoid a crash when dereferencing an ObjectMonitor* that may be concurrently freed by deflation.
ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp Gates crash-protection activation to avoid writing _exception_file for JVM-internal threads; adds null-guard for vtable receiver klass lookup.

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

Comment thread ddprof-lib/src/test/cpp/hotspot_crash_protection_ut.cpp
Comment thread ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp Outdated
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Jun 24, 2026

Copy link
Copy Markdown

Pipelines

Fix all issues with BitsAI

⚠️ Warnings

🚦 15 Pipeline jobs failed

DataDog/java-profiler | benchmarks-candidate-aarch64: [alloc]   View in Datadog   GitLab

DataDog/java-profiler | benchmarks-candidate-aarch64: [cpu,wall,alloc,memleak]   View in Datadog   GitLab

DataDog/java-profiler | benchmarks-candidate-aarch64: [cpu,wall]   View in Datadog   GitLab

View all 15 failed jobs.

Useful? React with 👍 / 👎

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

@dd-octo-sts

dd-octo-sts Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

CI Test Results

Run: #28384019189 | Commit: f0b1adf | Duration: 13m 30s (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-06-29 15:55:18 UTC

zhengyu123 and others added 4 commits June 24, 2026 16:58
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@dd-octo-sts

dd-octo-sts Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Reliability & Chaos Results

All reliability & chaos checks passed Pipeline: https://gitlab.ddbuild.io/DataDog/java-profiler/-/pipelines/121651273

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

Comment thread ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp

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

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Comment thread ddprof-lib/src/main/cpp/threadLocal.h Outdated
Comment thread ddprof-lib/src/main/cpp/threadLocal.h Outdated
Comment thread ddprof-lib/src/main/cpp/threadLocal.h
Comment thread ddprof-lib/src/main/cpp/jvmThread.cpp
Comment thread ddprof-lib/src/main/cpp/jvmThread.h
Comment thread ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp Outdated
zhengyu123 and others added 5 commits June 26, 2026 20:09
@zhengyu123 zhengyu123 changed the title wip: wip: Use TheadLocal to setup protection longjmp buffer Jun 29, 2026
@zhengyu123 zhengyu123 requested a review from Copilot June 29, 2026 13:30

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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 9 comments.

Comment thread ddprof-lib/src/main/cpp/hotspot/hotspotSupport.h
Comment on lines 16 to +20
bool JVMThread::initialize() {
void* current_thread = currentThreadSlow();
if (current_thread == nullptr) {
return false;
}
_jvm_thread.initialize(current_thread);
// _tid is side-effect of currentThreadSlow()
assert(_tid != nullptr);
Comment on lines +188 to +192
if (vm_thread != NULL) {
_jmp_ctx.set(&crash_protection_ctx);
if (profiled_thread != nullptr) {
profiled_thread->setCrashProtectionActive(true);
}
Comment on lines 894 to 898
bool protected_walk = (thrd != nullptr && thrd->isCrashProtectionActive())
|| sameStack(vm_thread->exception(), &vm_thread);
|| sameStack(_jmp_ctx.get(), &vm_thread);
if (!protected_walk) {
return;
}
Comment on lines +188 to +190
if (vm_thread != NULL) {
_jmp_ctx.set(&crash_protection_ctx);
if (profiled_thread != nullptr) {
Comment on lines +210 to +226
void initialize(void* current_thread) {
// Called from known JavaThread, it should never be nullptr.
if (current_thread == nullptr) {
assert(false && "Should not reach here");
}

long max_keys = sysconf(_SC_THREAD_KEYS_MAX);

for (long i = 0; i < max_keys; i++) {
if (pthread_getspecific((pthread_key_t)i) == current_thread) {
_key = pthread_key_t(i);
break;
}
}

assert(isKeyValid() && "Invalid thread key");
}
Comment on lines +9 to +19
* Root cause: walkVM() unconditionally wrote a jmp_buf address into
* ThreadShadow::_exception_file for every non-null VMThread, including
* JVM-internal threads such as MonitorDeflationThread. In JDK 25,
* ObjectMonitorDeflationSafepointer reads thread state (including
* _exception_file) at safepoint boundaries; finding a stale jmp_buf
* address instead of NULL or a C-string caused a crash in
* deflate_monitor_list.
*
* Fix: gate the _exception_file write on VMThread::isJavaThread(), which
* uses vtable comparison to distinguish regular Java application threads
* from JVM-internal threads that are JavaThread subclasses in JDK 25+.
Comment on lines +5 to +14
* Unit tests for the MonitorDeflationThread crash-protection gate.
*
* Root cause (JDK 25.0.2): walkVM() unconditionally wrote a jmp_buf address
* into ThreadShadow::_exception_file for every non-null VMThread, including
* JVM-internal threads like MonitorDeflationThread. In JDK 25,
* ObjectMonitorDeflationSafepointer reads _exception_file at safepoint
* boundaries; a stale jmp_buf address caused a crash in deflate_monitor_list.
*
* Fix: gate the write on `VMThread::isJavaThread(vm_thread)`.
*
Comment on lines +196 to +236
// ---------------------------------------------------------------------------
// C. setup_crash_protection gate condition
//
// walkVM computes: setup_crash_protection = (vm_thread != NULL) && isJavaThread()
// Verify that the gate is false for TYPE_NOT_JAVA_THREAD threads (fast path).
// ---------------------------------------------------------------------------

class CrashProtectionGateTest : public ::testing::Test {
protected:
void SetUp() override {
ProfiledThread::initCurrentThread();
_pt = ProfiledThread::currentSignalSafe();
ASSERT_NE(nullptr, _pt);
}

void TearDown() override {
ProfiledThread::release();
}

ProfiledThread* _pt = nullptr;

// Replicate the fast-path of isJavaThread() for gating purposes.
static bool fastPathIsJavaThread(ProfiledThread* pt) {
if (pt == nullptr) return false;
ProfiledThread::ThreadType type = pt->threadType();
if (type != ProfiledThread::TYPE_UNKNOWN) {
return type == ProfiledThread::TYPE_JAVA_THREAD;
}
return false; // TYPE_UNKNOWN → slow vtable path (not tested here)
}
};

// Gate is off for a JVM-internal thread (TYPE_NOT_JAVA_THREAD):
// _exception_file must NOT be written.
TEST_F(CrashProtectionGateTest, GateOffForNonJavaThread) {
_pt->setJavaThread(false);
// Simulate: vm_thread != NULL (non-null pointer means JVM thread struct exists)
bool vm_thread_non_null = true;
bool setup_crash_protection = vm_thread_non_null && fastPathIsJavaThread(_pt);
EXPECT_FALSE(setup_crash_protection);
}
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@dd-octo-sts

dd-octo-sts Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Scan-Build Report

User:runner@runnervmmklqx
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:Mon Jun 29 15:40:00 2026

Bug Summary

Bug TypeQuantityDisplay?
All Bugs1
Unused code
Dead initialization1

Reports

Bug Group Bug Type ▾ File Function/Method Line Path Length
Unused codeDead initializationhotspotSupport.cppwalkVM1851

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

Morty Proxy This is a proxified and sanitized view of the page, visit original site.