Skip to content
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

database/sql: Stmt.Close() causing segfault #14681

Closed
RobinGeuze opened this issue Mar 7, 2016 · 7 comments
Closed

database/sql: Stmt.Close() causing segfault #14681

RobinGeuze opened this issue Mar 7, 2016 · 7 comments

Comments

@RobinGeuze
Copy link

I encountered a crash in a defered Stmt.Close().

Go version:
go1.6 freebsd/amd64

getPropsStatement, err := connection.Prepare("Some random query")
if err != nil {
return result, err
}
defer getPropsStatement.Close()

Connection is of the type *sql.DB. Am I doing something wrong or is this a weird bug.

Stack trace:

unexpected fault address 0x4cb7c7

fatal error: fault
[signal 0xa code=0x3 addr=0x4cb7c7 pc=0x4cb7c7]

goroutine 8063085 [running]:
runtime.throw(0x8a9678, 0x5)
/usr/local/go/src/runtime/panic.go:530 +0x90 fp=0xc8295086d8 sp=0xc8295086c0
runtime.sigpanic()
/usr/local/go/src/runtime/sigpanic_unix.go:21 +0x1e4 fp=0xc829508728 sp=0xc8295086d8
database/sql.(*DB).noteUnusedDriverStatement(0xc8200e62c0, 0x31302f73656c6966, 0x800d3d028, 0xc828b8fda0)
/usr/local/go/src/database/sql/sql.go:855 +0x77 fp=0xc829508790 sp=0xc829508728
database/sql.(*Stmt).finalClose(0xc821c83e00, 0x0, 0x0)
/usr/local/go/src/database/sql/sql.go:1711 +0x144 fp=0xc829508818 sp=0xc829508790
database/sql.(finalCloser).(database/sql.finalClose)-fm(0x0, 0x0)
/usr/local/go/src/database/sql/sql.go:449 +0x40 fp=0xc829508848 sp=0xc829508818
database/sql.(*DB).removeDep(0xc8200e62c0, 0x800d3d068, 0xc821c83e00, 0x871440, 0xc821c83e00, 0x0, 0x0)
/usr/local/go/src/database/sql/sql.go:428 +0xa5 fp=0xc829508888 sp=0xc829508848
database/sql.(*Stmt).Close(0xc821c83e00, 0x0, 0x0)
/usr/local/go/src/database/sql/sql.go:1703 +0x235 fp=0xc829508918 sp=0xc829508888

@bradfitz bradfitz changed the title sql/database: Stmt.Close() causing segfault database/sql: Stmt.Close() causing segfault Mar 7, 2016
@bradfitz
Copy link
Contributor

bradfitz commented Mar 7, 2016

We need much more info.

Please provide the complete yet minimal source code to cause the crash. Also: which driver? (although that would be obvious from a complete example)

@RobinGeuze
Copy link
Author

The driver in question is https://github.com/go-sql-driver/mysql

As said I haven't actually been able to reliable reproduce it. The code in question is running on a couple dozen machines serving thousands if not millions of requests a day that run this code path and I have seen the crash happen only once in the last 5 days or so.

The codebase this happens in is quite extensive but the basic flow is something like:
Run http.ListenAndServe
Handle request -> connect to database
Handle new request -> build prepared statement, defer statement close, execute statement (one or multiple times), defer Rows close return data (and thus execute defered functions). All of this happens within one function.

@RobinGeuze
Copy link
Author

So I still haven't been able to reliably reproduce the crasher yet but the following code runs into the similar other issues I've noticed.

If I remove the SetConnMaxLifeTime and ensure MaxOpen and MaxIdle are equal most of the issues seem to disappear.

package main

import (
    "fmt"
    "time"

    "database/sql"

    _ "github.com/go-sql-driver/mysql"
)

func createPreparedStatement(conn *sql.DB) (*sql.Stmt, error) {
    return conn.Prepare("SELECT uid FROM oc_users")
}

func executeStatement(stmt *sql.Stmt) {
    var result sql.NullString
    err := stmt.QueryRow().Scan(&result)
    if err != nil {
        fmt.Printf("%v\n", err)
    }
}

func doStatementStuff(conn *sql.DB) {
    stmt, err := createPreparedStatement(conn)
    if err != nil {
        fmt.Printf("%v\n", err)
    }
    executeStatement(stmt)
    err = stmt.Close()
    if err != nil {
        fmt.Printf("%v\n", err)
    }
}

var globStatement *sql.Stmt

func main() {
    conn, err := sql.Open("mysql", "root@tcp(localhost:3306)/owncloud")
    conn.SetMaxOpenConns(5)
    conn.SetMaxIdleConns(3)
    conn.SetConnMaxLifetime(time.Second * 1)
    globStatement, err := createPreparedStatement(conn)
    if err != nil {
        fmt.Printf("%v\n", err)
    }
    for {
        for i := 0; i < 20; i++ {
            go doStatementStuff(conn)
            go executeStatement(globStatement)
        }
        time.Sleep(time.Millisecond * 10)
    }
}

@cespare
Copy link
Contributor

cespare commented Mar 8, 2016

So I still haven't been able to reliably reproduce the crasher yet but the following code runs into the similar other issues I've noticed.

What are "similar other issues"? Can you show errors/panics? If they're different from the original issue, they should probably be separate bugs.

@bradfitz bradfitz added this to the Unplanned milestone Apr 10, 2016
@methane
Copy link
Contributor

methane commented Jun 9, 2016

@RobinGeuze "similar other issue" is #16019, isn't it?

@RobinGeuze
Copy link
Author

Could be yes, tbh I have removed prepared statement based queries from my codebase, which "Fixed" the issue.

@kardianos
Copy link
Contributor

I suspect this is fixed now when #16019 was closed. If it is still failing on master/go1.8 please re-open.

@golang golang locked and limited conversation to collaborators Nov 28, 2017
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