wazero: Failure executing sqlite3 after bedde6d (at and preopen semantics)

Describe the bug

After bedde6d I’m getting some rather inscrutable bugs while testing github.com/ncruces/go-sqlite3.

I’m not entirely sure what’s going on.

To Reproduce

git clone --branch crash https://github.com/ncruces/go-sqlite3
cd go-sqlite3
./build_deps.sh
go run ./cmd

This panics inside my own code with the following error:

panic: module "sqlite3-1" closed with exit_code(71)

goroutine 1 [running]:
github.com/ncruces/go-sqlite3.(*Conn).free(0xc0000e26c0, 0x10cc20)
	/Users/cruces/Desktop/go-sqlite3/conn.go:166 +0xa5
github.com/ncruces/go-sqlite3.Open({0x11ab821, 0x7}, 0x0, {0x0, 0x0})
	/Users/cruces/Desktop/go-sqlite3/conn.go:92 +0xa29
main.main()
	/Users/cruces/Desktop/go-sqlite3/cmd/main.go:11 +0x2f
exit status 2

It’s this section of code: https://github.com/ncruces/go-sqlite3/blob/7c3b679b7dcc8fe36cf87a59447ab1048bf1b4d0/conn.go#L86-L94

After calling c.api.open.Call (which does a bunch of WASI FS calls) any function call seems to return this error (I’m panicking free errors). I’m guessing some libc internal state somehow gets corrupted?

Expected behavior

The above repro should print this:

2023/01/12 15:08:14 sqlite3: disk I/O error
exit status 1

Or, after #1026, it should succeed in creating a test.db with some tables in it.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 20 (3 by maintainers)

Commits related to this issue

Most upvoted comments

I don’t think there’s anything actionable for wazero to do here, but I added a benchmark to github.com/ncruces/go-sqlite3 that compares it to crawshaw.io/sqlite, and thought you might be curious.

The results:

$ go test -bench=. -benchmem -benchtime=10s ./bench    
goos: darwin
goarch: amd64
pkg: github.com/ncruces/go-sqlite3/bench
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkCrawshaw-12    	      18	 655783355 ns/op	104002710 B/op	 8999998 allocs/op
BenchmarkWasm-12        	      12	 995722020 ns/op	178749920 B/op	11000099 allocs/op
PASS
ok  	github.com/ncruces/go-sqlite3/bench	26.639s

The large memory difference I assume is due to Cgo memory not being tracked, and this being a :memory: database. wazero will have a footprint, but it should be fixed (and amortized by caching the CompiledModule), not “per operation.” It might make sense to reuse the instantiated module (across connections), or pool connections themselves, neither of which I’m doing.

The 50% CPU difference is more relevant.

The “bad” news there that all the prestat chattiness makes a big difference (and there’s likely little wazero can do about that). The “good” news for sqlite3 is that this can mostly be avoided by implementing a Go VFS:

$ go test -bench=. -benchmem -benchtime=10s ./bench
goos: darwin
goarch: amd64
pkg: github.com/ncruces/go-sqlite3/bench
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkCrawshaw-12    	      18	 663649267 ns/op	104002825 B/op	 9000000 allocs/op
BenchmarkWasm-12        	      15	 719824482 ns/op	178749060 B/op	11000105 allocs/op
PASS
ok  	github.com/ncruces/go-sqlite3/bench	25.207s

On SQLite.

SQLite is among the most widely deployed software of any kind.

At 150k lines of very high quality code, it’s both highly sophisticated, but small enough that using it through WASM makes perfect sense. It’s also self-contained enough to make it possible (the entire OS interface is easy to pull out and reimplement in Go).

Given the community’s stance on Cgo, considerable effort has been spent to try to avoid it. This seems a much shorter path there, remains to be seen what are the advantages/disadvantages.

I’d been musing on the idea for a while, and Filippo finally pushed me there.

No, for dcraw I’m fine. I made the hacked filesystem that wouldn’t pass testing/fstest: that’s on me. But I’m actually happy with my fix. I created something that I can reuse elsewhere.

I’m more worried with SQLite. I just open the DB, and immediately almost any call into the module exits with that error. And SQLite is a little too big to inspect.

I don’t need WASI here. The intent is to bypass it entirely with a custom from scratch VFS. Besides for now this is just an exploration. I just had this hitch to scratch and Filippo pointed the way.