Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: .NET / Golang Interop - Go catching .NET exceptions #30417

kfreezen opened this issue Feb 26, 2019 · 4 comments

runtime: .NET / Golang Interop - Go catching .NET exceptions #30417

kfreezen opened this issue Feb 26, 2019 · 4 comments


Copy link

@kfreezen kfreezen commented Feb 26, 2019

What version of Go are you using (go version)?

$ go version
go version go1.12 windows/amd64

Does this issue reproduce with the latest release?


What operating system and processor architecture are you using (go env)?

go env Output
$ go env
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\Kent\AppData\Local\go-build
set GOEXE=.exe
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=C:\Users\Kent\go
set GOROOT=C:\Go
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\Kent\AppData\Local\Temp\go-build993497478=/tmp/go-build -gno-record-gcc-switches

What did you do?

Ran a C# console application that interacts with a CGO DLL. The code of the .NET program is below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace SampleGoInterop
    class Program
        public delegate void CallbackDelegate(long handle);

        [DllImport("sample-dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
        public static extern void RunCallback();

        [DllImport("sample-dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
        public static extern void SetCallback(CallbackDelegate func);

        static void Callback(long handle)
                Console.WriteLine("Callback() is called");

                int i = 0;

                i /= 0;
            catch (Exception ex)
                Console.WriteLine("We've recovered!");

        static void Main(string[] args)
            SetCallback(new CallbackDelegate(Callback));


What did you expect to see?

Callback() is called
We've recovered!

What did you see instead?

Callback() is called
Exception 0xc0000094 0x0 0x0 0x7fff54d811f0
signal arrived during external code execution

main._Cfunc_FireCallback(0x267d37e08cc, 0x13371337deadbeef)
        _cgo_gotypes.go:43 +0x4c
        E:/code/sample-dll/main.go:31 +0x73
        E:/code/sample-dll/main.go:31 +0x3a
        _cgo_gotypes.go:74 +0x27
rax     0x0
rbx     0xc00003fe48
rcx     0x7ffef5780825
rdi     0x91e85be4e0
rsi     0x13371337deadbeef
rbp     0x91e85be4f0
rsp     0x91e85be4a0
r8      0x267bae45bec
r9      0x0
r10     0x91e85be448
r11     0x267b94be840
r12     0x267b94be840
r13     0x91e85be9c0
r14     0x91e85bea38
r15     0x4
rip     0x7fff54d811f0
rflags  0x10246
cs      0x33
fs      0x53
gs      0x2b

I know this is a really rare case, but is there any way we can make .NET exception handling work without having to make local changes to the Golang runtime?

Local changes are in signal_windows.go -- func lastcontinuehandler()

if testingWER {


// ... rest of function ...
Copy link

@agnivade agnivade commented Feb 27, 2019

/cc @ianlancetaylor

Btw, did you intentionally change the value of rsi ?

@ianlancetaylor ianlancetaylor changed the title .NET / Golang Interop - Go catching .NET exceptions runtime: .NET / Golang Interop - Go catching .NET exceptions Feb 27, 2019
Copy link

@ianlancetaylor ianlancetaylor commented Feb 27, 2019

The last time I looked into this, which was three years ago, I couldn't get anything to work. See #12516. It ought to be possible, but I didn't have the patience to figure it out.

We should probably close this as a dup of #12516, unless anybody sees a relevant difference.

Copy link

@kfreezen kfreezen commented Feb 27, 2019

@agnivade, no I did not. RunCallback() in the go portion of the code passes 0x13371337deadbeef as the handle. I hadn't noticed that value in rsi, which makes me wonder: What in the world is the right calling convention to use in my P/Invoke statements? I haven't noticed any differences between cdecl and stdcall.

@ianlancetaylor Yes this issue looks like a dup to me. The environment's a bit different, but it's still the same issue.

What would an acceptable fix be? I've thought about adding a simple flag that people using Go in a DLL can set to disable Go panics on exceptions like these, but it probably isn't the right fix.

Copy link

@ianlancetaylor ianlancetaylor commented Feb 27, 2019

I think the right fix is for Go's exception handler to pass the exception along to C code, rather than panic. It tries to do that today but apparently it doesn't work.

Closing this issue as a dup.

@golang golang locked and limited conversation to collaborators Feb 27, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants