From a857b45bac55d1e7954994b72126099c5e44c71f Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Thu, 20 Feb 2014 09:24:02 -0700 Subject: [PATCH] Check for sequence overflow. --- const.go | 7 +++++++ error.go | 4 ++++ rwtransaction.go | 6 ++++++ rwtransaction_test.go | 15 +++++++++++++++ 4 files changed, 32 insertions(+) diff --git a/const.go b/const.go index 9ad7d25..00228be 100644 --- a/const.go +++ b/const.go @@ -2,6 +2,13 @@ package bolt const version = 1 +const ( + maxUint = ^uint(0) + minUint = 0 + maxInt = int(^uint(0) >> 1) + minInt = -maxInt - 1 +) + const ( // MaxBucketNameSize is the maximum length of a bucket name, in bytes. MaxBucketNameSize = 255 diff --git a/error.go b/error.go index bad074e..7238203 100644 --- a/error.go +++ b/error.go @@ -38,6 +38,10 @@ var ( // ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize. ErrValueTooLarge = &Error{"value too large", nil} + + // ErrSequenceOverflow is returned when the next sequence number will be + // larger than the maximum integer size. + ErrSequenceOverflow = &Error{"sequence overflow", nil} ) // Error represents an error condition caused by Bolt. diff --git a/rwtransaction.go b/rwtransaction.go index 57135f3..84e6425 100644 --- a/rwtransaction.go +++ b/rwtransaction.go @@ -82,6 +82,12 @@ func (t *RWTransaction) NextSequence(name string) (int, error) { return 0, ErrBucketNotFound } + // Make sure next sequence number will not be larger than the maximum + // integer size of the system. + if b.bucket.sequence == uint64(maxInt) { + return 0, ErrSequenceOverflow + } + // Increment and return the sequence. b.bucket.sequence++ diff --git a/rwtransaction_test.go b/rwtransaction_test.go index ea84b87..18b6ae9 100644 --- a/rwtransaction_test.go +++ b/rwtransaction_test.go @@ -136,6 +136,21 @@ func TestRWTransactionNextSequence(t *testing.T) { }) } +// Ensure that incrementing past the maximum sequence number will return an error. +func TestRWTransactionNextSequenceOverflow(t *testing.T) { + withOpenDB(func(db *DB, path string) { + db.CreateBucket("widgets") + db.Do(func(txn *RWTransaction) error { + b := txn.Bucket("widgets") + b.bucket.sequence = uint64(maxInt) + seq, err := txn.NextSequence("widgets") + assert.Equal(t, err, ErrSequenceOverflow) + assert.Equal(t, seq, 0) + return nil + }) + }) +} + // Ensure that an error is returned when inserting into a bucket that doesn't exist. func TestRWTransactionPutBucketNotFound(t *testing.T) { withOpenDB(func(db *DB, path string) {