Skip to content

Commit

Permalink
Memory management.
Browse files Browse the repository at this point in the history
  • Loading branch information
ncruces committed Sep 9, 2024
1 parent c1915fe commit 9d77322
Show file tree
Hide file tree
Showing 13 changed files with 64 additions and 70 deletions.
11 changes: 4 additions & 7 deletions const.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@ const (
_ROW = 100 /* sqlite3_step() has another row ready */
_DONE = 101 /* sqlite3_step() has finished executing */

_UTF8 = 1

_MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings.
_MAX_LENGTH = 1e9
_MAX_SQL_LENGTH = 1e9
_MAX_ALLOCATION_SIZE = 0x7ffffeff
_MAX_FUNCTION_ARG = 100
_MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings.
_MAX_LENGTH = 1e9
_MAX_SQL_LENGTH = 1e9
_MAX_FUNCTION_ARG = 100

ptrlen = 4
)
Expand Down
20 changes: 8 additions & 12 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,17 @@ func (ctx Context) ResultFloat(value float64) {
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultText(value string) {
ptr := ctx.c.newString(value)
ctx.c.call("sqlite3_result_text64",
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
uint64(ctx.c.freer), _UTF8)
ctx.c.call("sqlite3_result_text_go",
uint64(ctx.handle), uint64(ptr), uint64(len(value)))
}

// ResultRawText sets the text result of the function to a []byte.
//
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultRawText(value []byte) {
ptr := ctx.c.newBytes(value)
ctx.c.call("sqlite3_result_text64",
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
uint64(ctx.c.freer), _UTF8)
ctx.c.call("sqlite3_result_text_go",
uint64(ctx.handle), uint64(ptr), uint64(len(value)))
}

// ResultBlob sets the result of the function to a []byte.
Expand All @@ -105,9 +103,8 @@ func (ctx Context) ResultRawText(value []byte) {
// https://sqlite.org/c3ref/result_blob.html
func (ctx Context) ResultBlob(value []byte) {
ptr := ctx.c.newBytes(value)
ctx.c.call("sqlite3_result_blob64",
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
uint64(ctx.c.freer))
ctx.c.call("sqlite3_result_blob_go",
uint64(ctx.handle), uint64(ptr), uint64(len(value)))
}

// ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB.
Expand Down Expand Up @@ -154,9 +151,8 @@ func (ctx Context) resultRFC3339Nano(value time.Time) {
buf := util.View(ctx.c.mod, ptr, maxlen)
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)

ctx.c.call("sqlite3_result_text64",
uint64(ctx.handle), uint64(ptr), uint64(len(buf)),
uint64(ctx.c.freer), _UTF8)
ctx.c.call("sqlite3_result_text_go",
uint64(ctx.handle), uint64(ptr), uint64(len(buf)))
}

// ResultPointer sets the result of the function to NULL, just like [Context.ResultNull],
Expand Down
Binary file modified embed/bcw2/bcw2.wasm
Binary file not shown.
14 changes: 7 additions & 7 deletions embed/exports.txt
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
aligned_alloc
free
malloc
malloc_destructor
sqlite3_anycollseq_init
sqlite3_autovacuum_pages_go
sqlite3_backup_finish
sqlite3_backup_init
sqlite3_backup_pagecount
sqlite3_backup_remaining
sqlite3_backup_step
sqlite3_bind_blob64
sqlite3_bind_blob_go
sqlite3_bind_double
sqlite3_bind_int64
sqlite3_bind_null
sqlite3_bind_parameter_count
sqlite3_bind_parameter_index
sqlite3_bind_parameter_name
sqlite3_bind_pointer_go
sqlite3_bind_text64
sqlite3_bind_text_go
sqlite3_bind_value
sqlite3_bind_zeroblob64
sqlite3_blob_bytes
Expand Down Expand Up @@ -74,17 +71,20 @@ sqlite3_filename_database
sqlite3_filename_journal
sqlite3_filename_wal
sqlite3_finalize
sqlite3_free
sqlite3_get_autocommit
sqlite3_get_auxdata
sqlite3_interrupt
sqlite3_last_insert_rowid
sqlite3_limit
sqlite3_malloc64
sqlite3_open_v2
sqlite3_overload_function
sqlite3_prepare_v3
sqlite3_progress_handler_go
sqlite3_realloc64
sqlite3_reset
sqlite3_result_blob64
sqlite3_result_blob_go
sqlite3_result_double
sqlite3_result_error
sqlite3_result_error_code
Expand All @@ -93,7 +93,7 @@ sqlite3_result_error_toobig
sqlite3_result_int64
sqlite3_result_null
sqlite3_result_pointer_go
sqlite3_result_text64
sqlite3_result_text_go
sqlite3_result_value
sqlite3_result_zeroblob64
sqlite3_rollback_hook_go
Expand Down
Binary file modified embed/sqlite3.wasm
Binary file not shown.
1 change: 1 addition & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
20 changes: 6 additions & 14 deletions sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ type sqlite struct {
mask uint32
}
stack [9]uint64
freer uint32
}

func instantiateSQLite() (sqlt *sqlite, err error) {
Expand All @@ -102,14 +101,7 @@ func instantiateSQLite() (sqlt *sqlite, err error) {
if err != nil {
return nil, err
}

global := sqlt.mod.ExportedGlobal("malloc_destructor")
if global == nil {
return nil, util.BadBinaryErr
}

sqlt.freer = util.ReadUint32(sqlt.mod, uint32(global.Get()))
if sqlt.freer == 0 {
if sqlt.getfn("sqlite3_progress_handler_go") == nil {
return nil, util.BadBinaryErr
}
return sqlt, nil
Expand Down Expand Up @@ -196,15 +188,15 @@ func (sqlt *sqlite) free(ptr uint32) {
if ptr == 0 {
return
}
sqlt.call("free", uint64(ptr))
sqlt.call("sqlite3_free", uint64(ptr))
}

func (sqlt *sqlite) new(size uint64) uint32 {
if size > _MAX_ALLOCATION_SIZE {
panic(util.OOMErr)
if size == 0 {
size = 1
}
ptr := uint32(sqlt.call("malloc", size))
if ptr == 0 && size != 0 {
ptr := uint32(sqlt.call("sqlite3_malloc64", size))
if ptr == 0 {
panic(util.OOMErr)
}
return ptr
Expand Down
13 changes: 13 additions & 0 deletions sqlite3/bind.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <stdlib.h>

#include "sqlite3.h"

int sqlite3_bind_text_go(sqlite3_stmt* stmt, int i, const char* zData,
sqlite3_uint64 nData) {
return sqlite3_bind_text64(stmt, i, zData, nData, &sqlite3_free, SQLITE_UTF8);
}

int sqlite3_bind_blob_go(sqlite3_stmt* stmt, int i, const char* zData,
sqlite3_uint64 nData) {
return sqlite3_bind_blob64(stmt, i, zData, nData, &sqlite3_free);
}
4 changes: 2 additions & 2 deletions sqlite3/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@
#include "ext/series.c"
#include "ext/uint.c"
// Bindings
#include "bind.c"
#include "column.c"
#include "func.c"
#include "hooks.c"
#include "pointer.c"
#include "result.c"
#include "time.c"
#include "vfs.c"
#include "vtab.c"

sqlite3_destructor_type malloc_destructor = &free;

__attribute__((constructor)) void init() {
sqlite3_initialize();
sqlite3_auto_extension((void (*)(void))sqlite3_base_init);
Expand Down
13 changes: 13 additions & 0 deletions sqlite3/result.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <stdlib.h>

#include "sqlite3.h"

void sqlite3_result_text_go(sqlite3_context* ctx, const char* zData,
sqlite3_uint64 nData) {
sqlite3_result_text64(ctx, zData, nData, &sqlite3_free, SQLITE_UTF8);
}

void sqlite3_result_blob_go(sqlite3_context* ctx, const void* zData,
sqlite3_uint64 nData) {
sqlite3_result_blob64(ctx, zData, nData, &sqlite3_free);
}
16 changes: 1 addition & 15 deletions sqlite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package sqlite3
import (
"bytes"
"math"
"os"
"testing"

"github.com/ncruces/go-sqlite3/internal/util"
Expand Down Expand Up @@ -39,7 +38,7 @@ func Test_sqlite_call_closed(t *testing.T) {
sqlite.close()

defer func() { _ = recover() }()
sqlite.call("free")
sqlite.call("sqlite3_free")
t.Error("want panic")
}

Expand All @@ -57,19 +56,6 @@ func Test_sqlite_new(t *testing.T) {
sqlite.new(math.MaxUint32)
t.Error("want panic")
})

t.Run("_MAX_ALLOCATION_SIZE", func(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
if os.Getenv("CI") != "" {
t.Skip("skipping in CI")
}
defer func() { _ = recover() }()
sqlite.new(_MAX_ALLOCATION_SIZE)
sqlite.new(_MAX_ALLOCATION_SIZE)
t.Error("want panic")
})
}

func Test_sqlite_newArena(t *testing.T) {
Expand Down
20 changes: 8 additions & 12 deletions stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,9 @@ func (s *Stmt) BindText(param int, value string) error {
return TOOBIG
}
ptr := s.c.newString(value)
r := s.c.call("sqlite3_bind_text64",
r := s.c.call("sqlite3_bind_text_go",
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(value)),
uint64(s.c.freer), _UTF8)
uint64(ptr), uint64(len(value)))
return s.c.error(r)
}

Expand All @@ -262,10 +261,9 @@ func (s *Stmt) BindRawText(param int, value []byte) error {
return TOOBIG
}
ptr := s.c.newBytes(value)
r := s.c.call("sqlite3_bind_text64",
r := s.c.call("sqlite3_bind_text_go",
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(value)),
uint64(s.c.freer), _UTF8)
uint64(ptr), uint64(len(value)))
return s.c.error(r)
}

Expand All @@ -279,10 +277,9 @@ func (s *Stmt) BindBlob(param int, value []byte) error {
return TOOBIG
}
ptr := s.c.newBytes(value)
r := s.c.call("sqlite3_bind_blob64",
r := s.c.call("sqlite3_bind_blob_go",
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(value)),
uint64(s.c.freer))
uint64(ptr), uint64(len(value)))
return s.c.error(r)
}

Expand Down Expand Up @@ -335,10 +332,9 @@ func (s *Stmt) bindRFC3339Nano(param int, value time.Time) error {
buf := util.View(s.c.mod, ptr, maxlen)
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)

r := s.c.call("sqlite3_bind_text64",
r := s.c.call("sqlite3_bind_text_go",
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(buf)),
uint64(s.c.freer), _UTF8)
uint64(ptr), uint64(len(buf)))
return s.c.error(r)
}

Expand Down
2 changes: 1 addition & 1 deletion vfs/vfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
out = err.Error()
}
if out != "" {
fn := mod.ExportedFunction("malloc")
fn := mod.ExportedFunction("sqlite3_malloc64")
stack := [...]uint64{uint64(len(out) + 1)}
if err := fn.CallWithStack(ctx, stack[:]); err != nil {
panic(err)
Expand Down

0 comments on commit 9d77322

Please sign in to comment.