"Bad pointer in scanbitvector" using odbc DB driver

293 views
Skip to first unread message

Shane Turner

unread,
Dec 1, 2014, 10:54:09 AM12/1/14
to golan...@googlegroups.com
Running go 1.3.3 on Mac (darwin/amd64), got the same error on CentOS also (linux/amd64).
I'm running go from source.
 $ hg summary
parent: 20236:f44017549ff9 go1.3.3 release
 go1.3.3
branch: release-branch.go1.3
commit: (clean)
update: (current)

I received the following error after running a couple of hundred iterations/transactions (it's a polling operation each wrapped in explicit transaction) on a DB connection.
There is a lot of infrastructure code at the moment so I'm trying to boil down an example that will make the problem happen with minimal code.
I'll post code later if/when I can recreate.

In the meantime, does anybody have an idea on the issue here?


bad pointer in frame code.google.com/p/odbc/api.SQLSetConnectAttr at 0x7f3c3c230c88: 0x1
fatal error: bad pointer in scanbitvector

A few partial stack traces that looked relevant:

runtime stack:
runtime.throw(0x86f2ab)
/usr/lib/golang/src/pkg/runtime/panic.c:520 +0x69 fp=0x7f3c32d869b0 sp=0x7f3c32d86998
scanbitvector(0x65abe8, 0x5cca01, 0x7f3c3c230c88, 0x7f3c32d86a68, 0x1, 0x7f3c32d86c78)
/usr/lib/golang/src/pkg/runtime/mgc0.c:1492 +0x38d fp=0x7f3c32d86a18 sp=0x7f3c32d869b0
scanframe(0x7f3c32d86ae8, 0x7f3c32d86c78)
/usr/lib/golang/src/pkg/runtime/mgc0.c:1631 +0x1a8 fp=0x7f3c32d86a90 sp=0x7f3c32d86a18
runtime.gentraceback(0x405bc5, 0x7f3c3c230be8, 0x0, 0xc2080037a0, 0x7f3c00000000, 0x0, 0x7fffffff, 0x40a2d0, 0x7f3c32d86c78, 0x0)
/usr/lib/golang/src/pkg/runtime/traceback_x86.c:253 +0x744 fp=0x7f3c32d86b78 sp=0x7f3c32d86a90
addstackroots(0xc2080037a0, 0x7f3c32d86c78)
/usr/lib/golang/src/pkg/runtime/mgc0.c:1692 +0x168 fp=0x7f3c32d86c08 sp=0x7f3c32d86b78
markroot(0xc208018480, 0x7f3c0000000b)
/usr/lib/golang/src/pkg/runtime/mgc0.c:1321 +0xbe fp=0x7f3c32d86c88 sp=0x7f3c32d86c08
runtime.parfordo(0xc208018480)
/usr/lib/golang/src/pkg/runtime/parfor.c:88 +0xa3 fp=0x7f3c32d86d00 sp=0x7f3c32d86c88
gc(0x7f3c3c21a8f0)
/usr/lib/golang/src/pkg/runtime/mgc0.c:2407 +0x1d6 fp=0x7f3c32d86e30 sp=0x7f3c32d86d00
mgc(0xc208002120)
/usr/lib/golang/src/pkg/runtime/mgc0.c:2349 +0x2e fp=0x7f3c32d86e40 sp=0x7f3c32d86e30
runtime.mcall(0x4021b4)
/usr/lib/golang/src/pkg/runtime/asm_amd64.s:181 +0x4b fp=0x7f3c32d86e50 sp=0x7f3c32d86e40

goroutine 21 [runnable]:
runtime.cgocall(0x401bb0, 0x7f3c3c230c48)
/usr/lib/golang/src/pkg/runtime/cgocall.c:143 +0xe5 fp=0x7f3c3c230c30 sp=0x7f3c3c230be8
code.google.com/p/odbc/api._Cfunc_SQLSetConnectAttrW(0x166ca80, 0x100000066, 0x1, 0xc2fffffffb, 0x860000)
code.google.com/p/odbc/api/_obj/_cgo_defun.c:216 +0x31 fp=0x7f3c3c230c48 sp=0x7f3c3c230c30
code.google.com/p/odbc/api.SQLSetConnectAttr(0x166ca80, 0x66, 0x1, 0x7f3cfffffffb, 0x4e641d)
/vagrant/dxp-service-dna-workspace/src/code.google.com/p/odbc/api/zapi_unix.go:118 +0x41 fp=0x7f3c3c230c78 sp=0x7f3c3c230c48
/vagrant/dxp-service-dna-workspace/src/code.google.com/p/odbc/tx.go:19 +0x56 fp=0x7f3c3c230cc8 sp=0x7f3c3c230c78
/vagrant/dxp-service-dna-workspace/src/code.google.com/p/odbc/tx.go:53 +0x1ba fp=0x7f3c3c230d50 sp=0x7f3c3c230cc8
/vagrant/dxp-service-dna-workspace/src/code.google.com/p/odbc/tx.go:61 +0x41 fp=0x7f3c3c230d78 sp=0x7f3c3c230d50
database/sql.(*Tx).Commit(0xc208024ea0, 0x0, 0x0)
/usr/lib/golang/src/pkg/database/sql/sql.go:1082 +0xf1 fp=0x7f3c3c230db8 sp=0x7f3c3c230d78


goroutine 16 [garbage collection]:
runtime.gc(0x0)
/usr/lib/golang/src/pkg/runtime/mgc0.c:2329 +0x1c6 fp=0x7f3c3c21a908 sp=0x7f3c3c21a8d8
runtime.mallocgc(0x10, 0x560c60, 0x1)
/usr/lib/golang/src/pkg/runtime/malloc.goc:205 +0x1d6 fp=0x7f3c3c21a970 sp=0x7f3c3c21a908
runtime.new(0x560c60, 0x0)
/usr/lib/golang/src/pkg/runtime/malloc.goc:826 +0x3b fp=0x7f3c3c21a990 sp=0x7f3c3c21a970
code.google.com/p/odbc.(*Stmt).Exec(0xc2080251a0, 0xc208058bc0, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0)
/vagrant/dxp-service-dna-workspace/src/code.google.com/p/odbc/stmt.go:69 +0x3da fp=0x7f3c3c21aa48 sp=0x7f3c3c21a990
database/sql.resultFromStatement(0x7f3c3c3b9640, 0xc208004900, 0x7f3c3c3b95a8, 0xc2080251a0, 0x7f3c3c21ad10, 0x2, 0x2, 0x0, 0x0, 0x0, ...)
/usr/lib/golang/src/pkg/database/sql/sql.go:1302 +0x317 fp=0x7f3c3c21ab78 sp=0x7f3c3c21aa48
database/sql.(*Stmt).Exec(0xc208062880, 0x7f3c3c21ad10, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0)
/usr/lib/golang/src/pkg/database/sql/sql.go:1275 +0x2c7 fp=0x7f3c3c21ac50 sp=0x7f3c3c21ab78
bitbucket.org/daxko/dxp-queue.func·004(0xc208025140, 0x0, 0x0, 0x0, 0x0)
/vagrant/dxp-service-dna-workspace/src/bitbucket.org/daxko/dxp-queue/queue.go:171 +0x17f fp=0x7f3c3c21ad38 sp=0x7f3c3c21ac50
/Users/sturner/development/dxp-service-dna-workspace/src/bitbucket.org/daxko/daxGo/database/util.go:13 +0xb9 fp=0x7f3c3c21adb0 sp=0x7f3c3c21ad38
bitbucket.org/daxko/dxp-queue.(*QueueAccess).Confirm(0xc208004360, 0xc20801a5a0, 0x7fffb0c023eb, 0x8, 0x0, 0x0)
/vagrant/dxp-service-dna-workspace/src/bitbucket.org/daxko/dxp-queue/queue.go:178 +0x72 fp=0x7f3c3c21ae10 sp=0x7f3c3c21adb0
/vagrant/dxp-service-dna-workspace/src/bitbucket.org/daxko/dxp-queue/queue.go:112 +0x53 fp=0x7f3c3c21ae48 sp=0x7f3c3c21ae10
main.main()






Shane Turner

unread,
Dec 1, 2014, 11:37:59 AM12/1/14
to golan...@googlegroups.com
Forgot to mention that I'm using FreeTDS/ODBC driver connecting to MS SQLServer.

Ian Lance Taylor

unread,
Dec 1, 2014, 11:40:54 AM12/1/14
to Shane Turner, golang-nuts
On Mon, Dec 1, 2014 at 7:54 AM, Shane Turner <kola...@gmail.com> wrote:
>
> Running go 1.3.3 on Mac (darwin/amd64), got the same error on CentOS also
> (linux/amd64).
> I'm running go from source.
> $ hg summary
> parent: 20236:f44017549ff9 go1.3.3 release
> go1.3.3
> branch: release-branch.go1.3
> commit: (clean)
> update: (current)
>
> I received the following error after running a couple of hundred
> iterations/transactions (it's a polling operation each wrapped in explicit
> transaction) on a DB connection.
> There is a lot of infrastructure code at the moment so I'm trying to boil
> down an example that will make the problem happen with minimal code.
> I'll post code later if/when I can recreate.
>
> In the meantime, does anybody have an idea on the issue here?
>
>
> bad pointer in frame code.google.com/p/odbc/api.SQLSetConnectAttr at
> 0x7f3c3c230c88: 0x1
> fatal error: bad pointer in scanbitvector

This suggests either heap corruption or a bug in the runtime. Heap
corruption should only be possible if you are using unsafe or if you
are calling into C code that is doing something unexpected. One
particular case that can cause this is passing a pointer to Go memory
into C code without ensuring that it stays live on the Go side.

I would encourage you to test the 1.4 beta releaase. A lot of this
code has changed, but if there is still a problem in 1.4, and the
problem is not in your code, there is a small window of opportunity to
fix it.

Ian

Shane Turner

unread,
Dec 1, 2014, 11:46:59 AM12/1/14
to golan...@googlegroups.com, kola...@gmail.com
I'm not using any native C code so I'm suspecting it's the odbc driver that is the culprit.
I'll give 1.4 a try and see what happens.

Bryan Turley

unread,
Dec 1, 2014, 2:06:25 PM12/1/14
to golan...@googlegroups.com, kola...@gmail.com
I get something similar frequently.  You are probably storing an integer in an unsafe.Pointer.

Some c library writers have decided to return void* but sometimes store an int in it instead of a normal pointer.
Or even better on Platform A it stores a pointer but on Platform B it stores an integer but we can't break the API so void*.
If you store that pointer in an unsafe.Pointer the GC will work fine on A but get angry on B (at least in go1.3).
Since it is opaque it doesn't matter to the c functions if it is a pointer or id.

Try switching some of your unsafe.Pointers to uintptrs (if you are storing things in unsafe.Pointers).
Or perhaps inside the go package you are using.

Just a guess, I may be completely wrong ;)

Shane Turner

unread,
Dec 1, 2014, 2:25:09 PM12/1/14
to golan...@googlegroups.com, kola...@gmail.com
Just rebuilt and ran with 1.4rc1 and still get the problem although error is a little different, but I suspect same general problem.

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


On Monday, December 1, 2014 10:40:54 AM UTC-6, Ian Lance Taylor wrote:

Shane Turner

unread,
Dec 1, 2014, 5:22:16 PM12/1/14
to golan...@googlegroups.com
I've finally got a working minimal example that demonstrates the problem.  
The issue has the sample program attached.


On Monday, December 1, 2014 9:54:09 AM UTC-6, Shane Turner wrote:

Daniel Theophanes

unread,
Dec 1, 2014, 6:14:38 PM12/1/14
to golan...@googlegroups.com
You might try:
bitbucket.org/kardianos/rdb/ms (tds ms sql driver)
bitbucket.org/kardianos/rdb/sql (interface shim)

Not yet perfect, but functional in prod for me.

Dave Cheney

unread,
Dec 1, 2014, 7:05:48 PM12/1/14
to golan...@googlegroups.com, kola...@gmail.com
Yes, that is the same problem, go 1.4 is just better at diagnosing this.

You said that you were not using any cgo in your package, but the odbc driver you are using is, it's clear from the stack trace.

I'd say then next step is to raise an issue against the odbc driver.

Shane Turner

unread,
Dec 1, 2014, 9:26:16 PM12/1/14
to golan...@googlegroups.com
I came across this the other night and it peaked my interest (only pure go TDS implementation I could find).
Does it support executing stored procedures (with result sets)?  Browsed through code, but didn't come across anything that specifically identified that feature.

Daniel Theophanes

unread,
Dec 1, 2014, 9:32:46 PM12/1/14
to Shane Turner, golang-nuts
It both executes stored procs and returns multiple results. To execute a stored proc, just put it as the only text in the Command.Sql field (no spaces).
rdb/table is useful for buffering results in memory. Also, rdb/ms/batch provides a utility to separate out multiple commands (often separated by "go") using a simple lexer from a single string (the go keyword isn't part of t-sql, just part of common tools).

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/4wk4fNRZ0p4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Konstantin Khomoutov

unread,
Dec 2, 2014, 5:33:02 AM12/2/14
to Shane Turner, golan...@googlegroups.com
On Mon, 1 Dec 2014 18:26:16 -0800 (PST)
Shane Turner <kola...@gmail.com> wrote:

> I came across this the other night and it peaked my interest (only
> pure go TDS implementation I could find).
[...]

No, there are others:
https://github.com/denisenkom/go-mssqldb
https://github.com/minus5/gofreetds

Not tested by me, so can't say anything further about them.

Shane Turner

unread,
Dec 2, 2014, 1:36:26 PM12/2/14
to golan...@googlegroups.com, kola...@gmail.com
For ease of use, I'm using the shim since I already have that code in place.  What is the parameter placeholder? a question mark?
I have the following, but it's not working.  I'm calling a stored proc with parameters.  I was previously using the "call" syntax of the odbc driver ("{call dbo.publish_message(?,?,?,?,?,?,?)}")
What is the syntax for this situation?

// prepare it
publishStmt := db.Prepare("dbo.publish_message ?,?,?,?,?,?,?")
// execute it later
tx.Stmt(publishStmt).Exec(<args>...)

I get the following error : Missing parameter name at index: 0

Thanks!

Daniel Theophanes

unread,
Dec 2, 2014, 2:12:24 PM12/2/14
to Shane Turner, golang-nuts
I think I need to put the shim through more paces before people use it. It should be possible, I just need to lift some restrictions in the driver and do more testing.

The tds (ms) package expects named parameters. If you were to use it, you'd call it with something like:
_, err := db.Query(&rdb.Command{Arity: rdb.ZeroMust, Sql: `dbo.publish_message`},
 rdb.Param{Name: "P1", Value: 1}, rdb.Param{Name: "P2", Value: 2},
)

You might try the other tds package https://github.com/denisenkom/go-mssqldb that implements the database/sql interfaces directly. I prefer my parameters names though...

brainman

unread,
Dec 5, 2014, 12:39:08 AM12/5/14
to golan...@googlegroups.com, kola...@gmail.com
On Tuesday, 2 December 2014 03:40:54 UTC+11, Ian Lance Taylor wrote:

> ... This suggests either heap corruption or a bug in the runtime. 

I think gc found 1 value stored in cgo pointer parameter and is not happy about it. See https://code.google.com/p/odbc/issues/detail?id=52#c5 for details. I cannot change C lib interface. What should I do here?

Thank you.

Alex

Tamás Gulácsi

unread,
Dec 5, 2014, 1:49:23 AM12/5/14
to golan...@googlegroups.com
Write a wrapper func in C, which gets that parameter as int, and casts it to SQLPOINTER.

brainman

unread,
Dec 5, 2014, 3:03:33 AM12/5/14
to golan...@googlegroups.com
On Friday, 5 December 2014 17:49:23 UTC+11, Tamás Gulácsi wrote:
Write a wrapper func in C, which gets that parameter as int, and casts it to SQLPOINTER.

I will try that. Thank you.

Alex 

Stephen Gutekanst

unread,
Dec 5, 2014, 3:39:00 PM12/5/14
to golan...@googlegroups.com
Don't use `int` for things like this. It's size is not guaranteed to be the size of a pointer. For instance in older versions of Go it was 32-bits on a 64-bit computer.

Use `uintptr` as that should always be the size of a machine word. Also the GC won't scan `uintptr` to see if it's invalid or not, so it'll work just fine.

- Stephen

brainman

unread,
Dec 5, 2014, 4:30:55 PM12/5/14
to golan...@googlegroups.com
On Saturday, 6 December 2014 07:39:00 UTC+11, Stephen Gutekanst wrote:
Don't use `int` for things like this. It's size is not guaranteed to be the size of a pointer. ...

I do not see how it maters here. There are 2 possible values for this parameter: 0 and 1. But uintptr will work too.

Alex

Stephen Gutekanst

unread,
Dec 5, 2014, 5:32:51 PM12/5/14
to brainman, golang-nuts
If the intent is to unsafely cast `int` to `void*` then it would matter. It depends on how complex the C API is, realistically.

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/4wk4fNRZ0p4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Follow me on twitter @slimsag.

brainman

unread,
Dec 5, 2014, 6:39:29 PM12/5/14
to golan...@googlegroups.com, alex.b...@gmail.com
On Saturday, 6 December 2014 09:32:51 UTC+11, Stephen Gutekanst wrote:
If the intent is to unsafely cast `int` to `void*` then it would matter. ...

Sure. But that is NOT my intention. I need to be able to pass one of 0 or 1 into C function that accepts void*. In a way that new (go1.4) gc does not complains about it. For that purpose previously suggested approach sounds reasonable to me.

Alex
Reply all
Reply to author
Forward
0 new messages