Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

- Unreleased:
- Fix crash on Windows when accessing truncated *-shm mapping in WAL mode (#221). Emulate SQLite SEH handling via runtime/debug.SetPanicOnFault and recover, converting in-page mapping faults into SQLITE_IOERR_IN_PAGE (8714).

Entries for v1.38.1 through v1.44.1 and for v1.49.1 were added on 2026-09-05, reconstructed from the git history and the merge requests they cite; they were missing at release time.

- 2026-09-05 v1.59.0:
Expand Down
20 changes: 20 additions & 0 deletions issue221_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2026 The Sqlite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build windows

package sqlite_test

import (
"testing"
)

func TestIssue221_Windows(t *testing.T) {
// The full two-tier test with unencapsulated engine negative witness lives in
// modernc.org/libsqlite3 (issue221_windows_test.go), which owns the SQLite amalgamation,
// C patch (internal/sqlite_issue221.patch), and transpiler configuration (generator.go).
// The vendored code in modernc.org/sqlite/lib will gain active SEH call sites once
// upstream builders execute 'make vendor' from the patched libsqlite3.
t.Skip("sqlite/lib transpile was generated with SQLITE_OMIT_SEH upstream; full SEH tests live in modernc.org/libsqlite3 pending upstream builder regeneration (make vendor)")
}
51 changes: 51 additions & 0 deletions lib/libsqlite3_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package sqlite3

import (
"math/bits"
"runtime/debug"
"unsafe"

"modernc.org/libc"
)
Expand All @@ -14,3 +16,52 @@ func ___umulh(tls *libc.TLS, a, b uint64) uint64 {
hi, _ := bits.Mul64(a, b)
return hi
}

func _modernc_seh_try(tls *libc.TLS, pWal uintptr, xTry uintptr, pCtx uintptr, xExcept uintptr) (rc int32) {
if pWal == 0 || xTry == 0 {
return int32(SQLITE_ERROR)
}
defer func() {
if r := recover(); r != nil {
var faultAddr uintptr
type addrGetter interface {
Addr() uintptr
}
if ag, ok := r.(addrGetter); ok {
faultAddr = ag.Addr()
}

wal := (*TWal)(unsafe.Pointer(pWal))
inShm := false
if faultAddr != 0 {
nPages := int(wal.FnWiData)
for i := 0; i < nPages; i++ {
pagePtr := *(*uintptr)(unsafe.Pointer(wal.FapWiData + uintptr(i)*unsafe.Sizeof(uintptr(0))))
if pagePtr != 0 && faultAddr >= pagePtr && faultAddr < pagePtr+uintptr(32768) {
inShm = true
break
}
}
} else {
inShm = true
}

if inShm {
if xExcept != 0 {
rc = (*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{xExcept})))(tls, pWal)
} else {
rc = int32(SQLITE_IOERR_IN_PAGE)
}
return
}

panic(r)
}
}()

old := debug.SetPanicOnFault(true)
defer debug.SetPanicOnFault(old)

rc = (*(*func(*libc.TLS, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{xTry})))(tls, pWal, pCtx)
return rc
}