英文:
Go, OpenAL, DirectSound and Heisenbug
问题
我已经花了一个星期的时间来解决我的一个项目中的一个神秘问题,但是我已经没有任何想法了。
我写了一个用于播放声音的Go包,它包装了OpenAL...非常基础的东西。我在我的Xubuntu 14.04(32位)上使其工作正常,所以我启动了Windows(7,也是32位)来进行移植...问题就从那时开始。
每当我尝试使用我的音频包时,程序就会崩溃并显示c0000005错误。我尝试通过gdb运行它,并惊讶地发现它可以正常工作,甚至播放我的测试声音。
时间过去了,不知道该怎么办,我下载了OpenAL Soft的源代码,并开始添加printf语句-并发现它崩溃的确切行:
http://repo.or.cz/w/openal-soft.git/blob/HEAD:/Alc/backends/dsound.c#l361
对于那些不想点击链接的人(或者链接停止工作的人),它是对DirectSoundCreate的调用。再次通过调试器运行,我看到了在调用之前和之后的打印输出,以及在它们之间创建了4个新线程。
这是Go文件中的相关内容:
package audio
/*
#cgo CFLAGS: -I"../libraries/include"
#cgo windows,386 LDFLAGS: ../libraries/lib/windows/x86/OpenAL32.dll
#cgo windows,amd64 LDFLAGS: ../libraries/lib/windows/x64/OpenAL32.dll
#cgo linux LDFLAGS: -lopenal
#include "audio.h"
*/
import "C"
import (
"errors"
)
var context *C.ALCcontext
func Init() error {
context = C.initAudio() // 它在这一行崩溃
if context == nil {
return errors.New("无法初始化音频")
}
SetActiveListener(NewListener())
return nil
}
这是实际进行OpenAL调用的C文件:
#include "audio.h"
#include <string.h>
#include <stdio.h>
ALCcontext* initAudio() {
ALCdevice* device = alcOpenDevice(NULL); // 在这里崩溃
if (device == NULL) {
return NULL;
}
ALCcontext* context = alcCreateContext(device, NULL);
if (!alcMakeContextCurrent(context)) {
return NULL;
}
return context;
}
最后但并非最不重要的是,如果我在纯C中做完全相同的事情(只需将main添加到我发布的文件中并调用initAudio
),它可以工作。
我的问题很明显:到底发生了什么?
编辑:
还有一些可能值得一提的事情:
我创建了一个与之前完全独立的新项目,在其中有我之前发布的两个文件(显然在Go文件中的链接器中有不同的路径)和只做一件事的主Go文件:调用audio.Init
。无论我尝试使用哪个dll(我尝试了http://openal.org上的“官方”版本,OpenAL Soft的预编译版本以及我自己编译的两个版本,一个使用MinGW,一个使用Visual Studio),它的行为都是相同的。我还尝试在audio.Init
的开头调用runtime.LockOSThread
,但没有帮助。
此外,我将编译好的程序发送给了我的两个朋友,一个运行Windows 8,一个运行Windows 7(都是64位)。Windows 8的朋友说它可以工作,Windows 7的朋友说它崩溃了。然而,如果我们在后者的机器上使用64位工具链从源代码编译它,它可以工作。
编辑2:
我刚刚尝试再次从源代码编译OpenAL Soft-首先使用Visual Studio,然后使用MinGW-然后将我之前提到的独立项目与库文件链接起来(使用VS的OpenAL32.lib和MinGW的libOpenAL32.dll.a,而不是直接使用DLL(因为那是...更正确的方式,我猜?)
使用VS的结果:
在链接过程中失败,显示以下消息:
# command-line-arguments
C:\Users\Milan\AppData\Local\Temp\go-build078751523/audiot/audio.a(_all.o): malf
ormed pe file: unexpected flags 0xe0500020 for PE section .text
audiot/audio._Cfunc_initAudio: undefined: _cgo_e0a3be4f138e_Cfunc_initAudio
使用MinGW的结果:
它成功编译和运行,并且虽然它没有阻止崩溃,但至少打印了一些输出:
fatal error: unexpected signal during runtime execution
[signal 0xc0000005 code=0x1 addr=0x420f85 pc=0x42874c]
runtime stack:
invalid spdelta 96655 -1
runtime: unexpected return pc for _cgo_ec587e40eeca_Cfunc_initAudio called from
0x42874800
runtime.throw(0x455dc0)
c:/go/src/pkg/runtime/panic.c:520 +0x71
runtime.sigpanic()
c:/go/src/pkg/runtime/os_windows.c:352 +0x46
invalid spdelta 96655 -1
runtime: unexpected return pc for _cgo_ec587e40eeca_Cfunc_initAudio called from
0x42874800
_cgo_ec587e40eeca_Cfunc_initAudio()
?:0 +0xc
goroutine 16 [syscall]:
runtime.cgocall(0x428740, 0x533f64)
c:/go/src/pkg/runtime/cgocall.c:143 +0xed fp=0x533f58 sp=0x533f2c
audiot/audio._Cfunc_initAudio(0x42e340)
audiot/audio/_obj/_cgo_defun.c:53 +0x37 fp=0x533f64 sp=0x533f58
audiot/audio.Init(0x0, 0x0)
C:/Users/Milan/Desktop/Dropbox/Projekty/Go/src/audiot/audio/at.go:23 +0x
3c fp=0x533f90 sp=0x533f64
main.main()
c:/Users/Milan/Desktop/Dropbox/Projekty/Go/src/audiot/main.go:10 +0x29 f
p=0x533f9c sp=0x533f90
runtime.main()
c:/go/src/pkg/runtime/proc.c:247 +0x11e fp=0x533fd0 sp=0x533f9c
runtime.goexit()
c:/go/src/pkg/runtime/proc.c:1445 fp=0x533fd4 sp=0x533fd0
created by _rt0_go
c:/go/src/pkg/runtime/asm_386.s:101 +0x102
goroutine 17 [syscall]:
runtime.goexit()
c:/go/src/pkg/runtime/proc.c:1445
exit status 2
我还认为将我的工具链的具体信息发布出来可能也没有坏处:
$ gcc --version
gcc.exe (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
$ go version
go version go1.3 windows/386
最后但并非最不重要的是Visual Studio 2013 Express。
英文:
I've already killed a week trying to solve a mysterious problem in a project of mine and I am out of ideas.
I wrote a Go package intended to play sounds which wraps OpenAL... pretty basic stuff. I got it working on my Xubuntu 14.04 (32-bit), so I booted into Windows (7, also 32-bit) in order to port it... and that's where the problems started.
Whenever I tried to use my audio package, the program crashed with c0000005. I tried to run it through gdb and was surprised to find out that it worked without a problem, it even played my test sound.
Time passed and not knowing what to do, I downloaded the OpenAL Soft source code and started adding printfs - and discovered the exact line it crashed on:
http://repo.or.cz/w/openal-soft.git/blob/HEAD:/Alc/backends/dsound.c#l361
For those lazy to click the link (or if the link stopped working), it's a call to DirectSoundCreate. Running through the debugger again, I saw my prints right before and after the call, and 4 new threads being created between them.
These are the relevant things in the Go file:
package audio
/*
#cgo CFLAGS: -I"../libraries/include"
#cgo windows,386 LDFLAGS: ../libraries/lib/windows/x86/OpenAL32.dll
#cgo windows,amd64 LDFLAGS: ../libraries/lib/windows/x64/OpenAL32.dll
#cgo linux LDFLAGS: -lopenal
#include "audio.h"
*/
import "C"
import (
"errors"
)
var context *C.ALCcontext
func Init() error {
context = C.initAudio() // it crashes on this line
if context == nil {
return errors.New("could not initialize audio")
}
SetActiveListener(NewListener())
return nil
}
And here's the C file actually making the OpenAL calls:
#include "audio.h"
#include <string.h>
#include <stdio.h>
ALCcontext* initAudio() {
ALCdevice* device = alcOpenDevice(NULL); // crashes here
if (device == NULL) {
return NULL;
}
ALCcontext* context = alcCreateContext(device, NULL);
if (!alcMakeContextCurrent(context)) {
return NULL;
}
return context;
}
Last but not least, if I do the exact same thing in pure C (literally just adding main into the file I posted and calling initAudio
), it works.
My question is obvious: What the #@!$ is going on?
edit:
Some other things which might be worth mentioning:
I created a new project completely separate from the previous one, in which I have the two files I posted earlier (with different paths for the linker in the Go file, obviously) and the main Go file which does only one thing: call audio.Init
. Regardless of which dll I try (I tried the "official" one from http://openal.org, the precompiled version of OpenAL Soft and two versions I compiled myself, one with MinGW and one with Visual Studio), it behaves the same. I also tried to call runtime.LockOSThread
at the start of audio.Init
, but it didn't help.
Also, I sent the compiled program to my two friends, one running Windows 8 and one with Windows 7 (both 64-bit). The one with Windows 8 said it worked, the one with 7 said it crashed. However, if we tried to compile it from source on the latter machine, with the 64-bit toolchain, it worked.
edit #2:
I just tried to compile OpenAL Soft from source again - first with Visual Studio and then with MinGW - and then link my independent project I mentioned earlier with the library files (OpenAL32.lib from VS and libOpenAL32.dll.a from MinGW) instead of the DLL directly (since that is... the more correct way I guess?)
The result with VS:
It failed during linking, with the following message:
# command-line-arguments
C:\Users\Milan\AppData\Local\Temp\go-build078751523/audiot/audio.a(_all.o): malf
ormed pe file: unexpected flags 0xe0500020 for PE section .text
audiot/audio._Cfunc_initAudio: undefined: _cgo_e0a3be4f138e_Cfunc_initAudio
The result with MinGW:
It succeeded to compile and run, and while it didn't prevent the crash, at least it printed something out:
fatal error: unexpected signal during runtime execution
[signal 0xc0000005 code=0x1 addr=0x420f85 pc=0x42874c]
runtime stack:
invalid spdelta 96655 -1
runtime: unexpected return pc for _cgo_ec587e40eeca_Cfunc_initAudio called from
0x42874800
runtime.throw(0x455dc0)
c:/go/src/pkg/runtime/panic.c:520 +0x71
runtime.sigpanic()
c:/go/src/pkg/runtime/os_windows.c:352 +0x46
invalid spdelta 96655 -1
runtime: unexpected return pc for _cgo_ec587e40eeca_Cfunc_initAudio called from
0x42874800
_cgo_ec587e40eeca_Cfunc_initAudio()
?:0 +0xc
goroutine 16 [syscall]:
runtime.cgocall(0x428740, 0x533f64)
c:/go/src/pkg/runtime/cgocall.c:143 +0xed fp=0x533f58 sp=0x533f2c
audiot/audio._Cfunc_initAudio(0x42e340)
audiot/audio/_obj/_cgo_defun.c:53 +0x37 fp=0x533f64 sp=0x533f58
audiot/audio.Init(0x0, 0x0)
C:/Users/Milan/Desktop/Dropbox/Projekty/Go/src/audiot/audio/at.go:23 +0x
3c fp=0x533f90 sp=0x533f64
main.main()
c:/Users/Milan/Desktop/Dropbox/Projekty/Go/src/audiot/main.go:10 +0x29 f
p=0x533f9c sp=0x533f90
runtime.main()
c:/go/src/pkg/runtime/proc.c:247 +0x11e fp=0x533fd0 sp=0x533f9c
runtime.goexit()
c:/go/src/pkg/runtime/proc.c:1445 fp=0x533fd4 sp=0x533fd0
created by _rt0_go
c:/go/src/pkg/runtime/asm_386.s:101 +0x102
goroutine 17 [syscall]:
runtime.goexit()
c:/go/src/pkg/runtime/proc.c:1445
exit status 2
I also thought it can't hurt to post the specifics of my toolchain:
$ gcc --version
gcc.exe (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
$ go version
go version go1.3 windows/386
And let's not forget Visual Studio 2013 Express
答案1
得分: 3
我刚刚得知Go 1.3.1发布了,所以我尝试更新...然后问题就消失了。(啊!)
我猜这可能是一个编译器的错误。不管怎样,感谢所有尝试帮助我的人,我非常感激。
英文:
I just learnt Go 1.3.1 came out, so I tried updating... and the problem disappeared. (argh!)
I guess it was a compiler bug then. Anyway, thanks to everyone who tried to help, I really appreciate it.
答案2
得分: 2
可能与线程切换有关:
解决方案可能是使用LockOSThread函数
http://golang.org/pkg/runtime/#LockOSThread
你可以在这里阅读更多相关信息:
https://code.google.com/p/go-wiki/wiki/LockOSThread
另外,如果你正在尝试初始化库,你的Init
函数应该是小写的。
英文:
It might be related to Thread Switching:
The solution could be to use LockOSThread
http://golang.org/pkg/runtime/#LockOSThread
You can read more about it here:
https://code.google.com/p/go-wiki/wiki/LockOSThread
Also your Init
function has capital I
if you are trying to initialize the library it has to be lower case.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论