-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
cgo: program crashes when more that one package uses cgo #8948
Comments
Reported at https://groups.google.com/d/topic/golang-nuts/_yka6Okq7tc/discussion Alex |
The crash happens inside of C code in func _Cfunc__sqlite3_open_v2(p0 *_Ctype_char, p1 **_Ctype_struct_sqlite3, p2 _Ctype_int, p3 *_Ctype_char) (r1 _Ctype_int) { _cgo_runtime_cgocall_errno(_cgo_edfc822ad612_Cfunc__sqlite3_open_v2, uintptr(unsafe.Pointer(&p0))) return } So I don't think that not instrumenting cgo wrapper code will help. Race detector does not instrument C code, so it seems that the C code just crashes. What's at PC 0x6c3180? That PC seems to dereference a NULL pointer. |
https://code.google.com/p/go/issues/detail?id=8948#c4 comment is lost. It says: It is crashing in sqlite3_os_init from sqlite3.c trying to execute osGetSystemInfo. I suspect address of real syscall is not setup properly during -race. It works fine when no -race. It might be go linker or gcc fault for all I know. I don't know enough about these things ... Alex |
This also happens with github.com/mattn/go-oci8 when I db.Exec an insert, however I don't get the call stack from inside go-oci8. It works fine without -race. Queries work either way. Using Go 1.4.1 x64 on Windows 7 create table test
(
pk NUMBER,
id NUMBER not null
) package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-oci8"
)
func main() {
db, err := sql.Open("oci8", "system/[email protected]:1521/orcl")
if err != nil {
fmt.Println(err)
}
db.Exec("delete from test")
_, err = db.Exec("insert into test values (:pk, :id)", 1, 1)
if err != nil {
fmt.Println(err)
}
}
|
If I change the program as (add usage of cgo): package main
/*
#include <stdio.h>
#include <windows.h>
void foo() {
SYSTEM_INFO info;
GetSystemInfo(&info);
printf("%d\n", info.dwPageSize);
}
*/
import "C"
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./test.db")
if err != nil {
fmt.Println("err%+v", err)
return
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err.Error())
}
fmt.Println("ok")
} Then the program fails even without race detector. In both working and non-working case, address of GetSystemInfo looks like 0x66b070, which means that it does not come from a windows system library (probably from libmingw?). However, in non-working cases the address of GetSystemInfo seems to be a little off. I can speculate that it is off by size of an object file or or a section in one of the packages. Probably we compute symbol offsets assuming that there is only one package that uses native code... |
I agree with you. This looks like effect of using 2 different packages (each must use cgo) in one program. When Go linker produces final executable, it might use different relocation strategies for external Windows API functions (like for example GetLastError). If single executable contains 2 function references that require different strategies, the linker just pick one at random. The relocations would be wrong for some function references, and, when the function is called, it just crashes. Running this test:
produces this output
I had to use "#cgo CFLAGS: -mnop-fun-dllimport" to force the crash with my gcc. But I suspect there are different ways to do it. github.com/mattn/go-sqlite3 does it too. The code that does relocations is in cmd/ld/data.c:^dynrelocsym. The logic that decides what to do is in cmd/ld/ldpe.c. I discovered all this while investigating issue #9356. I suspect it is a dup. I don't have fix for this. I tried some ideas but none of them work - I don't know this area enough. Perhaps if someone suggest something, I will try it. Alex |
@alexbrainman I have no ideas. Why do you say that GetCurrentThreadId requires two different relocation strategies? Both symbol references end up in the same module, so I would assume that they require relocation of the same type but maybe with different offsets or something. |
I am not saying it requires, I am saying Go linker does that at this moment. If you look in cmd/ld/data.c:^dynrelocsym, you will see that we add JMP instruction for "dynamic" symbols where sym->plt == -2 (like GetCurrentThreadId) but only if sym->got != -2. Sometimes (in some imported packages) GetCurrentThreadId has sym->got != -2, and sometimes sym->got == -2 (see in cmd/ld/ldpe.c). So if you use both of these packages at the same time, you end up generating JMP when you should not or vice versa. Alex |
I see. |
Maybe this https://go-review.googlesource.com/5711 will fix it. Alex |
Okay, I'll try this. |
Should be fixed by external linking support, #4069. |
The test is a simple reproduction of issue 9356. Update #8948. Update #9356. Change-Id: Ia77bc36d12ed0c3c4a8b1214cade8be181c9ad55 Reviewed-on: https://go-review.googlesource.com/7618 Reviewed-by: Minux Ma <[email protected]>
CL https://golang.org/cl/5711 mentions this issue. |
The text was updated successfully, but these errors were encountered: