alexbrainman / odbc

odbc driver written in go
BSD 3-Clause "New" or "Revised" License
352 stars 140 forks source link

When under load, concurrent usage of the driver panics with "invalid heap pointer" #52

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
It appears running concurrent connections with a high load.
The example I attached seems to breaks every time with invalid heap pointer.

What is the expected output? What do you see instead?
It should just keep running forever, but panics

What version of the product are you using? On what operating system?
Using go 1.4.rc1
latest version of odbc pulled using "go get".  
I'm running on a Mac using ODBC and FreeTDS to connect to MSSQLServer

I've attached a file that has a complete test program that causes the crash.
I don't see that I've used the driver in an invalid way, but do let me know if 
you see something i'm doing wrong.

Thanks!
Shane

Original issue reported on code.google.com by kolant...@gmail.com on 1 Dec 2014 at 10:17

Attachments:

GoogleCodeExporter commented 9 years ago
Are you using latest version of odbc package? What does hg is print? Thank you.

Alex

Original comment by alex.bra...@gmail.com on 1 Dec 2014 at 10:38

GoogleCodeExporter commented 9 years ago
I was meant to say "hg id".

Original comment by alex.bra...@gmail.com on 1 Dec 2014 at 10:39

GoogleCodeExporter commented 9 years ago
c7df2c6eae12 tip

Original comment by kolant...@gmail.com on 1 Dec 2014 at 11:53

GoogleCodeExporter commented 9 years ago
Thank you. I am on the road. I will try your program next week.

Alex

Original comment by alex.bra...@gmail.com on 2 Dec 2014 at 12:13

GoogleCodeExporter commented 9 years ago
I can reproduce this on Linux too:

runtime: garbage collector found invalid heap pointer *(0x18316ea8+0x8)=0x1 
s=nil
fatal error: invalid heap pointer

runtime stack:
runtime.throw(0x81aa863)
    /root/go/root/src/runtime/panic.go:491 +0x83 fp=0xb6b48fc4 sp=0xb6b48fac
scanblock(0x18316ea8, 0x14, 0x814d978)
    /root/go/root/src/runtime/mgc0.c:378 +0x48d fp=0xb6b49064 sp=0xb6b48fc4
scanframe(0xb6b490f0, 0x0, 0x1)
    /root/go/root/src/runtime/mgc0.c:740 +0x186 fp=0xb6b490a0 sp=0xb6b49064
runtime.gentraceback(0x804c31d, 0x18316e80, 0x0, 0x183008c0, 0x0, 0x0, 
0x7fffffff, 0xb6b49148, 0x0, 0x0, ...)
    /root/go/root/src/runtime/traceback.go:311 +0x5c5 fp=0xb6b4911c sp=0xb6b490a0
scanstack(0x183008c0)
    /root/go/root/src/runtime/mgc0.c:777 +0x1e0 fp=0xb6b49154 sp=0xb6b4911c
markroot(0x18310000, 0xb)
    /root/go/root/src/runtime/mgc0.c:553 +0xcd fp=0xb6b4918c sp=0xb6b49154
runtime.parfordo(0x18310000)
    /root/go/root/src/runtime/parfor.c:76 +0x99 fp=0xb6b491e8 sp=0xb6b4918c
gc(0xb6b49324)
    /root/go/root/src/runtime/mgc0.c:1439 +0x1fb fp=0xb6b49314 sp=0xb6b491e8
runtime.gc_m()
    /root/go/root/src/runtime/mgc0.c:1368 +0xd2 fp=0xb6b49334 sp=0xb6b49314
runtime.onM(0x18312000)
    /root/go/root/src/runtime/asm_386.s:266 +0x50 fp=0xb6b49338 sp=0xb6b49334
runtime.mstart()
    /root/go/root/src/runtime/proc.c:818 fp=0xb6b4933c sp=0xb6b49338

goroutine 1 [garbage collection]:
runtime.switchtoM()
    /root/go/root/src/runtime/asm_386.s:208 fp=0x1832a954 sp=0x1832a950
runtime.gogc(0x0)
    /root/go/root/src/runtime/malloc.go:469 +0x1aa fp=0x1832a974 sp=0x1832a954
runtime.mallocgc(0x30, 0x811d220, 0x0, 0x805c5ae)
    /root/go/root/src/runtime/malloc.go:341 +0x2c4 fp=0x1832a9cc sp=0x1832a974
runtime.newobject(0x811d220, 0x4)
    /root/go/root/src/runtime/malloc.go:353 +0x48 fp=0x1832a9e0 sp=0x1832a9cc
code.google.com/p/odbc.NewBindableColumn(0x1832f730, 0x182f0001, 0x4, 
0x1832f722)
    /root/go/path/mine/src/code.google.com/p/odbc/column.go:184 +0x35 fp=0x1832aa18 sp=0x1832a9e0
code.google.com/p/odbc.NewVariableWidthColumn(0x1832f730, 0x18320001, 0x3, 0x0, 
0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/column.go:211 +0x67 fp=0x1832aa68 sp=0x1832aa18
code.google.com/p/odbc.NewColumn(0x81dfa00, 0x0, 0x0, 0x0, 0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/column.go:89 +0x8c5 fp=0x1832ac44 sp=0x1832aa68
code.google.com/p/odbc.(*ODBCStmt).BindColumns(0x18333f50, 0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/odbcstmt.go:134 +0x1f9 fp=0x1832acb8 sp=0x1832ac44
code.google.com/p/odbc.(*Stmt).Query(0x18337420, 0x81b2218, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/stmt.go:91 +0x262 fp=0x1832ad04 sp=0x1832acb8
database/sql.rowsiFromStatement(0xb74c0ae0, 0x18332300, 0xb74c0ab8, 0x18337420, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
    /root/go/root/src/database/sql/sql.go:1489 +0x2b3 fp=0x1832ad8c sp=0x1832ad04
database/sql.(*DB).queryConn(0x183100f0, 0x18332300, 0x8154c80, 0x8136ec8, 
0x13, 0x0, 0x0, 0x0, 0x8080e72, 0x0, ...)
    /root/go/root/src/database/sql/sql.go:978 +0x35d fp=0x1832ae20 sp=0x1832ad8c
database/sql.(*Tx).Query(0x18333ef0, 0x8136ec8, 0x13, 0x0, 0x0, 0x0, 
0xb74af000, 0x0, 0x0)
    /root/go/root/src/database/sql/sql.go:1259 +0xbd fp=0x1832ae68 sp=0x1832ae20
database/sql.(*Tx).QueryRow(0x18333ef0, 0x8136ec8, 0x13, 0x0, 0x0, 0x0, 
0xb74c0a80)
    /root/go/root/src/database/sql/sql.go:1266 +0x50 fp=0x1832aea0 sp=0x1832ae68
main.func·001(0x18333ef0, 0x0, 0x0, 0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/odbc_panic.go:50 +0x74 fp=0x1832aef4 sp=0x1832aea0
main.executeTransaction(0x183100f0, 0x1832af7c, 0x0, 0x0, 0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/odbc_panic.go:108 +0x8c fp=0x1832af28 sp=0x1832aef4
main.main()
    /root/go/path/mine/src/code.google.com/p/odbc/odbc_panic.go:52 +0x433 fp=0x1832afcc sp=0x1832af28
runtime.main()
    /root/go/root/src/runtime/proc.go:63 +0xcc fp=0x1832aff0 sp=0x1832afcc
runtime.goexit()
    /root/go/root/src/runtime/asm_386.s:2287 +0x1 fp=0x1832aff4 sp=0x1832aff0

goroutine 2 [force gc (idle)]:
runtime.gopark(0x80709f0, 0x81ac708, 0x8131a88, 0xf)
    /root/go/root/src/runtime/proc.go:130 +0xde fp=0x183187cc sp=0x183187b4
runtime.goparkunlock(0x81ac708, 0x8131a88, 0xf)
    /root/go/root/src/runtime/proc.go:136 +0x42 fp=0x183187e0 sp=0x183187cc
runtime.forcegchelper()
    /root/go/root/src/runtime/proc.go:99 +0xa3 fp=0x183187f0 sp=0x183187e0
runtime.goexit()
    /root/go/root/src/runtime/asm_386.s:2287 +0x1 fp=0x183187f4 sp=0x183187f0
created by runtime.init·4
    /root/go/root/src/runtime/proc.go:87 +0x25

goroutine 3 [GC sweep wait]:
runtime.gopark(0x80709f0, 0x81b21b8, 0x8130648, 0xd)
    /root/go/root/src/runtime/proc.go:130 +0xde fp=0x1831bfcc sp=0x1831bfb4
runtime.goparkunlock(0x81b21b8, 0x8130648, 0xd)
    /root/go/root/src/runtime/proc.go:136 +0x42 fp=0x1831bfe0 sp=0x1831bfcc
runtime.bgsweep()
    /root/go/root/src/runtime/mgc0.go:98 +0x97 fp=0x1831bff0 sp=0x1831bfe0
runtime.goexit()
    /root/go/root/src/runtime/asm_386.s:2287 +0x1 fp=0x1831bff4 sp=0x1831bff0
created by gc
    /root/go/root/src/runtime/mgc0.c:1383

goroutine 4 [finalizer wait]:
runtime.gopark(0x80709f0, 0x81b21b4, 0x8131868, 0xe)
    /root/go/root/src/runtime/proc.go:130 +0xde fp=0x18317798 sp=0x18317780
runtime.goparkunlock(0x81b21b4, 0x8131868, 0xe)
    /root/go/root/src/runtime/proc.go:136 +0x42 fp=0x183177ac sp=0x18317798
runtime.runfinq()
    /root/go/root/src/runtime/malloc.go:727 +0x9c fp=0x183177f0 sp=0x183177ac
runtime.goexit()
    /root/go/root/src/runtime/asm_386.s:2287 +0x1 fp=0x183177f4 sp=0x183177f0
created by runtime.createfing
    /root/go/root/src/runtime/malloc.go:707 +0x59

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
    /root/go/root/src/runtime/asm_386.s:2287 +0x1 fp=0x18329ff4 sp=0x18329ff0

goroutine 5 [chan receive]:
runtime.gopark(0x80709f0, 0x18346070, 0x8131468, 0xc)
    /root/go/root/src/runtime/proc.go:130 +0xde fp=0x1831674c sp=0x18316734
runtime.goparkunlock(0x18346070, 0x8131468, 0xc)
    /root/go/root/src/runtime/proc.go:136 +0x42 fp=0x18316760 sp=0x1831674c
runtime.chanrecv(0x80f7400, 0x18346040, 0x183167e0, 0x1, 0x0)
    /root/go/root/src/runtime/chan.go:467 +0x6fc fp=0x183167b8 sp=0x18316760
runtime.chanrecv2(0x80f7400, 0x18346040, 0x183167e0, 0x0)
    /root/go/root/src/runtime/chan.go:316 +0x24 fp=0x183167d0 sp=0x183167b8
database/sql.(*DB).connectionOpener(0x183100f0)
    /root/go/root/src/database/sql/sql.go:589 +0x43 fp=0x183167e8 sp=0x183167d0
runtime.goexit()
    /root/go/root/src/runtime/asm_386.s:2287 +0x1 fp=0x183167ec sp=0x183167e8
created by database/sql.Open
    /root/go/root/src/database/sql/sql.go:452 +0x256

goroutine 6 [syscall, locked to thread]:
runtime.cgocall_errno(0x8049d30, 0x18316ea8, 0x0)
    /root/go/root/src/runtime/cgocall.go:130 +0xcd fp=0x18316e98 sp=0x18316e80
code.google.com/p/odbc/api._Cfunc_SQLSetConnectAttrW(0x81bf758, 0x66, 0x1, 
0xfffffffb, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/api/:207 +0x3e fp=0x18316ea8 sp=0x18316e98
code.google.com/p/odbc/api.SQLSetConnectAttr(0x81bf758, 0x66, 0x1, 0xfffffffb, 
0x8050002)
    /root/go/path/mine/src/code.google.com/p/odbc/api/zapi_unix.go:118 +0x40 fp=0x18316ec0 sp=0x18316ea8
code.google.com/p/odbc.(*Conn).setAutoCommitAttr(0x1830a150, 0x1, 0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/tx.go:19 +0x52 fp=0x18316ee4 sp=0x18316ec0
code.google.com/p/odbc.(*Conn).endTx(0x1830a150, 0x81acb01, 0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/tx.go:53 +0x17d fp=0x18316f1c sp=0x18316ee4
code.google.com/p/odbc.(*Tx).Commit(0x1830b088, 0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/tx.go:61 +0x3f fp=0x18316f30 sp=0x18316f1c
database/sql.(*Tx).Commit(0x18333e00, 0x0, 0x0)
    /root/go/root/src/database/sql/sql.go:1106 +0xb0 fp=0x18316f58 sp=0x18316f30
main.executeTransaction(0x183100f0, 0x8154ca8, 0x0, 0x0, 0x0, 0x0)
    /root/go/path/mine/src/code.google.com/p/odbc/odbc_panic.go:117 +0x112 fp=0x18316f8c sp=0x18316f58
main.readData(0x183100f0, 0x18346080)
    /root/go/path/mine/src/code.google.com/p/odbc/odbc_panic.go:74 +0x31 fp=0x18316fe8 sp=0x18316f8c
runtime.goexit()
    /root/go/root/src/runtime/asm_386.s:2287 +0x1 fp=0x18316fec sp=0x18316fe8
created by main.createReadChannel
    /root/go/path/mine/src/code.google.com/p/odbc/odbc_panic.go:64 +0x57

It is crashing because new Go runtime gc checks that all pointers looks 
reasonable. Here the third parameter of odbc/api._Cfunc_SQLSetConnectAttrW is 
C.SQLPOINTER (which is pointer as per cgo), but is set to 1. Real pointers 
cannot be set to 1, but C does not check for these things.

I did not write odbc/api._Cfunc_SQLSetConnectAttrW. It is generated by cgo 
auto-magically. I cannot change the function so it accepts non-pointer 
parameters.

I am not sure how to make Go runtime ignore that. Perhaps I will ask on go-nuts.

Alex

Original comment by alex.bra...@gmail.com on 5 Dec 2014 at 5:33

GoogleCodeExporter commented 9 years ago
write a c wrapper function for SQLSetConnectAttrW that takes uintptr_t for that 
parameter,
and in your cgo code, call your wrapper function instead of the real 
SQLSetConnectAttrW.

Original comment by mi...@golang.org on 5 Dec 2014 at 7:04

GoogleCodeExporter commented 9 years ago
I will try that. Thank you, minux.

Alex

Original comment by alex.bra...@gmail.com on 5 Dec 2014 at 8:04

GoogleCodeExporter commented 9 years ago
kolanthes,

This https://codereview.appspot.com/181650043 should fix your problem. Please 
check it. Thank you.

Alex

Original comment by alex.bra...@gmail.com on 8 Dec 2014 at 3:23

GoogleCodeExporter commented 9 years ago
This issue was closed by revision dec83d07538e.

Original comment by alex.bra...@gmail.com on 9 Dec 2014 at 4:33