From 6b61672bd97651285272585c1e4c2a8ed4370926 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 21 Jul 2026 15:04:38 +0000 Subject: [PATCH] [fault-injection] Unprotected access to JVM class loader data mutex and method list --- .../src/main/cpp/hotspot/hotspotSupport.cpp | 5 +-- ddprof-lib/src/main/cpp/hotspot/vmStructs.cpp | 12 ++++++ ddprof-lib/src/main/cpp/hotspot/vmStructs.h | 41 +++++++------------ .../src/main/cpp/hotspot/vmStructs.inline.h | 32 +++++++++++++++ 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp b/ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp index 1c925e492d..4d12c0bbae 100644 --- a/ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp +++ b/ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp @@ -1264,11 +1264,10 @@ static void patchClassLoaderData(JNIEnv* jni, jclass klass) { int method_count = vmklass->methodCount(); if (method_count > 0) { VMClassLoaderData *cld = vmklass->classLoaderData(); - cld->lock(); + VMClassLoaderDataMutexLocker locker(cld->mutex()); for (int i = 0; i < method_count; i += MethodList::SIZE) { - *cld->methodList() = new MethodList(*cld->methodList()); + *cld->methodList() = new MethodList(cld->methodList()); } - cld->unlock(); } } } diff --git a/ddprof-lib/src/main/cpp/hotspot/vmStructs.cpp b/ddprof-lib/src/main/cpp/hotspot/vmStructs.cpp index ccbca45089..8ceae60cca 100644 --- a/ddprof-lib/src/main/cpp/hotspot/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/hotspot/vmStructs.cpp @@ -1165,3 +1165,15 @@ HeapUsage HeapUsage::get(bool allow_jmx) { } return usage; } + +VMClassLoaderDataMutexLocker::VMClassLoaderDataMutexLocker(void* mutex) : _mutex(mutex) { + if (_mutex != nullptr) { + _lock_func(_mutex); + } +} + +VMClassLoaderDataMutexLocker::~VMClassLoaderDataMutexLocker() { + if (_mutex != nullptr) { + _unlock_func(_mutex); + } +} diff --git a/ddprof-lib/src/main/cpp/hotspot/vmStructs.h b/ddprof-lib/src/main/cpp/hotspot/vmStructs.h index 9ef2586851..54bcfcf821 100644 --- a/ddprof-lib/src/main/cpp/hotspot/vmStructs.h +++ b/ddprof-lib/src/main/cpp/hotspot/vmStructs.h @@ -449,18 +449,11 @@ class VMStructs { static void checkNativeBinding(jvmtiEnv *jvmti, JNIEnv *jni, jmethodID method, void *address); static const void *findHeapUsageFunc(); - const char* at(int offset) { - const char* ptr = (const char*)this + offset; - assert(crashProtectionActive() || SafeAccess::isReadable(ptr)); - // Poison only the returned pointer; the assert above sees the real ptr. - return INJECT_FAULT_ADDRESS_RARE(ptr); - } + const char* at(int offset); + const char* at(int offset) const; - const char* at(int offset) const { - const char* ptr = (const char*)this + offset; - assert(crashProtectionActive() || SafeAccess::isReadable(ptr)); - return INJECT_FAULT_ADDRESS_RARE(ptr); - } + template + T load_at_offset(int offset) const; static bool goodPtr(const void* ptr) { return (uintptr_t)ptr >= 0x1000 && ((uintptr_t)ptr & (sizeof(uintptr_t) - 1)) == 0; @@ -635,24 +628,20 @@ DECLARE(VMSymbol) static int bodyOffset() { return _symbol_body_offset; } DECLARE_END -DECLARE(VMClassLoaderData) +class VMClassLoaderDataMutexLocker : protected VMStructs { private: - void* mutex() { - return *(void**) at(sizeof(uintptr_t) * 3); - } - + void* _mutex; public: - void lock() { - _lock_func(mutex()); - } - - void unlock() { - _unlock_func(mutex()); - } + VMClassLoaderDataMutexLocker(void* mutex); + ~VMClassLoaderDataMutexLocker(); +}; - MethodList** methodList() { - return (MethodList**) at(sizeof(uintptr_t) * 6 + 8); - } +// VMClassLoaderData is used outside of protected (longjmp) context, +// so both methods are protected by SafeAccess +DECLARE(VMClassLoaderData) + public: + inline void* mutex(); + inline MethodList* methodList(); DECLARE_END DECLARE(VMKlass) diff --git a/ddprof-lib/src/main/cpp/hotspot/vmStructs.inline.h b/ddprof-lib/src/main/cpp/hotspot/vmStructs.inline.h index 2b7edb3250..8a18150f13 100644 --- a/ddprof-lib/src/main/cpp/hotspot/vmStructs.inline.h +++ b/ddprof-lib/src/main/cpp/hotspot/vmStructs.inline.h @@ -28,6 +28,29 @@ inline T* cast_to(const void* ptr) { return reinterpret_cast(const_cast(ptr)); } +inline const char* VMStructs::at(int offset) { + const char* ptr = (const char*)this + offset; + assert(crashProtectionActive() || SafeAccess::isReadable(ptr)); + // Poison only the returned pointer; the assert above sees the real ptr. + return INJECT_FAULT_ADDRESS_RARE(ptr); +} + +inline const char* VMStructs::at(int offset) const { + const char* ptr = (const char*)this + offset; + assert(crashProtectionActive() || SafeAccess::isReadable(ptr)); + return INJECT_FAULT_ADDRESS_RARE(ptr); +} + +template +T VMStructs::load_at_offset(int offset) const { + const char* ptr = at(offset); + if (safe) { + return (T)SafeAccess::loadPtr((void**)ptr, nullptr); + } else { + return *((T*)ptr); + } +} + VMThread* VMThread::current() { assert(VM::isHotspot()); return VMThread::cast(JVMThread::current()); @@ -188,5 +211,14 @@ u16 VMConstMethod::signatureIndex() const { return *(u16*)at(_constmethod_sig_index_offset); } +// ClassLoaderData accesses are unprotected +void* VMClassLoaderData::mutex() { + return load_at_offset(sizeof(uintptr_t) * 3); +} + +MethodList* VMClassLoaderData::methodList() { + return load_at_offset(sizeof(uintptr_t) * 6 + 8); +} + #endif // _HOTSPOT_VMSTRUCTS_INLINE_H