From 21aff4c9f5274f68cdba6259cf3a29af695d1828 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Mon, 27 Feb 2023 03:20:23 +0000 Subject: [PATCH] Towards incremental blobs. --- api.go | 16 ++++++++++++++-- conn.go | 23 +++++++++++++---------- conn_test.go | 29 ++++++++++++++++++++++++----- const.go | 2 ++ embed/build.sh | 10 ++++++++-- embed/sqlite3.wasm | Bin 1034734 -> 1035380 bytes mem.go | 11 +++++++---- mem_test.go | 7 +++++++ stmt.go | 4 ++-- vfs.go | 10 +++++----- 10 files changed, 82 insertions(+), 30 deletions(-) diff --git a/api.go b/api.go index 0b0e598..1fbbbf9 100644 --- a/api.go +++ b/api.go @@ -30,8 +30,8 @@ func newConn(ctx context.Context, module api.Module) (_ *Conn, err error) { ctx: ctx, mem: memory{module}, api: sqliteAPI{ - malloc: getFun("malloc"), free: getFun("free"), + malloc: getFun("malloc"), destructor: uint64(getPtr("malloc_destructor")), errcode: getFun("sqlite3_errcode"), errstr: getFun("sqlite3_errstr"), @@ -66,6 +66,12 @@ func newConn(ctx context.Context, module api.Module) (_ *Conn, err error) { lastRowid: getFun("sqlite3_last_insert_rowid"), changes: getFun("sqlite3_changes64"), interrupt: getFun("sqlite3_interrupt"), + blobOpen: getFun("sqlite3_blob_open"), + blobClose: getFun("sqlite3_blob_close"), + blobReopen: getFun("sqlite3_blob_reopen"), + blobBytes: getFun("sqlite3_blob_bytes"), + blobRead: getFun("sqlite3_blob_read"), + blobWrite: getFun("sqlite3_blob_write"), }, } if err != nil { @@ -75,8 +81,8 @@ func newConn(ctx context.Context, module api.Module) (_ *Conn, err error) { } type sqliteAPI struct { - malloc api.Function free api.Function + malloc api.Function destructor uint64 errcode api.Function errstr api.Function @@ -111,4 +117,10 @@ type sqliteAPI struct { lastRowid api.Function changes api.Function interrupt api.Function + blobOpen api.Function + blobClose api.Function + blobReopen api.Function + blobBytes api.Function + blobRead api.Function + blobWrite api.Function } diff --git a/conn.go b/conn.go index cdce31a..6d5cdbf 100644 --- a/conn.go +++ b/conn.go @@ -333,8 +333,11 @@ func (c *Conn) free(ptr uint32) { c.call(c.api.free, uint64(ptr)) } -func (c *Conn) new(size uint32) uint32 { - r := c.call(c.api.malloc, uint64(size)) +func (c *Conn) new(size uint64) uint32 { + if size > _MAX_ALLOCATION_SIZE { + panic(oomErr) + } + r := c.call(c.api.malloc, size) ptr := uint32(r[0]) if ptr == 0 && size != 0 { panic(oomErr) @@ -346,22 +349,22 @@ func (c *Conn) newBytes(b []byte) uint32 { if b == nil { return 0 } - ptr := c.new(uint32(len(b))) + ptr := c.new(uint64(len(b))) c.mem.writeBytes(ptr, b) return ptr } func (c *Conn) newString(s string) uint32 { - ptr := c.new(uint32(len(s) + 1)) + ptr := c.new(uint64(len(s) + 1)) c.mem.writeString(ptr, s) return ptr } -func (c *Conn) newArena(size uint32) arena { +func (c *Conn) newArena(size uint64) arena { return arena{ c: c, - size: size, base: c.new(size), + size: uint32(size), } } @@ -390,10 +393,10 @@ func (a *arena) reset() { a.next = 0 } -func (a *arena) new(size uint32) uint32 { - if a.next+size <= a.size { +func (a *arena) new(size uint64) uint32 { + if size <= uint64(a.size-a.next) { ptr := a.base + a.next - a.next += size + a.next += uint32(size) return ptr } ptr := a.c.new(size) @@ -402,7 +405,7 @@ func (a *arena) new(size uint32) uint32 { } func (a *arena) string(s string) uint32 { - ptr := a.new(uint32(len(s) + 1)) + ptr := a.new(uint64(len(s) + 1)) a.c.mem.writeString(ptr, s) return ptr } diff --git a/conn_test.go b/conn_test.go index d12bbcd..7aff16d 100644 --- a/conn_test.go +++ b/conn_test.go @@ -6,6 +6,20 @@ import ( "testing" ) +func TestConn_error_OOM(t *testing.T) { + t.Parallel() + + db, err := Open(":memory:") + if err != nil { + t.Fatal(err) + } + defer db.Close() + + defer func() { _ = recover() }() + db.error(uint64(NOMEM)) + t.Error("want panic") +} + func TestConn_call_nil(t *testing.T) { t.Parallel() @@ -29,9 +43,14 @@ func TestConn_new(t *testing.T) { } defer db.Close() - defer func() { _ = recover() }() - db.new(math.MaxUint32) - t.Error("want panic") + testOOM := func(size uint64) { + defer func() { _ = recover() }() + db.new(size) + t.Error("want panic") + } + + testOOM(math.MaxUint32) + testOOM(_MAX_ALLOCATION_SIZE) } func TestConn_newArena(t *testing.T) { @@ -88,7 +107,7 @@ func TestConn_newBytes(t *testing.T) { } want := buf - if got := db.mem.view(ptr, uint32(len(want))); !bytes.Equal(got, want) { + if got := db.mem.view(ptr, uint64(len(want))); !bytes.Equal(got, want) { t.Errorf("got %q, want %q", got, want) } } @@ -114,7 +133,7 @@ func TestConn_newString(t *testing.T) { } want := str + "\000" - if got := db.mem.view(ptr, uint32(len(want))); string(got) != want { + if got := db.mem.view(ptr, uint64(len(want))); string(got) != want { t.Errorf("got %q, want %q", got, want) } } diff --git a/const.go b/const.go index 62db4c8..7edd141 100644 --- a/const.go +++ b/const.go @@ -12,6 +12,8 @@ const ( _MAX_STRING = 512 // Used for short strings: names, error messages… _MAX_PATHNAME = 512 + _MAX_ALLOCATION_SIZE = 0x7ffffeff + ptrlen = 4 ) diff --git a/embed/build.sh b/embed/build.sh index d80d08d..e5f1c00 100755 --- a/embed/build.sh +++ b/embed/build.sh @@ -13,8 +13,8 @@ zig cc --target=wasm32-wasi -flto -g0 -Os \ -mbulk-memory -mreference-types \ -mnontrapping-fptoint -msign-ext \ -D_HAVE_SQLITE_CONFIG_H \ - -Wl,--export=malloc \ -Wl,--export=free \ + -Wl,--export=malloc \ -Wl,--export=malloc_destructor \ -Wl,--export=sqlite3_errcode \ -Wl,--export=sqlite3_errstr \ @@ -45,7 +45,13 @@ zig cc --target=wasm32-wasi -flto -g0 -Os \ -Wl,--export=sqlite3_column_text \ -Wl,--export=sqlite3_column_blob \ -Wl,--export=sqlite3_column_bytes \ + -Wl,--export=sqlite3_blob_open \ + -Wl,--export=sqlite3_blob_close \ + -Wl,--export=sqlite3_blob_bytes \ + -Wl,--export=sqlite3_blob_read \ + -Wl,--export=sqlite3_blob_write \ + -Wl,--export=sqlite3_blob_reopen \ -Wl,--export=sqlite3_get_autocommit \ -Wl,--export=sqlite3_last_insert_rowid \ -Wl,--export=sqlite3_changes64 \ - -Wl,--export=sqlite3_interrupt \ + -Wl,--export=sqlite3_interrupt \ \ No newline at end of file diff --git a/embed/sqlite3.wasm b/embed/sqlite3.wasm index 56e68a94fe894c18633ae05593cc200601c85e59..8bed1fce76d8a7072099cfddbbe5044720f239d7 100755 GIT binary patch delta 36736 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 LiM!4pMvC|UA)6+6 delta 35973 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 F{2wf?Cw~9{ diff --git a/mem.go b/mem.go index a29ae62..c1e77a0 100644 --- a/mem.go +++ b/mem.go @@ -11,11 +11,14 @@ type memory struct { mod api.Module } -func (m memory) view(ptr, size uint32) []byte { +func (m memory) view(ptr uint32, size uint64) []byte { if ptr == 0 { panic(nilErr) } - buf, ok := m.mod.Memory().Read(ptr, size) + if size > math.MaxUint32 { + panic(rangeErr) + } + buf, ok := m.mod.Memory().Read(ptr, uint32(size)) if !ok { panic(rangeErr) } @@ -100,12 +103,12 @@ func (m memory) readString(ptr, maxlen uint32) string { } func (m memory) writeBytes(ptr uint32, b []byte) { - buf := m.view(ptr, uint32(len(b))) + buf := m.view(ptr, uint64(len(b))) copy(buf, b) } func (m memory) writeString(ptr uint32, s string) { - buf := m.view(ptr, uint32(len(s)+1)) + buf := m.view(ptr, uint64(len(s)+1)) buf[len(s)] = 0 copy(buf, s) } diff --git a/mem_test.go b/mem_test.go index 3a9836c..54322bf 100644 --- a/mem_test.go +++ b/mem_test.go @@ -19,6 +19,13 @@ func Test_memory_view_range(t *testing.T) { t.Error("want panic") } +func Test_memory_view_overflow(t *testing.T) { + defer func() { _ = recover() }() + mem := newMemory(128) + mem.view(1, math.MaxInt64) + t.Error("want panic") +} + func Test_memory_readUint32_nil(t *testing.T) { defer func() { _ = recover() }() mem := newMemory(128) diff --git a/stmt.go b/stmt.go index f739078..76813bc 100644 --- a/stmt.go +++ b/stmt.go @@ -347,7 +347,7 @@ func (s *Stmt) ColumnText(col int) string { r = s.c.call(s.c.api.columnBytes, uint64(s.handle), uint64(col)) - mem := s.c.mem.view(ptr, uint32(r[0])) + mem := s.c.mem.view(ptr, r[0]) return string(mem) } @@ -370,7 +370,7 @@ func (s *Stmt) ColumnBlob(col int, buf []byte) []byte { r = s.c.call(s.c.api.columnBytes, uint64(s.handle), uint64(col)) - mem := s.c.mem.view(ptr, uint32(r[0])) + mem := s.c.mem.view(ptr, r[0]) return append(buf[0:0], mem...) } diff --git a/vfs.go b/vfs.go index 4251068..46f0562 100644 --- a/vfs.go +++ b/vfs.go @@ -85,7 +85,7 @@ func vfsLocaltime(ctx context.Context, mod api.Module, t uint64, pTm uint32) uin } func vfsRandomness(ctx context.Context, mod api.Module, pVfs, nByte, zByte uint32) uint32 { - mem := memory{mod}.view(zByte, nByte) + mem := memory{mod}.view(zByte, uint64(nByte)) n, _ := rand.Reader.Read(mem) return uint32(n) } @@ -119,8 +119,8 @@ func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative, nFull // Or using [os.Readlink] to resolve a symbolic link (as the Unix VFS did). // This might be buggy on Windows (the Windows VFS doesn't try). - size := uint32(len(abs) + 1) - if size > nFull { + size := uint64(len(abs) + 1) + if size > uint64(nFull) { return uint32(CANTOPEN_FULLPATH) } mem := memory{mod}.view(zFull, size) @@ -246,7 +246,7 @@ func vfsClose(ctx context.Context, mod api.Module, pFile uint32) uint32 { } func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst uint64) uint32 { - buf := memory{mod}.view(zBuf, iAmt) + buf := memory{mod}.view(zBuf, uint64(iAmt)) file := vfsFilePtr{mod, pFile}.OSFile() n, err := file.ReadAt(buf, int64(iOfst)) @@ -263,7 +263,7 @@ func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfs } func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst uint64) uint32 { - buf := memory{mod}.view(zBuf, iAmt) + buf := memory{mod}.view(zBuf, uint64(iAmt)) file := vfsFilePtr{mod, pFile}.OSFile() _, err := file.WriteAt(buf, int64(iOfst))