运行时:在Windows上使用"JNI_CreateJavaVM"创建JVM时,Go程序崩溃,

blmhpbnm  于 5个月前  发布在  Go
关注(0)|答案(8)|浏览(51)

你正在使用的Go版本是什么(go version)?

$ go version
go version go1.20 windows/amd64

这个问题在最新版本的发布中是否会重现?
是的

你正在使用什么操作系统和处理器架构(go env)?
go env 输出

$ go env
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\green\AppData\Local\go-build
set GOENV=C:\Users\green\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\green\go\pkg\mod
set GONOPROXY=github.com/MetaFFI/*,github.com/GreenFuze/*
set GONOSUMDB=github.com/MetaFFI/*,github.com/GreenFuze/*
set GOOS=windows
set GOPATH=C:\Users\green\go
set GOPRIVATE=github.com/MetaFFI/*,github.com/GreenFuze/*
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.20
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=NUL
set GOWORK=
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=c:\temp\go-build2999029303=/tmp/go-build -gno-record-gcc-switches

你做了什么?
当"runtime/signal_windows.go:168"中的"var testingWER bool"为false时,以下代码会在运行时崩溃。

package main

/*
#include <Windows.h>
#include <stdio.h>

typedef struct JavaVMInitArgs {
    int version;

    int nOptions;
    void *options;
    unsigned char ignoreUnrecognized;
} JavaVMInitArgs;

void create_jvm()
{
	HMODULE h = LoadLibrary("C:\\Program Files\\Microsoft\\jdk-11.0.18.10-hotspot\\bin\\server\\jvm.dll");
	void* create = GetProcAddress(h, "JNI_CreateJavaVM");

	JavaVMInitArgs vm_args;
    vm_args.version = 0x000a0000; //JNI_VERSION_10
    vm_args.nOptions = 0;
    vm_args.options = 0;
    vm_args.ignoreUnrecognized = 0;

    void* pjvm = 0;
    void* penv = 0;

	printf("Before calling JNI_CreateJavaVM\r\n");
    ((void(*)(void**, void**, JavaVMInitArgs*))create)(&pjvm, &penv, &vm_args);
	printf("After calling JNI_CreateJavaVM\r\n");
}
*/
import "C"

func main(){
	C.create_jvm();
}

将"var testingWER bool"更改为true,使应用程序正常工作。

你期望看到什么?
它不会崩溃

你看到了什么?
JNI_CreateJavaVM因ACCESS_VIOLATION而崩溃。

解决方案建议
问题在于由JNI(并被其捕获)生成的ACCESS_VIOLATION没有被捕获,原因是Go没有继续异常搜索(即_EXCEPTION_CONTINUE_SEARCH)。
将Go修补为"testingWER=true"强制Go继续搜索,允许JNI处理错误。
作为短期解决方案,我建议将"testingWER"设置为公共变量,这样开发人员可以在不修补Go的情况下解决意外问题。
作为长期解决方案,如果Go模块是库或存档,则signal_windows.go应返回_EXCEPTION_CONTINUE_SEARCH。我建议执行以下操作之一:

  1. 如果正在使用CGo,则返回_EXCEPTION_CONTINUE_SEARCH,因为走出"Go运行时"可能需要自定义异常处理。
  2. 为用户提供一个函数来替换signal_windows.go中的"lastcontinuehandler",用他们自己的。我认为这是最佳选项,因为我们在Go意识到无法处理异常之后才达到这一点,所以让用户采取一些行动。您还可以将引发异常的代码(winthrow()函数)作为参数传递给用户的自定义"lastcontinuehandler"。
csbfibhn

csbfibhn1#

(CC @golang/windows)

huwehgph

huwehgph4#

在版本go1.21.1中,测试WER已被移除,但JVM仍然崩溃。目前我无法找到使用JNI_CreateJavaVM在Windows上加载JVM的解决方法。有人能提供一个解决方案吗?

66bbxpm5

66bbxpm55#

我有一些CL(CL 525475CL 457875)正在飞行,它们将教导Go运行时在异常被捕获并由SEH异常处理程序处理时不崩溃。这应该解决了你的问题。

有人能提供一个解决方法吗?

如果你之前修补过Go,我建议你继续这样做,即重新添加testingWER

oiopk7p5

oiopk7p56#

你好,
我想问一下,在不久的将来的GO版本中是否会修复上述提到的问题?
感谢更新。

f3temu5u

f3temu5u7#

尚未,我无法及时降落CL 457875,因为我被SEH机器中的一个重要缺失部分所分心(参见CL 534555)。我的计划是在go 1.23中解决这个问题。

bjp0bcyl

bjp0bcyl8#

https://go.dev/cl/457875提到了这个问题:runtime,cmd/link: use SEH instead of vectored exception handlers

相关问题