JDK-8320886 : Unsafe_SetMemory0 is not guarded
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 21,22
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2023-11-28
  • Updated: 2024-07-01
  • Resolved: 2023-12-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 22 JDK 23
22Fixed 23 b02Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
When accessing a memory mapped file that is truncated, we might get a SIGBUS error. We translate those errors into Java exceptions in order to avoid VM crashes. This is done by 'guarding' a memory access, which entails setting a thread-local flag to indicate we are doing an unsafe access. The signal handler then translates the SIGBUS into an exception when it sees that the flag is set.

This behavior was introduced as pat of: https://bugs.openjdk.org/browse/JDK-8191278

But, the original fix was not applied to Unsafe_SetMemory0. Hence, it is possible to get a SIGBUS VM crash when using setMemory through e.g. MemorySegment::fill. (See attached test changes):

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGBUS (0x7) at pc=0x00007f4f601afe6c, pid=30985, tid=31010
#
# JRE version: OpenJDK Runtime Environment (22.0) (fastdebug build 22-internal-2023-11-28-1136385.jvernee...)
# Java VM: OpenJDK 64-Bit Server VM (fastdebug 22-internal-2023-11-28-1136385.jvernee..., mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# C  [libc.so.6+0x18ee6c]
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E" (or dumping to /home/jvernee/jdk/open/build/linux-x64-debug/test-support/jtreg_test_hotspot_jtreg_runtime_Unsafe_InternalErrorTest_java/scratch/0/core.30985)
#

Comments
Hi Jorn, I created https://bugs.openjdk.org/browse/JDK-8322163 .
15-12-2023

[~mbaesken] Yes, thanks. That would be appreciated.
14-12-2023

Hi [~jvernee] Should I open a separate JBS issue for the 'bad behavior' on Alpine ?
14-12-2023

> With Unsafe calls I think it was possible to crash for many many years It's not about Unsafe. Unsafe is unsafe. However, when using a public Java API (in this case MemorySegment::fill) we should not be able to crash the JVM (unless we used a restricted API). Just like https://bugs.openjdk.org/browse/JDK-8191278 was a bug as well, I believe the fact that it's possible to crash the JVM through use of non-restricted public API on Alpine is a bug.
14-12-2023

> Disabling the test could work as an interim solution, but the crash should be addressed in the longer term, as it's still possible to trigger a crash using plain/public Java API. With Unsafe calls I think it was possible to crash for many many years - this is how I tested my hs_err file output extensions :-) ! stdout on Alpine for the test shows this : CompileCommand: exclude *InternalErrorTest.main bool exclude = true CompileCommand: inline *.get bool inline = true CompileCommand: inline *Unsafe.* bool inline = true # # A fatal error has been detected by the Java Runtime Environment: # So probably we can just skip the test part that causes the trouble (do not need to skip the whole test). when I google search alpine "memset" "sigsegv" it seems there are quite a few 'hits" so getting a SIGSEGV from memset seems to happen at other projects running on Alpine too (not sure why it happens here, maybe some 'speciality' of Alpine memset ?) .
14-12-2023

Disabling the test could work as an interim solution, but the crash should be addressed in the longer term, as it's still possible to trigger a crash using plain/public Java API. The test is disabled on Windows since that platform doesn't allow a memory-mapped file to be truncated, so there's no crash possible (the test fails with a Java exception when enabled on Windows) That note on Unsafe::setMemory is there for other methods in Unsafe as well. In general the caller should make sure that the call is safe. However, in the case of file truncation, it is not possible for the caller to make sure the access is safe, hence we have the current guarded access approach where we lazily translate signals into exceptions. One open question is: why is this failing with a SIGSEGV instead of a SIGBUS on Alpine?
13-12-2023

The guard is designed to work only for SIGBUS, but we're getting SIGSEGV on Alpine. I guess the failure is only triggered by the addition of the test case for "segment.fill((byte) 0xF0);" which uses memset in some cases. Note that the checks inside of setMemory are not required by the spec: * <em>Note:</em> It is the responsibility of the caller to make * sure arguments are checked before the methods are called. While * some rudimentary checks are performed on the input, the checks * are best effort and when performance is an overriding priority, * as when methods of this class are optimized by the runtime * compiler, some or all checks (if any) may be elided. Hence, the * caller must not rely on the checks and corresponding * exceptions! Not sure what the best solution for this problem is. We could handle SIGSEGV like SIGBUS. Or disable the test for Alpine. That is already done for Windows.
13-12-2023

[~mbaesken] How does Alpine handle file truncation issues with Unsafe.copyMemory/Unsafe.copySwapMemory? I think maybe a case on Alpine is missing that translates the SIGSEGV into an exception. Could you check if you still see the crashes if you run the same updated test without the changes in Unsafe_SetMemory0?
13-12-2023

Hi Jorn, since today we notice therese crashes on Alpine Linux, maybe related to JDK-8320886. test runtime/Unsafe/InternalErrorTest.java crashes on Alpine (works fine on other test OS/CPU platforms) : # # SIGSEGV (0xb) at pc=0x00007fd3c080064f, pid=7075, tid=7161 # # JRE version: OpenJDK Runtime Environment (23.0) (build 23-internal-adhoc.jenkinsi.jdk) # Java VM: OpenJDK 64-Bit Server VM (23-internal-adhoc.jenkinsi.jdk, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64) # Problematic frame: # C [ld-musl-x86_64.so.1+0x5464f] memset+0xa7 # backtrace : Stack: [0x00007fd35ceff000,0x00007fd35cfffa90], sp=0x00007fd35cffeb28, free space=1022k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [ld-musl-x86_64.so.1+0x5464f] memset+0xa7 j jdk.internal.misc.Unsafe.setMemory0(Ljava/lang/Object;JJB)V+0 java.base@23-internal j jdk.internal.misc.Unsafe.setMemory(Ljava/lang/Object;JJB)V+25 java.base@23-internal j jdk.internal.misc.ScopedMemoryAccess.setMemoryInternal(Ljdk/internal/foreign/MemorySessionImpl;Ljava/lang/Object;JJB)V+17 java.base@23-internal j jdk.internal.misc.ScopedMemoryAccess.setMemory(Ljdk/internal/foreign/MemorySessionImpl;Ljava/lang/Object;JJB)V+8 java.base@23-internal j jdk.internal.foreign.AbstractMemorySegmentImpl.fill(B)Ljava/lang/foreign/MemorySegment;+30 java.base@23-internal j InternalErrorTest.test(Ljava/nio/MappedByteBuffer;Ljdk/internal/misc/Unsafe;JJI)V+105 j InternalErrorTest.main([Ljava/lang/String;)V+231 j java.lang.invoke.LambdaForm$DMH+0x00007fd363002000.invokeStatic(Ljava/lang/Object;Ljava/lang/Object;)V+10 java.base@23-internal j ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????+33 java.base@23-internal j java.lang.invoke.Invokers$Holder.invokeExact_MT(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+20 java.base@23-internal j jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+55 java.base@23-internal j jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+23 java.base@23-internal j java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+102 java.base@23-internal j com.sun.javatest.regtest.agent.MainWrapper$MainTask.run()V+134 j java.lang.Thread.runWith(Ljava/lang/Object;Ljava/lang/Runnable;)V+5 java.base@23-internal j java.lang.Thread.run()V+19 java.base@23-internal v ~StubRoutines::call_stub 0x00007fd3aef6bcc4 V [libjvm.so+0x91e91b] JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x2db (javaCalls.cpp:415) V [libjvm.so+0x920282] JavaCalls::call_virtual(JavaValue*, Handle, Klass*, Symbol*, Symbol*, JavaThread*)+0x1c2 (javaCalls.cpp:329) V [libjvm.so+0xa0390c] [error occurred during error reporting (printing native stack (with source info)), id 0xb, SIGSEGV (0xb) at pc=0x00007fd3c07d2b8e]
13-12-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk22/pull/8 Date: 2023-12-11 19:19:59 +0000
11-12-2023

Changeset: ce4b257f Author: Jorn Vernee <jvernee@openjdk.org> Date: 2023-12-11 19:05:40 +0000 URL: https://git.openjdk.org/jdk/commit/ce4b257fa539d35a7d14bba2d5d3342093d714e1
11-12-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/16848 Date: 2023-11-28 12:09:12 +0000
28-11-2023

ILW = impact high: crash. likelihood medium: reliable crash with certain use of public API. workaround medium: don't access truncated part of file = P2
28-11-2023