Skip to content

Commit e5d1518

Browse files
committed
fix: fix panic in tx.check
Signed-off-by: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com>
1 parent 7c7b05c commit e5d1518

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

tx_check.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ func (tx *Tx) Check(options ...CheckOption) <-chan error {
3636
}
3737

3838
func (tx *Tx) check(cfg checkConfig, ch chan error) {
39+
defer func() {
40+
if r := recover(); r != nil {
41+
ch <- panicked{r}
42+
}
43+
}()
3944
// Force loading free list if opened in ReadOnly mode.
4045
tx.db.loadFreelist()
4146

tx_check_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,43 @@ func TestTx_Check_WithNestBucket(t *testing.T) {
120120
db.MustClose()
121121
}
122122

123+
func TestTx_Check_Panic(t *testing.T) {
124+
bucketName := []byte("data")
125+
t.Log("Creating db file.")
126+
db := btesting.MustCreateDBWithOption(t, &bbolt.Options{PageSize: 4096})
127+
128+
// Each page can hold roughly 20 key/values pair, so 100 such
129+
// key/value pairs will consume about 5 leaf pages.
130+
err := db.Fill(bucketName, 1, 100,
131+
func(tx int, k int) []byte { return []byte(fmt.Sprintf("%04d", k)) },
132+
func(tx int, k int) []byte { return make([]byte, 100) },
133+
)
134+
require.NoError(t, err)
135+
136+
corruptRootPage(t, db.DB, bucketName)
137+
138+
path := db.Path()
139+
140+
require.NoError(t, db.Close())
141+
142+
db = btesting.MustOpenDBWithOption(t, path, &bbolt.Options{PageSize: 4096})
143+
144+
vErr := db.View(func(tx *bbolt.Tx) error {
145+
errChan := tx.Check()
146+
for cErr := range errChan {
147+
fmt.Println("cErr", cErr)
148+
return cErr
149+
}
150+
return nil
151+
})
152+
require.Error(t, vErr)
153+
require.ErrorContains(t, vErr, "has unexpected type/flags: 0")
154+
155+
// Manually close the db, otherwise the PostTestCleanup will
156+
// check the db again and accordingly fail the test.
157+
db.MustClose()
158+
}
159+
123160
// corruptRandomLeafPage corrupts one random leaf page.
124161
func corruptRandomLeafPageInBucket(t testing.TB, db *bbolt.DB, bucketName []byte) (victimPageId common.Pgid, validPageIds []common.Pgid) {
125162
bucketRootPageId := mustGetBucketRootPage(t, db, bucketName)
@@ -152,6 +189,18 @@ func corruptRandomLeafPageInBucket(t testing.TB, db *bbolt.DB, bucketName []byte
152189
return victimPageId, validPageIds
153190
}
154191

192+
func corruptRootPage(t testing.TB, db *bbolt.DB, bucketName []byte) {
193+
bucketRootPageId := mustGetBucketRootPage(t, db, bucketName)
194+
bucketRootPage, bucketRootPageBuf, err := guts_cli.ReadPage(db.Path(), uint64(bucketRootPageId))
195+
require.NoError(t, err)
196+
require.True(t, bucketRootPage.IsBranchPage())
197+
198+
bucketRootPage.SetFlags(0)
199+
200+
err = guts_cli.WritePage(db.Path(), bucketRootPageBuf)
201+
require.NoError(t, err)
202+
}
203+
155204
// mustGetBucketRootPage returns the root page for the provided bucket.
156205
func mustGetBucketRootPage(t testing.TB, db *bbolt.DB, bucketName []byte) common.Pgid {
157206
var rootPageId common.Pgid

0 commit comments

Comments
 (0)