-
Notifications
You must be signed in to change notification settings - Fork 18k
runtime: go1.5beta1 on Windows 64 with CGO: signal arrived during external code execution #11710
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
Comments
Oh, and there is no need for an Oracle database, the error happens before trying to connect. |
The error message suggests that the C code is calling a NULL pointer. |
As far as I can tell this is what is expected to happen when an exception occurs with PC == 0. I don't know if PC == 0 is correct, and I don't know what has changed here since Go 1.4. |
Your program raised EXCEPTION_ACCESS_VIOLATION exception somewhere inside your C WrapOCIEnvCreate function. EXCEPTION_ACCESS_VIOLATION means memory access error - most common would be dereferencing 0 pointer. You can try and debug this yourself - just insert extra printf statements inside of WrapOCIEnvCreate to try and understand what is happening. Is error happening in WrapOCIEnvCreate? Or is it happening inside external OCIEnvCreate function? If it happens inside of OCIEnvCreate, print its parameters and make sure they are correct. Alex |
I did some investigating, but first a small disclamier: I have very little knowledge of C and CGO, so I might be missing something obvious. Ok, I'm using go-oci8 to debug, and the function that is causing the error is this: https://github.com/mattn/go-oci8/blob/master/oci8.go#L142-161 I modified it to print values that are passed to OCIEnvCreate: static ret2ptr
WrapOCIEnvCreate(ub4 mode, size_t extra) {
ret2ptr vvv = {NULL, NULL, 0};
void *ptr;
if (extra == 0) {
ptr = NULL;
} else {
ptr = &vvv.extra;
}
printf("OciEnv: %p\n", (OCIEnv**)(&vvv.ptr));
printf("Mode: %d\n", mode);
printf("Extra: %d\n", extra);
printf("Extra Ptr: %p\n", ptr);
vvv.rv = OCIEnvCreate(
(OCIEnv**)(&vvv.ptr),
mode,
NULL,
NULL,
NULL,
NULL,
extra,
ptr);
printf("worked\n");
return vvv;
} And this is the output: Go 1.5:
Go 1.4:
Apparently the parameters are passed correctly. The problem is on the line that calls OCIEnvCreate, however I monitored calls to API using a program called API Monitor V2, and while the 1.4 version shows the DLL being called, the 1.5 version shows nothing. So the problem is most likely inside the C code in oci8.go. I also tried forcing an error passing an invalid parameter in 1.4, but I got a treated message from this code block: if rv := C.WrapOCIEnvCreate(
C.OCI_DEFAULT|C.OCI_THREADED,
0); rv.rv != C.OCI_SUCCESS && rv.rv != C.OCI_SUCCESS_WITH_INFO {
// TODO: error handle not yet allocated, we can't get string error from oracle
return nil, errors.New("can't OCIEnvCreate") And the call is also shown in API Monitor. Is there anything else I can do to help identify the problem? In the meantime I'll see if I can simulate it with a simpler DLL call. |
Unfortunately I don't know how to help you. In go1.5 cgo changed considerably. Go used to always link final executable, but now it calls gcc if you use cgo. I don't know much about gcc. You can revert to old way of linking by asking go command to use "internal" linker. I think you need to say:
Another alternative might be to use my github.com/alexbrainman/odbc driver. I haven't used it for Oracle. But I don't see why it wouldn't work. Another option would be for you to call into Oracle DLL directly with syscall.Syscall. Probably too much work if you start from scratch. But you never know. I also wouldn't give up on what you have. There might be bugs in the library you use. Make your example as small as possible. Check that things work every step of the way (you have call monitor, check all values are passed and returned correctly and so on). And add things slowly. Alex |
@alexbrainman I tried your first suggestion linking using the -linkmode flag and it worked:
The strange thing is that in one of my machines it started working all of a sudden, even if I don't pass the -linkmode flag. I tried forcing external and internal and both work. I created a simpler package that only calls this first method of the OCI.dll, but I am still trying to get consistent results. As for ODBC, my application needs to query and format up to 5 million database rows as fast as possible. Right now the speed is around 35k rows per second, and from my previous experience I don't think ODBC will come even close to that. But I will try your driver, it might surprise me. |
I created a very simple application that reproduces the problem with no external dependencies. To test it:
|
Sure I will try it. Thank you. Alex |
@ricsmania Thanks for that very small program. It is possible that what has changed is whether the cgo call executes in the main (program startup) thread. Perhaps the OCI DLL requires that the call be started from the main thread. If you put func init() { in your program, then func main will be forced to run in the main OS thread. It would be interesting to see if that changes the behavior reliably. |
@rsc Thanks for your suggestion. Unfortunately nothing changed, I still get the error. |
That does not build on my pc:
Alex |
you may need to put oci8.pc in your $PKG_CONFIG_PATH. |
@alexbrainman could you please try setting CGO_CFLAGS and CGO_LDFLAGS to an absolute path before building? set CGO_CFLAGS=-I%GOPATH%\github.com\ricsmania\ocitest Thanks |
Still get the same error message:
Alex |
@alexbrainman I'm sorry, I forgot a part, the path should be set CGO_LDFLAGS=-LC:\dev\src\github.com\ricsmania\ocitest\oracle They should point to the folder that has oci.dll and several .h files. |
Also, after building you will probably have to add this same path to your %PATH% before executing. |
Still broken:
Alex |
@ricsmania I was able to build your program by running 'go build' in the github.com/ricsmania/ocitest directory, and then after downloading some DLLs from Oracle and then downloading msvcr100.dll from some random site on the internet, I was able to run the program, and it prints "worked". This is with Windows 7 (ver prints "Microsoft Windows [Version 6.1.7601]", which the internet says is Windows 7). I did notice that the file github.com/ricsmania/ocitest/oracle/oci.dll is a 32-bit DLL, so that's not going to work. But I assume you copied the wrong one off your system and that on your system you are still using a 64-bit DLL, just not that one. When I tried to run with the 32-bit DLL I got exit code 0xc000007b. (Missing DLL is 0xc0000135.) My guess is that something is wrong with your Windows 7 system, possibly with the version of oci.dll that you have installed. The one that worked for me was the "Instant Client Package - Basic", from http://www.oracle.com/technetwork/topics/winx64soft-089540.html. Please try extracting that and put the instantclient_12_1 directory first in your %PATH%. Thanks. |
@rsc I still have this problem on some machines. I recently installed Windows 10 from scratch and the problem is happening on Go 1.5 with 3 different drivers: https://github.com/mattn/go-oci8 If I use "-linkmode internal" or create the environment variable GO_EXTLINK_ENABLED=0 the problem goes away, so I'm pretty sure it has to do with the linking mode. The problem is that I can't reliably reproduce it, it happens on some machines but not on others. I got to reproduce it on a VM, however I don't think I can legally distribute a Windows VM. If I reproduce it on an EC2 or Azure instance, would you be able to help us investigate it? |
Go version: go1.5beta1 windows/amd64
OS: Windows 7 SP1 64 bits
When trying to connect to Oracle using https://github.com/mattn/go-oci8 or https://github.com/go-goracle/goracle I get the following errors:
go-oci8:
goracle:
Test code is below. Drivers need to be installed first.
This works using Go 1.4.2. It also works if I use the 32 bit version of Go 1.5beta1 on Windows, or if I use the 64 bit version on Linux.
The text was updated successfully, but these errors were encountered: