Skip to content

Error when calling go DLL from go using cgo #36157

Closed
@DaLynX

Description

@DaLynX

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

$ go version
go version go1.13.5 windows/amd64

Does this issue reproduce with the latest release?

I believe it is the latest release, so yes.

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

go env Output
$ go env
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\xxx\AppData\Local\go-build
set GOENV=C:\Users\xxx\AppData\Roaming\go\env
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\xxx\Documents\B - Dev\Go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Users\xxx\scoop\apps\go\current
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Users\xxx\scoop\apps\go\current\pkg\tool\windows_amd64
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\xxx\AppData\Local\Temp\go-build988957846=/tmp/go-build -gno-record-gcc-switches

What did you do?

I am trying to call a DLL made with go from another program in go.

DLL code

package main

import "fmt"
import "C"
import "unsafe"
import "syscall"

// MessageBox of Win32 API.
func MessageBox(hwnd uintptr, caption, title string, flags uint) int {
	ret, _, _ := syscall.NewLazyDLL("user32.dll").NewProc("MessageBoxW").Call(
		uintptr(hwnd),
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),
		uintptr(flags))

	return int(ret)
}

// MessageBoxPlain of Win32 API.
func MessageBoxPlain(title, caption string) int {
	const (
		NULL  = 0
		MB_OK = 0
	)
	return MessageBox(NULL, caption, title, MB_OK)
}

//export hello
func hello () {
	MessageBoxPlain("Hello", "Hello world!")
}

func main() {
	fmt.Println("main: Hello world!")
	hello()
}

Caller code

package main

// #include <Windows.h>
//
// typedef void (*pfunc)();
//
// void callfunc(pfunc pf)
// {
//		pf();
// }
import "C"
import "fmt"
import "os"

func main() {
	var hModule C.HINSTANCE
	var hProc C.FARPROC
	var dllname, procname string
	var cDLLName, cProcName *C.char

	dllname = os.Args[1]
	procname = os.Args[2]

	fmt.Println("[i] DLL file to be loaded:", dllname)
	cDLLName = C.CString(dllname)
	hModule = C.LoadLibrary(cDLLName)
	if hModule == nil {
		fmt.Println("[!] Error loading library.")
		return
	}
	fmt.Println("[i] Got hModule:", fmt.Sprintf("%p", hModule))

	fmt.Println("[i] Procedure to be called:", procname)
	cProcName = C.CString(procname)
	hProc = C.GetProcAddress(hModule, cProcName)
	if hProc == nil {
		fmt.Println("[!] Error finding procedure:", procname)
		return
	}
	fmt.Println("[i] Got procedure", procname, "at address:", fmt.Sprintf("%p", hProc))

	fmt.Printf("[i] Calling %s:\n>\t", procname)
	C.callfunc(hProc)
	fmt.Println("[i] Done.")

}

What did you expect to see?

I expected to see the following output in the console, and the Hello World dialog.

C:\Users\xxx\Documents\B - Dev\Go\bin>goCaller.exe hello.dll hello
[i] DLL file to be loaded: hello.dll
[i] Got hModule: 0x62400000
[i] Procedure to be called: hello
[i] Got procedure hello at address: 0x6249cb90
[i] Calling hello:
>       [i] Done.

What did you see instead?

I get the following output:

C:\Users\xxx\Documents\B - Dev\Go\bin>goCaller.exe hello.dll hello
[i] DLL file to be loaded: hello.dll
[i] Got hModule: 0x62400000
[i] Procedure to be called: hello
[i] Got procedure hello at address: 0x6249cb90
[i] Calling hello:
>       fatal error: unexpected signal during runtime execution
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x62456d38]

goroutine 1 [running, locked to thread]:
runtime.throw(0x624f0d48, 0x2a)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/panic.go:774 +0x79 fp=0xc0000898d8 sp=0xc0000898a8 pc=0x6242d469
runtime.sigpanic()
        C:/Users/xxx/scoop/apps/go/current/src/runtime/signal_windows.go:227 +0x25a fp=0xc000089908 sp=0xc0000898d8 pc=0x6243de6a
runtime.memmove(0x0, 0xc0000044e0, 0x1)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/memmove_amd64.s:146 +0x108 fp=0xc000089910 sp=0xc000089908 pc=0x62456d38
runtime.heapBitsSetType(0xc0000044e0, 0x20, 0x20, 0x624d7ae0)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/mbitmap.go:1400 +0x4bb fp=0xc000089a18 sp=0xc000089910 pc=0x62413d4b
runtime.mallocgc(0x20, 0x624d7ae0, 0x1, 0x0)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/malloc.go:1052 +0x57d fp=0xc000089ab8 sp=0xc000089a18 pc=0x6240becd
runtime.newobject(0x624d7ae0, 0x0)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/malloc.go:1151 +0x3f fp=0xc000089ae8 sp=0xc000089ab8 pc=0x6240c53f
syscall.NewLazyDLL(...)
        C:/Users/xxx/scoop/apps/go/current/src/syscall/dll_windows.go:269
main.MessageBox(0x0, 0x624ea697, 0xc, 0x624e9723, 0x5, 0x0, 0x0)
        C:/Users/xxx/Documents/B - Dev/Go/src/hello/main.go:10 +0x38 fp=0xc000089b58 sp=0xc000089ae8 pc=0x6249c938
main.MessageBoxPlain(...)
        C:/Users/xxx/Documents/B - Dev/Go/src/hello/main.go:25
main.hello(...)
        C:/Users/xxx/Documents/B - Dev/Go/src/hello/main.go:30
main._cgoexpwrap_d3a9d25dfce7_hello()
        _cgo_gotypes.go:45 +0x65 fp=0xc000089ba0 sp=0xc000089b58 pc=0x6249c8e5
runtime.call32(0x0, 0x93fc00, 0x93fd7f, 0x0)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/asm_amd64.s:539 +0x42 fp=0xc000089bd0 sp=0xc000089ba0 pc=0x62453c72
runtime.cgocallbackg1(0x0)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/cgocall.go:314 +0x1c5 fp=0xc000089cb8 sp=0xc000089bd0 pc=0x62403ff5
runtime.cgocallbackg(0x0)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/cgocall.go:191 +0xd5 fp=0xc000089d28 sp=0xc000089cb8 pc=0x62403d75
runtime: unexpected return pc for runtime.cgocallback_gofunc called from 0x454f57
stack: frame={sp:0xc000089d28, fp:0xc000089d48} stack=[0xc000082000,0xc00008a000)
000000c000089c28:  0000000000000000  0000000000000008
000000c000089c38:  000000c000089bd0  0000000062403fa3 <runtime.cgocallbackg1+371>
000000c000089c48:  00000000624f27a8  0000000000000000
000000c000089c58:  000000c000089f90  000000c000089c17
000000c000089c68:  0000000000000000  0000000000000000
000000c000089c78:  000000c000089ca8  00000000624361d3 <runtime.exitsyscall+435>
000000c000089c88:  000000c000036000  0000000200000003
000000c000089c98:  000000c000036000  000000c000036000
000000c000089ca8:  000000c000089d18  0000000062403d75 <runtime.cgocallbackg+213>
000000c000089cb8:  0000000000000000  0000000000000000
000000c000089cc8:  000000c00000a280  0000000000403e15
000000c000089cd8:  00007ffcac342900  0000000000000005
000000c000089ce8:  000000c0000896b8  0000000000000001
000000c000089cf8:  0000000000000000  0000000000000000
000000c000089d08:  000000c000089d50  000000c000036000
000000c000089d18:  000000000093fbc0  00000000624552d2 <runtime.cgocallback_gofunc+178>
000000c000089d28: <0000000000000000  0000000000582560
000000c000089d38:  000000c000089d50 !0000000000454f57
000000c000089d48: >0000000000403e39  000000000049d9b0
000000c000089d58:  000000c000089db8  0000000000000015
000000c000089d68:  0000000000000040  0000000000582560
000000c000089d78:  000000c000089da8  000000000049ceb8
000000c000089d88:  000000000049d9b0  000000c000089db8
000000c000089d98:  000000c00005e820  000000c000089db8
000000c000089da8:  000000c000089f50  000000000049d4aa
000000c000089db8:  000000006249cb90  000000c000006018
000000c000089dc8:  00000000004ecf8c  0000000000000012
000000c000089dd8:  000000c000089e80  0000000000000001
000000c000089de8:  0000000000000001  0000000000000015
000000c000089df8:  0000000000000000  0000000000000000
000000c000089e08:  0000000000000005  0000000000000009
000000c000089e18:  000000000000000a  000000c0000100f0
000000c000089e28:  000000006249cb90  0000000062400000
000000c000089e38:  000000c0000100e0  000000c000040220
runtime.cgocallback_gofunc(0x403e39, 0x49d9b0, 0xc000089db8, 0x15)
        C:/Users/xxx/scoop/apps/go/current/src/runtime/asm_amd64.s:793 +0xb2 fp=0xc000089d48 sp=0xc000089d28 pc=0x624552d2

goroutine 1 [runnable, locked to thread]:
syscall.getSystemDirectory(0x1c000064000, 0x104, 0x104, 0x1c000064000, 0x6246b30b)
        C:/Users/xxx/scoop/apps/go/current/src/syscall/zsyscall_windows.go:1921 +0xf6
syscall.init.0()
        C:/Users/xxx/scoop/apps/go/current/src/syscall/dll_windows.go:48 +0x73

It gets weirder!

If I replace the cgo code in the caller by the following, it works:

// #include <Windows.h>
//
// typedef void (*pfunc)();
//
// void callfunc(pfunc pf)
// {
//		MessageBox(0, "Calling...", "goCaller", 0);
//		pf();
// }
import "C"

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions