Skip to content

Slice Bounds Out of Range in packets.go #254

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
dethtron5000 opened this issue Jul 8, 2014 · 4 comments
Closed

Slice Bounds Out of Range in packets.go #254

dethtron5000 opened this issue Jul 8, 2014 · 4 comments

Comments

@dethtron5000
Copy link

I am getting the following panic after running rows.Next(). I've verified that the returned rows object is not nil prior to running Next() This seems to only occur when there are multiple goroutines trying to communicate with the database.

panic: runtime error: slice bounds out of range
goroutine 324 [running]:
runtime.panic(0x73cb20, 0xae382a)
        /usr/lib/go/src/pkg/runtime/panic.c:266 +0xb6
github.com/go-sql-driver/mysql.(*binaryRows).readRow(0xc2103df940, 0xc2104b3f00, 0xf, 0xf, 0x41c976, ...)
        /home/pete/labs/usertransporter/src/github.com/go-sql-driver/mysql/packets.go:1046 +0xa5c
github.com/go-sql-driver/mysql.(*binaryRows).Next(0xc2103df940, 0xc2104b3f00, 0xf, 0xf, 0xf, ...)
        /home/pete/labs/usertransporter/src/github.com/go-sql-driver/mysql/rows.go:65 +0xc9
database/sql.(*Rows).Next(0xc2104d5e40, 0x7ff2e123be90)
        /usr/lib/go/src/pkg/database/sql/sql.go:1509 +0x14f
dbloader.(*dbDescriptor).fetchUserData(0xc210126b70, 0xc2103a72a0)
        /home/pete/labs/usertransporter/src/dbloader/dbloader.go:162 +0x7d5
created by dbloader.(*dbDescriptor).Add
        /home/pete/labs/usertransporter/src/dbloader/dbloader.go:137 +0xcf

It seems like the pos variable here is causing the issue:
dest[i], isNull, n, err = readLengthEncodedString(data[pos:])

I can verify that pos exceeds the length of the data slice:
reading from position: 78 length: 76 capacity: 3274

Please let me know if there's anything else that can help you with this bug.

@julienschmidt
Copy link
Member

The following information would be helpful:

  • Go version
  • Driver version, if not the latest: update and reproduce the panic with the current version
  • MySQL Server version
  • Query and code snippet causing this panic

@dethtron5000
Copy link
Author

go version: 1.2.1 linux/amd64
mysql version: 5.1.56
driver version: latest as of this morning (master branch, fresh pull)
query and relevant code: at bottom of this ticket

I have narrowed down the replication conditions a bit. The query that is blowing up can either come up empty (return no rows) or return rows. The panics only seem to occur only when a query which returns rows follows a query which comes up empty. So:

q1 -> row
q2 -> row
... 
qn -> row
no panic

q1 -> row
q2 -> row
q3 -> no row
q4 -> row 
panic

The code is passing a prepared statement on a channel via a struct to a pool of workers (using a worker pool to limit connections to the database).

######## function where panic occurs
// Fetches a user and adds, removes or updates their data as needed by the returned data.
func (d *dbDescriptor) fetchData(qry querytransport) {

    qry.statement = d.statements["statusQuery"] // d.statements is map[string]*sql.Stmt
    qry.listenChan = make(chan *sql.Rows)

    d.wpChan <- qry // send the query to the worker pool 

    rows := <-qry.listenChan

    b := rows.Next() // panic occurs here

    if b {

        _, s := formatSyscall(rows) // this assigns the results to a struct and preps it to send to the next step
        rows.Close()
        d.OutChan <- s
    } else {
        rows.Close()
        // if nothing returned, send an empty system call back to the channel
        // this helps do flow control in later steps
        s := new(syscall)

        d.OutChan <- s

    }
}


// This is a worker pool launched in the setup step.
func queryWorker(wpChan chan querytransport) {
    for ut := range wpChan {

        rows, err := ut.statement.Query(ut.userId)

        if err == nil {
            ut.listenChan <- rows
        } else {
            ut.listenChan <- nil // this isn't happening, but I'm checking for the case anyway
        }
        close(ut.listenChan)
    }
}

Here is the query. I've had to redact most of the field names and tables, but I have the type after each in comments. I have also tried explicitly CAST-ing the type in each field.

SELECT DISTINCT
            `e`, // char
            `ui`, // unsigned int
            `pc`, // char 
            `st`, // char
            `ci`,  // char
            `fn`, // char
            `ln`, // char
            `g`, // unsigned int
            `bd`, // date
            `etid`, // unsigned int
            IF(
                (SELECT 
                    1 
                FROM  
                    `uc`.`vt` 
                WHERE 
                    `pp` > 0 
                LIMIT 0,1),1,0) as `ipd`, // unsigned int
            IF(
                (SELECT 
                    1 
                FROM  
                    `vtc` 
                WHERE 
                    `pp` = 0 
                LIMIT 0,1) as `ifp`, // unsigned int
            IF(
                (SELECT 
                    1 
                FROM 
                    `dco` 
                WHERE 

                    CURDATE() BETWEEN `start_date` AND `end_date` 
                LIMIT 0,1 ) as `ics`, // unsigned int

               IF((SELECT 
                     `typ` 
                FROM `table`
                WHERE 
                   `condition`
                LIMIT 0,1) IS NULL, 'NONE',`typ`)  as `styp`, // char
            IF(`pff` = 1,'HTML','TEXT') as `ef` // char

        FROM
        [tables]
        WHERE 
        [where]

Please let me know if you need more information or if there is anything I can do to help.

@arnehormann
Copy link
Member

Hi @dethtron5000, sorry for the long wait.
The code sample you sent doesn't help to diagnose the error, there's too much context missing and in my opinion, your Go usage is unusual - it feels like overuse of channels.
Judging from your snippet, I'm inclined to say this is not a driver bug but one in your code.
Can you build a small program also generating the error (please stay well under 200 lines - more is ok, but less is better)?
It shouldn't do anything else but produce the error.

Update some hours later, this unfortunately reads a lot harsher than I intended, sorry.
Concerning the test code, can you somehow condense the problem? There are examples in #257 (http://play.golang.org/p/ivHnWaBGbQ) and #185. Maybe your bug is also related to the one in #185. Do you use multiple different Goroutines to access one Rows instance?

@julienschmidt
Copy link
Member

Closed for now because of inactivity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants