Skip to content

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

Closed
ricsmania opened this issue Jul 14, 2015 · 20 comments

Comments

@ricsmania
Copy link

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:

Exception 0xc0000005 0x8 0x0 0x0
PC=0x0
signal arrived during external code execution

github.com/mattn/go-oci8._Cfunc_WrapOCIEnvCreate(0x1, 0x0, 0x0, 0x0, 0x0)
        ??:0 +0x5a
github.com/mattn/go-oci8.(*OCI8Driver).Open(0x6dc678, 0x5f9560, 0x1d, 0x0, 0x0, 0x0, 0x0)
        C:/Projetos/Go/src/github.com/mattn/go-oci8/oci8.go:531 +0x4a8
database/sql.(*DB).conn(0xc082070140, 0x44c801, 0xc082065ea0, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:710 +0x458
database/sql.(*DB).Ping(0xc082070140, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:491 +0x3d
main.main()
        C:/projetos/go/exemplos-Go/oracle-connect.go:16 +0x16a

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        c:/go/src/runtime/asm_amd64.s:1696 +0x1

goroutine 5 [chan receive]:
database/sql.(*DB).connectionOpener(0xc082070140)
        c:/go/src/database/sql/sql.go:634 +0x4c
created by database/sql.Open
        c:/go/src/database/sql/sql.go:481 +0x33d
rax     0x22fd30
rbx     0xc082065a20
rcx     0x22fd30
rdi     0xc082065a20
rsi     0x6b91e0
rbp     0x22fd50
rsp     0x22fce8
r8      0x0
r9      0x0
r10     0xc082008d80
r11     0x55555555555555
r12     0x3
r13     0x6185a2
r14     0x38
r15     0x0
rip     0x0
rflags  0x10246
cs      0x33
fs      0x53
gs      0x2b
exit status 2

goracle:

Exception 0xc0000005 0x8 0x0 0x0
PC=0x0
signal arrived during external code execution

gopkg.in/goracle.v1/oracle._Cfunc_OCIEnvNlsCreate(0xc082054bd0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffff00000000, 0x0)
        ??:0 +0x43
gopkg.in/goracle.v1/oracle.NewEnvironment(0x6620c0, 0x0, 0x0)
        C:/Projetos/Go/src/gopkg.in/goracle.v1/oracle/environment.go:99 +0x266
gopkg.in/goracle.v1/oracle.NewConnection(0x6b5fa0, 0x6, 0x6b5fa7, 0x7, 0x6b5faf, 0xe, 0x6b5f00, 0xc08200e400, 0x0, 0x0)
        C:/Projetos/Go/src/gopkg.in/goracle.v1/oracle/connection.go:132 +0xd1
gopkg.in/goracle%2ev1.(*Driver).Open(0x7b10a0, 0x6b5fa0, 0x1d, 0x0, 0x0, 0x0, 0x0)
        C:/Projetos/Go/src/gopkg.in/goracle.v1/driver.go:255 +0x166
database/sql.(*DB).conn(0xc08206c140, 0x44f601, 0xc082061ea0, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:710 +0x458
database/sql.(*DB).Ping(0xc08206c140, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:491 +0x3d
main.main()
        C:/projetos/go/exemplos-Go/oracle-connect.go:17 +0x16a

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        c:/go/src/runtime/asm_amd64.s:1696 +0x1

goroutine 5 [chan receive]:
database/sql.(*DB).connectionOpener(0xc08206c140)
        c:/go/src/database/sql/sql.go:634 +0x4c
created by database/sql.Open
        c:/go/src/database/sql/sql.go:481 +0x33d
rax     0xc082054bd0
rbx     0x0
rcx     0xc082054bd0
rdi     0x0
rsi     0x0
rbp     0x22fda0
rsp     0x22fd18
r8      0x0
r9      0x0
r10     0x0
r11     0x0
r12     0x10
r13     0x6e15bc
r14     0x8
r15     0x2
rip     0x0
rflags  0x10202
cs      0x33
fs      0x53
gs      0x2b
exit status 2

Test code is below. Drivers need to be installed first.

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/mattn/go-oci8"
    _ "gopkg.in/goracle.v1"
)

func main() {
    // Change to "goracle" to test Goracle
    db, err := sql.Open("oci8", "system/manager@127.0.0.1/orcl")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer db.Close()
    err = db.Ping()
    if err != nil {
        fmt.Println(err)
        return
    }
}

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.

@ricsmania
Copy link
Author

Oh, and there is no need for an Oracle database, the error happens before trying to connect.

@ianlancetaylor
Copy link
Contributor

The error message suggests that the C code is calling a NULL pointer.

@ianlancetaylor ianlancetaylor added this to the Go1.5 milestone Jul 14, 2015
@ianlancetaylor ianlancetaylor changed the title go1.5beta1 on Windows 64 with CGO: signal arrived during external code execution cmd/cgo: go1.5beta1 on Windows 64 with CGO: signal arrived during external code execution Jul 14, 2015
@ianlancetaylor ianlancetaylor changed the title cmd/cgo: go1.5beta1 on Windows 64 with CGO: signal arrived during external code execution runtime: go1.5beta1 on Windows 64 with CGO: signal arrived during external code execution Jul 14, 2015
@ianlancetaylor
Copy link
Contributor

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.

CC @alexbrainman

@alexbrainman
Copy link
Member

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

@ricsmania
Copy link
Author

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:

OciEnv: 000000000022FD60
Mode: 1
Extra: 0
Extra Ptr: 0000000000000000
Exception 0xc0000005 0x0 0xd7d526 0x69c018
PC=0x69c018
signal arrived during external code execution

github.com/mattn/go-oci8._Cfunc_WrapOCIEnvCreate(0x1, 0x0, 0x0, 0x0, 0x0)
        ??:0 +0x5a
github.com/mattn/go-oci8.(*OCI8Driver).Open(0x6db678, 0x5f8ba0, 0x1c, 0x0, 0x0,
0x0, 0x0)
        c:/projetos/go/src/github.com/mattn/go-oci8/oci8.go:538 +0x4a8
database/sql.(*DB).conn(0xc08206a140, 0x44be01, 0xc08205bea0, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:710 +0x458
database/sql.(*DB).Ping(0xc08206a140, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:491 +0x3d
main.main()
        C:/Projetos/Go/oracle-connect.go:17 +0x16a

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        c:/go/src/runtime/asm_amd64.s:1696 +0x1

goroutine 5 [chan receive]:
database/sql.(*DB).connectionOpener(0xc08206a140)
        c:/go/src/database/sql/sql.go:634 +0x4c
created by database/sql.Open
        c:/go/src/database/sql/sql.go:481 +0x33d
rax     0x1c
rbx     0xc08205ba20
rcx     0x22fd60
rdi     0x22fd60
rsi     0x0
rbp     0x1
rsp     0x22fd18
r8      0x0
r9      0x0
r10     0x0
r11     0x246
r12     0x0
r13     0xc08205bfa0
r14     0x38
r15     0x0
rip     0x69c018
rflags  0x10246
cs      0x33
fs      0x53
gs      0x2b

Go 1.4:

OciEnv: 000000000022FE60
Mode: 1
Extra: 0
Extra Ptr: 0000000000000000
worked

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.

go1 4

go1 5

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.

@alexbrainman
Copy link
Member

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:

go build -gcflags "-linkmode internal" ...

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

@ricsmania
Copy link
Author

@alexbrainman I tried your first suggestion linking using the -linkmode flag and it worked:

go build -ldflags "-linkmode internal" oracle-connect.go

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.

@ricsmania
Copy link
Author

I created a very simple application that reproduces the problem with no external dependencies.

To test it:

go get github.com/ricsmania/ocitest
cd %GOPATH%\src\ricsmania\ocitest
go run oci.go

@alexbrainman
Copy link
Member

Sure I will try it. Thank you.

Alex

@rsc
Copy link
Contributor

rsc commented Jul 22, 2015

@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() {
runtime.LockOSThread()
}

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.

@ricsmania
Copy link
Author

@rsc Thanks for your suggestion. Unfortunately nothing changed, I still get the error.

@alexbrainman
Copy link
Member

That does not build on my pc:

C:\dev\src\github.com\ricsmania\ocitest>go build
# github.com/ricsmania/ocitest
C:\DOCUME~1\brainman\LOCALS~1\Temp\go-build303634482\github.com\ricsmania\ocitest\_obj\oci.cgo2.o: In function `CreateEnv':
c:/dev/src/github.com/ricsmania/ocitest/oci.go:14: undefined reference to `OCIEnvCreate'
collect2.exe: error: ld returned 1 exit status

Alex

@mattn
Copy link
Member

mattn commented Jul 28, 2015

you may need to put oci8.pc in your $PKG_CONFIG_PATH.

@ricsmania
Copy link
Author

@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
set CGO_LDFLAGS=-L%GOPATH%\github.com\ricsmania\ocitest

Thanks

@alexbrainman
Copy link
Member

Still get the same error message:

C:\dev\src\github.com\ricsmania\ocitest>set CGO_CFLAGS=-I%GOPATH%\github.com\ricsmania\ocitest

C:\dev\src\github.com\ricsmania\ocitest>set CGO_LDFLAGS=-L%GOPATH%\github.com\ricsmania\ocitest

C:\dev\src\github.com\ricsmania\ocitest>set | find "CGO_"
CGO_CFLAGS=-Ic:\dev\github.com\ricsmania\ocitest
CGO_LDFLAGS=-Lc:\dev\github.com\ricsmania\ocitest

C:\dev\src\github.com\ricsmania\ocitest>go build
# github.com/ricsmania/ocitest
C:\DOCUME~1\brainman\LOCALS~1\Temp\go-build110287182\github.com\ricsmania\ocitest\_obj\oci.cgo2.o:oci.cgo2.c:(.text+0x4c): undefined reference to `OCIEnvCreate'

collect2.exe: error: ld returned 1 exit status

C:\dev\src\github.com\ricsmania\ocitest>

Alex

@ricsmania
Copy link
Author

@alexbrainman I'm sorry, I forgot a part, the path should be
set CGO_CFLAGS=-IC:\dev\src\github.com\ricsmania\ocitest\oracle

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.

@ricsmania
Copy link
Author

Also, after building you will probably have to add this same path to your %PATH% before executing.

@alexbrainman
Copy link
Member

Still broken:

C:\dev\src\github.com\ricsmania\ocitest>set CGO_CFLAGS=-IC:\dev\src\github.com\ricsmania\ocitest\oracle

C:\dev\src\github.com\ricsmania\ocitest>set CGO_LDFLAGS=-LC:\dev\src\github.com\ricsmania\ocitest\oracle

C:\dev\src\github.com\ricsmania\ocitest>go build
# github.com/ricsmania/ocitest
C:\DOCUME~1\brainman\LOCALS~1\Temp\go-build119391970\github.com\ricsmania\ocitest\_obj\oci.cgo2.o:oci.cgo2.c:(.text+0x4c): undefined reference to `OCIEnvCreate'

collect2.exe: error: ld returned 1 exit status

C:\dev\src\github.com\ricsmania\ocitest>

Alex

@rsc
Copy link
Contributor

rsc commented Aug 5, 2015

@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 rsc modified the milestones: Go1.5Maybe, Go1.5 Aug 5, 2015
@rsc rsc closed this as completed Aug 7, 2015
@ricsmania
Copy link
Author

@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
https://github.com/go-goracle/goracle
https://github.com/rana/ora

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?

@golang golang locked and limited conversation to collaborators Sep 4, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants