JVM crashes in JIT compiled code without hs_err_pid file

Alexandr Miloslavskiy alexandr.miloslavskiy at syntevo.com
Sun Feb 19 15:57:21 UTC 2023


Hi Thomas,

 > someone in the process may have established a competing signal 
handler via AddVectoredExceptionHandler

I tested it and you were right, if 'AddVectoredExceptionHandler()' is 
present then it's called instead of 'RtlAddFunctionTable()'.
See attached code for a demo.

I'll try to figure if this was the case for the customer.

 > Possibility 2: registering code cache did not work

Sounds unlikely, because in the dump, I can see that it's registered 
(when a dump is created, it also collects all function tables). Also, in 
such case, application wouldn't run longer than a second or two before 
crashing.
-------------- next part --------------
#include <windows.h>
#include <stdio.h>
#include <stdint.h>

#pragma comment(linker, "/SUBSYSTEM:console /ENTRY:mainCRTStartup")

LONG FunctionableHandler(IN PEXCEPTION_RECORD ExceptionRecord, IN ULONG64 EstablisherFrame, IN OUT PCONTEXT ContextRecord, IN OUT PDISPATCHER_CONTEXT DispatcherContext)
{
	printf(
		"FunctionableHandler: exception %08X at %p\n",
		ExceptionRecord->ExceptionCode,
		ExceptionRecord->ExceptionAddress
	);

	TerminateProcess(GetCurrentProcess(), 0);
	return 0;
}

LONG VectoredExceptionHandler(_EXCEPTION_POINTERS *ExceptionInfo)
{
	printf(
		"VectoredExceptionHandler: exception %08X at %p\n",
		ExceptionInfo->ExceptionRecord->ExceptionCode,
		ExceptionInfo->ExceptionRecord->ExceptionAddress
	);

	TerminateProcess(GetCurrentProcess(), 0);
	return 0;
}

// Same as in OpenJDK
typedef unsigned char UBYTE; 
typedef struct _UNWIND_INFO_EH_ONLY {
	UBYTE Version : 3;
	UBYTE Flags : 5;
	UBYTE SizeOfProlog;
	UBYTE CountOfCodes;
	UBYTE FrameRegister : 4;
	UBYTE FrameOffset : 4;
	union {
		OPTIONAL ULONG ExceptionHandler;
		OPTIONAL ULONG FunctionEntry;
	};
	OPTIONAL ULONG ExceptionData[1];
} UNWIND_INFO_EH_ONLY, *PUNWIND_INFO_EH_ONLY;

struct CodePageContents
{
	UNWIND_INFO_EH_ONLY	unwind;
	RUNTIME_FUNCTION	runtimeFunction;
	uint8_t				exceptionHandlerCode[16];
	uint8_t				jitCode[64];
};

typedef void (*PlainFunction)();

PlainFunction createJitCode()
{
	const uint32_t codePageSize = 0x1000;
	CodePageContents* memoryPage = (CodePageContents*)VirtualAlloc(0, codePageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	
	// Set up exception handling
	{
		UNWIND_INFO_EH_ONLY* punwind = &memoryPage->unwind;
		punwind->Version			= 1;
		punwind->Flags				= UNW_FLAG_EHANDLER;
		punwind->SizeOfProlog		= 0;
		punwind->CountOfCodes		= 0;
		punwind->FrameRegister		= 0;
		punwind->FrameOffset		= 0;
		punwind->ExceptionHandler	= (ULONG)((char*)memoryPage->exceptionHandlerCode - (char*)memoryPage);
		punwind->ExceptionData[0]	= 0;

		RUNTIME_FUNCTION* prt = &memoryPage->runtimeFunction;
		prt->BeginAddress			= 0;
		prt->EndAddress				= codePageSize;
		prt->UnwindData				= (DWORD)((char*)&memoryPage->unwind - (char*)memoryPage);

		RtlAddFunctionTable(prt, 1, (DWORD64)memoryPage);

		uint8_t* code = memoryPage->exceptionHandlerCode;
		
		// mov rax, FunctionableHandler
		code[0] = 0x48;
		code[1] = 0xb8;
		code += 2;
		*(uint64_t*)code = (uint64_t)FunctionableHandler;
		code += 8;

		// jmp rax
		code[0] = 0xff;
		code[1] = 0xe0;
	}

	// "JIT" code
	{
		uint8_t* code = memoryPage->jitCode;

		// xor eax, eax
		code[0] = 0x31;
		code[1] = 0xc0;
		code += 2;

		// mov eax,DWORD PTR [eax] 
		code[0] = 0x67;
		code[1] = 0x8b;
		code[2] = 0x00;
		code += 3;
	}

	return (PlainFunction)&memoryPage->jitCode;
}

int main()
{
	PlainFunction function = createJitCode();

	// Comment/uncomment as needed
	AddVectoredExceptionHandler(TRUE, VectoredExceptionHandler);

	// Run "jit" code and crash
	function();

	return 0;
}


More information about the hotspot-compiler-dev mailing list