golang调用DLL,抛出0xc00000fd异常

213 views
Skip to first unread message

Hydra

unread,
Dec 17, 2014, 4:56:35 AM12/17/14
to golang...@googlegroups.com
大家好:
     我在GOLANG中调用C++写的DLL,导出的函数是STDCALL.调用过程中,DLL内部抛出0xc00000fd异常。
     昨天在golang-nuts发了同样的寻求,后来我把DLL内部的函数重构,跑起来后正常,以为解决了,但是今天多跑了几次后,发现还是遇到了这个异常。
     我在C++下写了测试程序去跑,一切都是正常的。
     今天试着分析是否是因为调度的原因导致的,我就用runtime.LockOSThread/UnlockOSThread,但是问题依旧存在。
     该怎么解决这个问题? 有没有朋友遇到同样的问题?

Hydra

unread,
Dec 17, 2014, 10:47:35 AM12/17/14
to golang...@googlegroups.com
问题解决了。是DLL内部的C++的对象体积巨大,导致编译器在编译的时候插入了_chkstk。然后我把该对象放到堆上构造,_chkstk没有了。

__chkstk触发的流程机制和GO的栈扩展有冲突?

在 2014年12月17日星期三UTC+8下午5时56分35秒,Hydra写道:

Hydra

unread,
Dec 17, 2014, 10:48:06 AM12/17/14
to golang...@googlegroups.com
http://www.cnblogs.com/concurrency/p/4170657.html
这是我的一个小总结。

在 2014年12月17日星期三UTC+8下午11时47分35秒,Hydra写道:

Doyle

unread,
Dec 17, 2014, 8:34:06 PM12/17/14
to golang...@googlegroups.com
感谢分享~

--
--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina
---
您收到此邮件是因为您订阅了Google网上论坛上的“Golang-China”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/5db46473-1a29-4446-ba6b-40d16ff8bccc%40googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

minux

unread,
Dec 17, 2014, 9:20:05 PM12/17/14
to Golang-China


On Dec 17, 2014 10:48 AM, "Hydra" <xxeag...@gmail.com> wrote:
> http://www.cnblogs.com/concurrency/p/4170657.html
> 这是我的一个小总结。
看了你的小结,有几个疑问要请教下:

1. “这个限制值目前是2000。如果超过就会抛出一个异常。这个是非常蛋疼的事情。而且从GO的ISSUE库里,这个问题的解决是一推再推。“  请问你说的是具体哪一个issue?我刚才翻了翻,没找到。

2. 通过 cgo 或者 syscall 调用 dll 的导出函数的时候,对应的函数都会在操作系统提供的堆栈上执行(所谓的 m stack),而不会在 Go 的堆栈上执行,所以我认为你对于 chkstk 导致程序崩溃的原因分析得不正确。

3. 这个问题为啥不报告一个bug?当然,你得用先化简你的代码并且提供一个具体的重现步骤。我不用VS,所以没办法重现你的问题。但是如果真的是用了 chkstk 的 dll 和 Go 不兼容的话,那或许真是 Go 的问题。值得报告一个bug。

Hydra

unread,
Dec 17, 2014, 9:54:14 PM12/17/14
to golang...@googlegroups.com
1. “这个限制值目前是2000。如果超过就会抛出一个异常。这个是非常蛋疼的事情。而且从GO的ISSUE库里,这个问题的解决是一推再推。“  请问你说的是具体哪一个issue?我刚才翻了翻,没找到。

我的想法是和1912里的观点一样,应该让用户回收掉这个CALLBACK。
但是2193里Alex说理应如此。
嗯,我夸大了事实...原谅我..

2. 通过 cgo 或者 syscall 调用 dll 的导出函数的时候,对应的函数都会在操作系统提供的堆栈上执行(所谓的 m stack),而不会在 Go 的堆栈上执行,所以我认为你对于 chkstk 导致程序崩溃的原因分析得不正确。

我去搞下。

3. 这个问题为啥不报告一个bug?当然,你得用先化简你的代码并且提供一个具体的重现步骤。我不用VS,所以没办法重现你的问题。但是如果真的是用了 chkstk 的 dll 和 Go 不兼容的话,那或许真是 Go 的问题。值得报告一个bug。

再次原谅我吧,我没有这个意识...

在 2014年12月18日星期四UTC+8上午10时20分05秒,minux写道:

Hydra

unread,
Dec 18, 2014, 12:19:19 AM12/18/14
to golang...@googlegroups.com
minux:
 
2. 通过 cgo 或者 syscall 调用 dll 的导出函数的时候,对应的函数都会在操作系统提供的堆栈上执行(所谓的 m stack),而不会在 Go 的堆栈上执行,所以我认为你对于 chkstk 导致程序崩溃的原因分析得不正确。

附件GoDll导出了两个函数,一个是Test,一个是TestEx 两者功能一样,只是TestEx把rapidxml::xml_document放到了堆上构造,而前者是栈上构造。
有一个简单的C++测试程序test,运行可以看到两个函数正常。
godll.go是一个加载并调用两个函数的测试代码。可以根据参数callex决定是否调用TestEx,在我机器上TestEx正常,Test出错。
另外还有两个xml,需要和godll.go编译的程序放在同一目录下。
C++代码编译环境是VS2013 UPDATE4
GO的版本是1.4 32位和64位都可以复现
OS版本是WIN7 SP1




在 2014年12月18日星期四UTC+8上午10时20分05秒,minux写道:
GoDll.zip

minux

unread,
Dec 18, 2014, 12:38:31 AM12/18/14
to Golang-China


On Dec 17, 2014 9:54 PM, "Hydra" <xxeag...@gmail.com> wrote:
> 1. “这个限制值目前是2000。如果超过就会抛出一个异常。这个是非常蛋疼的事情。而且从GO的ISSUE库里,这个问题的解决是一推再推。“  请问你说的是具体哪一个issue?我刚才翻了翻,没找到。
>
> https://code.google.com/p/go/issues/detail?id=1912 https://code.google.com/p/go/issues/detail?id=2193
> 我的想法是和1912里的观点一样,应该让用户回收掉这个CALLBACK。
> 但是2193里Alex说理应如此。
> 嗯,我夸大了事实...原谅我..

这俩issue不都关闭了么。callback是没办法回收的,Go怎么知道系统不会再调用某一个callback了呢?这个肯定只有用户才知道。

我说一下callback上限的原因。由于系统调用callback函数的时候不提供任何其他的参数,导致区分不同的callback只能通过被调用函数的地址,也就是说,一个Go的callback函数必须对应一个单独的C函数地址

旧的机制是对每个Go函数,在堆上动态构造一个对应的C函数。这样在 Go 1.1 之前的时候没问题,因为当时函数闭包也需要可执行的堆,但是 1.1 修改了函数的表示方式,闭包不再需要动态代码生成了,为了把 Windows 上也不再需要可执行的堆,必须想另外一个办法来实现 callback,新的机制参加 issue 5494,是我提议的。既然不动态生成代码,很明显的一个问题就是 callback 的总数会有一个上限。这是这有任何办法的了。

其实一般的 Windows 程序也不会有那么多 callback,2000个绝对是绰绰有余的;之所以 Go 这里很容易用光,是因为可能大家愿意使用 closure,而不是一个全局函数做 callback,使用全局函数做 callback (C/C++程序就是这么做的),2000个绝对是绰绰有余;但是由于闭包每次建立都是不同的,就算你其实就一个地方需要创建 callback,用闭包的话2000次就用光了所有的 callback。使用 callback 的时候建议用全局函数,也不要用 method,因为那样也是闭包,2000 个绝对足够足够。

Hydra

unread,
Dec 18, 2014, 12:52:23 AM12/18/14
to golang...@googlegroups.com
嗯嗯,所以我说到就是自己把CALLBACK弄成全局函数来用。
但是我真的想用闭包来搞,这样用起来更简洁。
难道不能提供FreeCallback这种东西么..

在 2014年12月18日星期四UTC+8下午1时38分31秒,minux写道:

minux

unread,
Dec 18, 2014, 1:02:33 AM12/18/14
to Golang-China
2014-12-18 0:52 GMT-05:00 Hydra <xxeag...@gmail.com>:
嗯嗯,所以我说到就是自己把CALLBACK弄成全局函数来用。
但是我真的想用闭包来搞,这样用起来更简洁。 
难道不能提供FreeCallback这种东西么..
曾经有,但是现在没提供的原因是不安全吧。

比如说,你 FreeCallback 了,然后又注册了一个新的 NewCallback,
由于种种原因,Windows 又调用了一次你的旧 callback,结果新注册
的函数被调用了。

这种 bug 一旦出现,很难查。考虑到 C/C++ 程序里,用全局函数做
callback 是没这个问题的,所以 Go 的 syscall 包也就不允许 free 了。

你可以试试建个 issue,要求 syscall.FreeCallback,看看 alex.brainman
和其他人怎么说。我对这个不是太确定(我的态度比较中立,让他们决定
吧……)

哦 有一个问题,注意到从 1.4 开始 syscall 包被冻结了。。。。发 issue
的时候最好直接说 go.sys/windows,而不是 syscall.

Hydra

unread,
Dec 18, 2014, 1:03:24 AM12/18/14
to golang...@googlegroups.com
FreeCallback这种事情不想了,确实不太合理。
还是老老实实的用全局函数,幸好很多API都提供传入user data指针。这个应该可以反转到GO下继续使用。就像C/C++下那么玩

在 2014年12月18日星期四UTC+8下午1时52分23秒,Hydra写道:

Hydra

unread,
Dec 18, 2014, 1:19:49 AM12/18/14
to golang...@googlegroups.com
不去提ISSUE了。现在这种情况更合理一些。

在 2014年12月18日星期四UTC+8下午2时02分33秒,minux写道:

minux

unread,
Dec 18, 2014, 3:09:32 AM12/18/14
to Golang-China
2014-12-18 0:19 GMT-05:00 Hydra <xxeag...@gmail.com>:
2. 通过 cgo 或者 syscall 调用 dll 的导出函数的时候,对应的函数都会在操作系统提供的堆栈上执行(所谓的 m stack),而不会在 Go 的堆栈上执行,所以我认为你对于 chkstk 导致程序崩溃的原因分析得不正确。

附件GoDll导出了两个函数,一个是Test,一个是TestEx 两者功能一样,只是TestEx把rapidxml::xml_document放到了堆上构造,而前者是栈上构造。
有一个简单的C++测试程序test,运行可以看到两个函数正常。
godll.go是一个加载并调用两个函数的测试代码。可以根据参数callex决定是否调用TestEx,在我机器上TestEx正常,Test出错。
另外还有两个xml,需要和godll.go编译的程序放在同一目录下。
C++代码编译环境是VS2013 UPDATE4
GO的版本是1.4 32位和64位都可以复现
OS版本是WIN7 SP1
我没有 VS,你能给我编译一个32位的 dll 么?我的测试环境是 xp。
(虚拟机,XP以上的系统太耗费资源了,我本来也不用 windows...)

Hydra

unread,
Dec 18, 2014, 3:23:54 AM12/18/14
to golang...@googlegroups.com
编译好的文件在附件。

在 2014年12月18日星期四UTC+8下午4时09分32秒,minux写道:
GoDll.zip

Hydra

unread,
Jan 4, 2015, 8:11:34 PM1/4/15
to golang...@googlegroups.com
原因及更有效的解决方法可以查看这里:https://github.com/golang/go/issues/9457

在 2014年12月17日星期三UTC+8下午11时47分35秒,Hydra写道:
Reply all
Reply to author
Forward
0 new messages