RFR: 8224221: add memprotect calls to event log

David Holmes david.holmes at oracle.com
Fri May 24 06:46:17 UTC 2019


Hi Matthias,

On 23/05/2019 11:25 pm, Baesken, Matthias wrote:
>>>>
>>>> This is starting to look a bit inconsistent. If you want to log
>>>> VirtualProtect calls then there are more of them than just in
>>>> guard_memory and unguard_memory. So I'm unclear on the intent here -
>> is
>>>> it to log all "memory protection" actions or only to log those that
>>>> pertain to specific semantic actions?
>>>
>>> My Intention was to cover Windows as well,  however  it looks like  there
>> are more  VirtualProtect calls  (9)   in  os_windows.cpp   than  mprotects  in
>> os_linux.cpp  (just 1 in linux_mprotect).
>>> But maybe it is better to  omit VirtualProtect /   os_windows in this patch ,
>> no problem.
>>> What do you think ?
>>
>> I think you need to decide what this work is trying to log - is it
>> "mprotect" calls or is it "memory protection" calls? Or something else.
> 
> Hi David,
> 
> Let's  concentrate on the mprotects    !
> 
> http://cr.openjdk.java.net/~mbaesken/webrevs/8224221.4/

Okay so basically non-Windows support. Please make this clear in the bug 
report.

Those changes seem fine.

>>>
>>> Yes ,  if I keep  the   eventlog_init()   where it is, I miss  a few  early
>> mprotect  calls .
>>> I observed this in our tests .
>>>
>>> However  when  moving forward  eventlog_init  like I did in the first rev.   (
>> http://cr.openjdk.java.net/~mbaesken/webrevs/8224221.0/src/hotspot/sha
>> re/runtime/thread.cpp.frames.html  ) ,
>>> I run into   " assert(os::mutex_init_done()) failed: Too early! "
>>> Mutex_init is done in   os::init_2 , which is  called from
>>>
>>> Threads::create_vm() {
>>>      ...
>>> 3740   // Initialize the os module after parsing the args
>>> 3741   jint os_init_2_result = os::init_2();
>>> 3742   if (os_init_2_result != JNI_OK) return os_init_2_result;
>>>     ...
>>> }
>>>
>>> So  I could  place  eventlog_init()   after   os::init_2  instead of the start of
>> Threads::create_vm .
>>
>> I added an assert(false) in linux_mprotect to see where it is first
>> called from (not 100% accurate as different flags may trigger other code
>> paths) and found it was called from initialize_assert_poison() here:
>>
>>     // Initialize the os module after parsing the args
>>     jint os_init_2_result = os::init_2();
>>     if (os_init_2_result != JNI_OK) return os_init_2_result;
>>
>> #ifdef CAN_SHOW_REGISTERS_ON_ASSERT
>>     // Initialize assert poison page mechanism.
>>     if (ShowRegistersOnAssert) {
>>       initialize_assert_poison();
>>     }
>> #endif // CAN_SHOW_REGISTERS_ON_ASSERT
>>
>> So if you move your event_init to before the #ifdef it not only should
>> work okay, but it also shouldn't normally miss any calls to mprotect.
>> Obviously more extensive testing would be needed.
>>
> 
> Thanks for looking into it .
> Unfortunately this causes another assertion  (shows up already in the fastdebug  build  when using  the new JVM) .
> 
> 
> jdk/src/hotspot/share/runtime/thread.hpp:818), pid=53146, tid=53268
> assert(current != __null) failed: Thread::current() called on detached thread

Okay so that's a different problem: the event log uses a mutex and that 
needs an attached thread. So you can't use the event_log before the main 
thread has attached even if you've initialized the event log. So even if 
you keep the eventlog_init() where it is inside vm_init_globals(), 
there's a small risk you could still try to use the event log before the 
main thread attaches:

   // Initialize global data structures and create system classes in heap
   vm_init_globals();

#if INCLUDE_JVMCI
   if (JVMCICounterSize > 0) {
     JavaThread::_jvmci_old_thread_counters = NEW_C_HEAP_ARRAY(jlong, 
JVMCICounterSize, mtInternal);
     memset(JavaThread::_jvmci_old_thread_counters, 0, sizeof(jlong) * 
JVMCICounterSize);
   } else {
     JavaThread::_jvmci_old_thread_counters = NULL;
   }
#endif // INCLUDE_JVMCI

   // Attach the main thread to this os thread
   JavaThread* main_thread = new JavaThread();
   main_thread->set_thread_state(_thread_in_vm);
   main_thread->initialize_thread_current();
   // must do this before set_active_handles
   main_thread->record_stack_base_and_size();
   main_thread->register_thread_stack_with_NMT();
   main_thread->set_active_handles(JNIHandleBlock::allocate_block());

   if (!main_thread->set_as_starting_thread()) {
     vm_shutdown_during_initialization(
                                       "Failed necessary internal 
allocation. Out of swap space");
     main_thread->smr_delete();
     *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
     return JNI_ENOMEM;
   }

   // Enable guard page *after* os::create_main_thread(), otherwise it would
   // crash Linux VM, see notes in os_linux.cpp.
   main_thread->create_stack_guard_pages();

Fortunately the sequence of mprotect calls seems to be:
- initialize_assert_poison() (if enabled and a debug build)
- two via SafepointMechanism::initialize();
- main_thread->create_stack_guard_pages();  (around 10 calls in here)

So it appears that currently leaving the eventlog_init() where it is, 
and ensuring you don't log before initialization, that things will work 
okay. I have some reservations about what may be possible if the main 
thread takes a lock etc before its guard pages have been set up - but I 
think that should be safe. There may also be an issue if we take the 
vm_exit path - but as of now there are no mprotect calls if we do that.

David
-----

> V  [libjvm.so+0x18d000f]  VMError::report_and_die(Thread*, void*, char const*, int, char const*, char const*, __va_list_tag*)+0x2f
> V  [libjvm.so+0xa7f051]  report_vm_error(char const*, int, char const*, char const*, ...)+0x111
> V  [libjvm.so+0x136e04e]  Monitor::lock_without_safepoint_check()+0x1be
> V  [libjvm.so+0xaacf07]  Events::log(Thread*, char const*, ...)+0xe7
> V  [libjvm.so+0x140c18b]  linux_mprotect(char*, unsigned long, int)+0x12b
> V  [libjvm.so+0xa84197]  initialize_assert_poison()+0xc7
> V  [libjvm.so+0x1810322]  Threads::create_vm(JavaVMInitArgs*, bool*)+0x2b2
> V  [libjvm.so+0xf07b59]  JNI_CreateJavaVM+0x69
> C  [libjli.so+0x42b6]  JavaMain+0x86
> C  [libjli.so+0x8319]  ThreadJavaMain+0x9
> 
> Best regards, Matthias
> 


More information about the hotspot-dev mailing list