8310228: Improve error reporting for uncaught native exceptions on Windows

Reviewed-by: dholmes, djelinski
This commit is contained in:
Jorn Vernee 2023-09-21 13:54:35 +00:00
parent 349723cb8d
commit 38bf1192b6
4 changed files with 140 additions and 22 deletions

View File

@ -1504,6 +1504,8 @@ else
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libCompleteExit += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libnativeStack += -lpthread
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeGetCreatedJavaVMs := -ljvm -lpthread
BUILD_HOTSPOT_JTREG_EXCLUDE += libNativeException.c
endif
ifeq ($(ASAN_ENABLED), true)

View File

@ -280,10 +280,12 @@ void os::run_periodic_checks(outputStream* st) {
return;
}
#ifndef _WIN64
// previous UnhandledExceptionFilter, if there is one
static LPTOP_LEVEL_EXCEPTION_FILTER prev_uef_handler = nullptr;
#endif
LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo);
static LONG WINAPI Uncaught_Exception_Handler(struct _EXCEPTION_POINTERS* exceptionInfo);
void os::init_system_properties_values() {
// sysclasspath, java_home, dll_dir
@ -397,7 +399,7 @@ void os::init_system_properties_values() {
#ifndef _WIN64
// set our UnhandledExceptionFilter and save any previous one
prev_uef_handler = SetUnhandledExceptionFilter(Handle_FLT_Exception);
prev_uef_handler = SetUnhandledExceptionFilter(Uncaught_Exception_Handler);
#endif
// Done
@ -2534,9 +2536,7 @@ LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
#if defined(_M_AMD64) || defined(_M_IX86)
//-----------------------------------------------------------------------------
LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
PCONTEXT ctx = exceptionInfo->ContextRecord;
#ifndef _WIN64
static bool handle_FLT_exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
// handle exception caused by native method modifying control word
DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode;
@ -2547,34 +2547,48 @@ LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_FLT_UNDERFLOW: {
PCONTEXT ctx = exceptionInfo->ContextRecord;
#ifndef _WIN64
jint fp_control_word = (* (jint*) StubRoutines::x86::addr_fpu_cntrl_wrd_std());
if (fp_control_word != ctx->FloatSave.ControlWord) {
// Restore FPCW and mask out FLT exceptions
ctx->FloatSave.ControlWord = fp_control_word | 0xffffffc0;
// Mask out pending FLT exceptions
ctx->FloatSave.StatusWord &= 0xffffff00;
return EXCEPTION_CONTINUE_EXECUTION;
return true;
}
#else // !_WIN64
// On Windows, the mxcsr control bits are non-volatile across calls
// See also CR 6192333
//
jint MxCsr = INITIAL_MXCSR;
// we can't use StubRoutines::x86::addr_mxcsr_std()
// because in Win64 mxcsr is not saved there
if (MxCsr != ctx->MxCsr) {
ctx->MxCsr = MxCsr;
return true;
}
#endif // !_WIN64
}
}
return false;
}
#endif
#ifndef _WIN64
static LONG WINAPI Uncaught_Exception_Handler(struct _EXCEPTION_POINTERS* exceptionInfo) {
if (handle_FLT_exception(exceptionInfo)) {
return EXCEPTION_CONTINUE_EXECUTION;
}
// we only override this on 32 bits, so only check it there
if (prev_uef_handler != nullptr) {
// We didn't handle this exception so pass it to the previous
// UnhandledExceptionFilter.
return (prev_uef_handler)(exceptionInfo);
}
#else // !_WIN64
// On Windows, the mxcsr control bits are non-volatile across calls
// See also CR 6192333
//
jint MxCsr = INITIAL_MXCSR;
// we can't use StubRoutines::x86::addr_mxcsr_std()
// because in Win64 mxcsr is not saved there
if (MxCsr != ctx->MxCsr) {
ctx->MxCsr = MxCsr;
return EXCEPTION_CONTINUE_EXECUTION;
}
#endif // !_WIN64
return EXCEPTION_CONTINUE_SEARCH;
}
@ -2831,9 +2845,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
}
#if defined(_M_AMD64) || defined(_M_IX86)
if ((in_java || in_native) && exception_code != EXCEPTION_UNCAUGHT_CXX_EXCEPTION) {
LONG result=Handle_FLT_Exception(exceptionInfo);
if (result==EXCEPTION_CONTINUE_EXECUTION) return result;
if ((in_java || in_native) && handle_FLT_exception(exceptionInfo)) {
return EXCEPTION_CONTINUE_EXECUTION;
}
#endif

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test id
* @enablePreview
* @requires os.family == "windows"
* @library /test/lib
* @run testng UncaughtNativeExceptionTest
*/
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import org.testng.annotations.Test;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.regex.Pattern;
import static org.testng.Assert.assertTrue;
public class UncaughtNativeExceptionTest {
private static class Crasher {
public static void main(String[] args) throws Throwable {
System.loadLibrary("NativeException");
throwException();
}
static native void throwException();
}
// check that we actually report the native exception,
// and don't terminate abruptly due to stack overflow error
@Test
public void testNativeExceptionReporting() throws Exception {
OutputAnalyzer output = ProcessTools.executeTestJvm(
// executeTestJvm doesn't seem to forward 'java.library.path'
"-Djava.library.path=" + System.getProperty("java.library.path"),
Crasher.class.getName());
File hsErrFile = HsErrFileUtils.openHsErrFileFromOutput(output);
Path hsErrPath = hsErrFile.toPath();
assertTrue(Files.exists(hsErrPath));
Pattern[] positivePatterns = {
Pattern.compile(".*Internal Error \\(0x2a\\).*")
};
HsErrFileUtils.checkHsErrFileContent(hsErrFile, positivePatterns, null, true /* check end marker */, false /* verbose */);
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <jni.h>
#include <Windows.h>
const DWORD EX_CODE = 42;
JNIEXPORT void JNICALL Java_UncaughtNativeExceptionTest_00024Crasher_throwException(JNIEnv* env, jclass cls) {
RaiseException(EX_CODE, EXCEPTION_NONCONTINUABLE, 0, NULL);
}