diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5651bc9..215b399 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -112,7 +112,7 @@ jobs: version: '10.1' flags: '-test.v -test.short' - name: openbsd - version: '7.6' + version: '7.7' flags: '-test.v -test.short' runs-on: ubuntu-latest needs: test @@ -128,7 +128,7 @@ jobs: run: .github/workflows/build-test.sh - name: Test - uses: cross-platform-actions/action@v0.27.0 + uses: cross-platform-actions/action@v0.28.0 with: operating_system: ${{ matrix.os.name }} architecture: ${{ matrix.os.arch }} diff --git a/sqlite3/libc/libc.wasm b/sqlite3/libc/libc.wasm index e996264..ba5147f 100755 Binary files a/sqlite3/libc/libc.wasm and b/sqlite3/libc/libc.wasm differ diff --git a/sqlite3/libc/libc.wat b/sqlite3/libc/libc.wat index 97d625a..7db9da4 100644 --- a/sqlite3/libc/libc.wat +++ b/sqlite3/libc/libc.wat @@ -3115,10 +3115,24 @@ (local.get $11) ) ) - (block $block6 + (local.set $1 + (select + (i32.const -1) + (i32.sub + (local.get $1) + (local.get $3) + ) + (i32.eq + (local.get $1) + (i32.const -1) + ) + ) + ) + (block $block5 (block $block1 - (br_if $block1 - (i32.lt_u + (if + (i32.gt_u + (local.get $0) (local.tee $14 (i32.sub (i32.sub @@ -3131,7 +3145,12 @@ (i32.const 16) ) ) - (local.get $0) + ) + (then + (local.set $5 + (local.get $1) + ) + (br $block1) ) ) (local.set $18 @@ -3185,22 +3204,21 @@ ) ) ) - (block $block3 - (br_if $block3 - (i32.ne + (local.set $5 + (i32.const -1) + ) + (br_if $block1 + (i32.and + (i32.eqz + (i8x16.all_true + (local.get $17) + ) + ) + (i32.eq (local.get $1) (i32.const -1) ) ) - (br_if $block3 - (i8x16.all_true - (local.get $17) - ) - ) - (local.set $1 - (i32.const -1) - ) - (br $block1) ) (br_if $block2 (i32.eqz @@ -3215,13 +3233,10 @@ (if (i32.lt_u (local.get $1) - (i32.add - (local.tee $5 - (i32.ctz - (local.get $7) - ) + (local.tee $5 + (i32.ctz + (local.get $7) ) - (local.get $3) ) ) (then @@ -3230,9 +3245,9 @@ ) ) ) - (br_if $block6 + (br_if $block5 (i32.eqz - (block $block5 (result i32) + (block $block4 (result i32) (local.set $9 (i32.add (local.tee $8 @@ -3250,7 +3265,7 @@ (local.set $12 (i32.const 0) ) - (block $block4 + (block $block3 (if (i32.ge_u (local.tee $10 @@ -3263,7 +3278,7 @@ (i32.const 1) ) (loop $label1 - (br_if $block4 + (br_if $block3 (v128.any_true (v128.xor (v128.load align=1 @@ -3307,19 +3322,19 @@ ) ) ) - (br $block5 + (br $block4 (i32.const 0) ) ) ) - (br_if $block4 + (br_if $block3 (i32.eqz (local.get $10) ) ) (loop $label2 (drop - (br_if $block5 + (br_if $block4 (i32.const 1) (i32.ne (i32.load8_u @@ -3370,7 +3385,7 @@ ) ) ) - (block $block7 + (block $block6 (if (i32.eq (local.get $1) @@ -3385,10 +3400,10 @@ (local.set $7 (i32.const 16) ) - (local.set $1 + (local.set $5 (i32.const -1) ) - (br $block7) + (br $block6) ) ) (return @@ -3396,13 +3411,9 @@ ) ) ) - (local.set $8 - (i32.const 0) - ) (br_if $block6 - (i32.lt_u - (local.get $1) - (local.tee $1 + (i32.le_u + (local.tee $5 (i32.sub (local.get $1) (local.tee $7 @@ -3431,14 +3442,15 @@ ) ) ) - ) - ) - (br_if $block6 - (i32.lt_u (local.get $1) - (local.get $3) ) ) + (return + (i32.const 0) + ) + ) + (local.set $1 + (local.get $5) ) (br_if $label4 (i32.le_u @@ -3453,90 +3465,85 @@ ) ) ) - (local.set $11 - (i32.sub - (local.get $1) - (local.get $3) - ) - ) - (local.set $4 + (local.set $1 (i32.const 0) ) - (local.set $1 + (local.set $4 (i32.ne - (local.get $1) + (local.get $5) (i32.const -1) ) ) - (loop $label6 + (loop $label5 (local.set $6 (i32.const 0) ) - (block $block8 - (loop $label5 - (local.set $8 - (i32.const 0) - ) - (br_if $block6 - (i32.eqz - (i32.or - (local.get $1) - (local.tee $5 - (i32.load8_u - (i32.add - (local.get $0) - (local.get $6) - ) + (loop $label6 + (local.set $8 + (i32.const 0) + ) + (br_if $block5 + (i32.eqz + (i32.or + (local.get $4) + (local.tee $11 + (i32.load8_u + (i32.add + (local.get $0) + (local.get $6) ) ) ) ) ) - (br_if $block8 - (i32.ne - (i32.load8_u - (i32.add - (local.get $2) - (local.get $6) - ) + ) + (if + (i32.ne + (local.get $11) + (i32.load8_u + (i32.add + (local.get $2) + (local.get $6) ) - (local.get $5) ) ) - (br_if $label5 - (i32.ne - (local.get $3) - (local.tee $6 - (i32.add - (local.get $6) - (i32.const 1) + (then + (local.set $0 + (i32.add + (local.get $0) + (i32.const 1) + ) + ) + (br_if $label5 + (i32.le_u + (local.tee $1 + (i32.add + (local.get $1) + (i32.const 1) + ) ) + (local.get $5) + ) + ) + (br $block5) + ) + ) + (br_if $label6 + (i32.ne + (local.get $3) + (local.tee $6 + (i32.add + (local.get $6) + (i32.const 1) ) ) ) ) - (return - (local.get $0) - ) - ) - (local.set $0 - (i32.add - (local.get $0) - (i32.const 1) - ) - ) - (br_if $label6 - (i32.le_u - (local.tee $4 - (i32.add - (local.get $4) - (i32.const 1) - ) - ) - (local.get $11) - ) ) ) + (local.set $8 + (local.get $0) + ) ) (local.get $8) ) diff --git a/sqlite3/libc/libc_test.go b/sqlite3/libc/libc_test.go index 4d951d5..de77d73 100644 --- a/sqlite3/libc/libc_test.go +++ b/sqlite3/libc/libc_test.go @@ -1,11 +1,13 @@ package libc import ( + "bytes" "context" _ "embed" "os" "strings" "testing" + "unicode/utf8" "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" @@ -453,8 +455,8 @@ func Test_strrchr(t *testing.T) { } } -func Test_memcmp(t *testing.T) { - const s1 string = "" + +const ( + compareTest1 = "" + "\x94\x63\x8f\x01\x74\x63\x8f\x01\x54\x63\x8f\x01\x34\x63\x8f\x01" + "\xb4\xf2\x93\x01\x94\xf2\x93\x01\x54\xf1\x93\x01\x34\xf1\x93\x01" + "\x14\xf1\x93\x01\x14\xf2\x93\x01\x34\xf2\x93\x01\x54\xf2\x93\x01" + @@ -463,7 +465,7 @@ func Test_memcmp(t *testing.T) { "\x14\xf4\x93\x01\xf4\xf3\x93\x01\xd4\xf3\x93\x01\xb4\xf3\x93\x01" + "\x94\xf3\x93\x01\x74\x80\x93\x01\x54\xf3\x93\x01\x34\xf3\x93\x01" + "\x7f\xf3\x93\x01\x00\x01" - const s2 string = "" + + compareTest2 = "" + "\x94\x63\x8f\x01\x74\x63\x8f\x01\x54\x63\x8f\x01\x34\x63\x8f\x01" + "\xb4\xf2\x93\x01\x94\xf2\x93\x01\x54\xf1\x93\x01\x34\xf1\x93\x01" + "\x14\xf1\x93\x01\x14\xf2\x93\x01\x34\xf2\x93\x01\x54\xf2\x93\x01" + @@ -472,6 +474,11 @@ func Test_memcmp(t *testing.T) { "\xbc\x40\x96\x01\xf4\xf3\x93\x01\xd4\xf3\x93\x01\xb4\xf3\x93\x01" + "\x94\xf3\x93\x01\x74\x7f\x93\x01\x54\xf3\x93\x01\x34\xf3\x93\x01" + "\x80\xf3\x93\x01\x00\x02" +) + +func Test_memcmp(t *testing.T) { + const s1 = compareTest1 + const s2 = compareTest2 ptr2 := len(memory) - len(s2) @@ -492,24 +499,8 @@ func Test_memcmp(t *testing.T) { } func Test_strcmp(t *testing.T) { - const s1 string = "" + - "\x94\x63\x8f\x01\x74\x63\x8f\x01\x54\x63\x8f\x01\x34\x63\x8f\x01" + - "\xb4\xf2\x93\x01\x94\xf2\x93\x01\x54\xf1\x93\x01\x34\xf1\x93\x01" + - "\x14\xf1\x93\x01\x14\xf2\x93\x01\x34\xf2\x93\x01\x54\xf2\x93\x01" + - "\x74\xf2\x93\x01\x74\xf1\x93\x01\xd4\xf2\x93\x01\x94\xf1\x93\x01" + - "\xb4\xf1\x93\x01\xd4\xf1\x93\x01\xf4\xf1\x93\x01\xf4\xf2\x93\x01" + - "\x14\xf4\x93\x01\xf4\xf3\x93\x01\xd4\xf3\x93\x01\xb4\xf3\x93\x01" + - "\x94\xf3\x93\x01\x74\x80\x93\x01\x54\xf3\x93\x01\x34\xf3\x93\x01" + - "\x7f\xf3\x93\x01\x00\x01" - const s2 string = "" + - "\x94\x63\x8f\x01\x74\x63\x8f\x01\x54\x63\x8f\x01\x34\x63\x8f\x01" + - "\xb4\xf2\x93\x01\x94\xf2\x93\x01\x54\xf1\x93\x01\x34\xf1\x93\x01" + - "\x14\xf1\x93\x01\x14\xf2\x93\x01\x34\xf2\x93\x01\x54\xf2\x93\x01" + - "\x74\xf2\x93\x01\x74\xf1\x93\x01\xd4\xf2\x93\x01\x94\xf1\x93\x01" + - "\xb4\xf1\x93\x01\xd4\xf1\x93\x01\xf4\xf1\x93\x01\xf4\xf2\x93\x01" + - "\xbc\x40\x96\x01\xf4\xf3\x93\x01\xd4\xf3\x93\x01\xb4\xf3\x93\x01" + - "\x94\xf3\x93\x01\x74\x7f\x93\x01\x54\xf3\x93\x01\x34\xf3\x93\x01" + - "\x80\xf3\x93\x01\x00\x02" + const s1 = compareTest1 + const s2 = compareTest2 ptr2 := len(memory) - len(s2) - 1 @@ -528,24 +519,8 @@ func Test_strcmp(t *testing.T) { } func Test_strncmp(t *testing.T) { - const s1 string = "" + - "\x94\x63\x8f\x01\x74\x63\x8f\x01\x54\x63\x8f\x01\x34\x63\x8f\x01" + - "\xb4\xf2\x93\x01\x94\xf2\x93\x01\x54\xf1\x93\x01\x34\xf1\x93\x01" + - "\x14\xf1\x93\x01\x14\xf2\x93\x01\x34\xf2\x93\x01\x54\xf2\x93\x01" + - "\x74\xf2\x93\x01\x74\xf1\x93\x01\xd4\xf2\x93\x01\x94\xf1\x93\x01" + - "\xb4\xf1\x93\x01\xd4\xf1\x93\x01\xf4\xf1\x93\x01\xf4\xf2\x93\x01" + - "\x14\xf4\x93\x01\xf4\xf3\x93\x01\xd4\xf3\x93\x01\xb4\xf3\x93\x01" + - "\x94\xf3\x93\x01\x74\x80\x93\x01\x54\xf3\x93\x01\x34\xf3\x93\x01" + - "\x7f\xf3\x93\x01\x00\x01" - const s2 string = "" + - "\x94\x63\x8f\x01\x74\x63\x8f\x01\x54\x63\x8f\x01\x34\x63\x8f\x01" + - "\xb4\xf2\x93\x01\x94\xf2\x93\x01\x54\xf1\x93\x01\x34\xf1\x93\x01" + - "\x14\xf1\x93\x01\x14\xf2\x93\x01\x34\xf2\x93\x01\x54\xf2\x93\x01" + - "\x74\xf2\x93\x01\x74\xf1\x93\x01\xd4\xf2\x93\x01\x94\xf1\x93\x01" + - "\xb4\xf1\x93\x01\xd4\xf1\x93\x01\xf4\xf1\x93\x01\xf4\xf2\x93\x01" + - "\xbc\x40\x96\x01\xf4\xf3\x93\x01\xd4\xf3\x93\x01\xb4\xf3\x93\x01" + - "\x94\xf3\x93\x01\x74\x7f\x93\x01\x54\xf3\x93\x01\x34\xf3\x93\x01" + - "\x80\xf3\x93\x01\x00\x02" + const s1 = compareTest1 + const s2 = compareTest2 ptr2 := len(memory) - len(s2) - 1 @@ -903,6 +878,215 @@ func Test_strcasestr(t *testing.T) { } } +func Fuzz_memcmp(f *testing.F) { + const s1 = compareTest1 + const s2 = compareTest2 + + for i := range len(compareTest1) + 1 { + f.Add(s1[i:], s2[i:]) + } + + f.Fuzz(func(t *testing.T, s1, s2 string) { + if len(s1) > 128 || len(s1) != len(s2) { + t.SkipNow() + } + copy(memory[ptr1:], s1) + copy(memory[ptr2:], s2) + + got := call(memcmp, uint64(ptr1), uint64(ptr2), uint64(len(s1))) + want := strings.Compare(s1, s2) + + if sign(int32(got)) != want { + t.Errorf("memcmp(%q, %q) = %d, want %d", + s1, s2, uint32(got), uint32(want)) + } + }) +} + +func Fuzz_strcmp(f *testing.F) { + const s1 = compareTest1 + const s2 = compareTest2 + + for i := range len(compareTest1) + 1 { + f.Add(term(s1[i:]), term(s2[i:])) + } + + f.Fuzz(func(t *testing.T, s1, s2 string) { + if len(s1) > 128 || len(s2) > 128 { + t.SkipNow() + } + copy(memory[ptr1:], s1) + copy(memory[ptr2:], s2) + memory[ptr1+len(s1)] = 0 + memory[ptr2+len(s2)] = 0 + + got := call(strcmp, uint64(ptr1), uint64(ptr2)) + want := strings.Compare(term(s1), term(s2)) + + if sign(int32(got)) != want { + t.Errorf("strcmp(%q, %q) = %d, want %d", + s1, s2, uint32(got), uint32(want)) + } + }) +} + +func Fuzz_strncmp(f *testing.F) { + const s1 = compareTest1 + const s2 = compareTest2 + + for i := range len(compareTest1) + 1 { + f.Add(term(s1[i:]), term(s2[i:]), uint8(len(s1))) + } + + f.Fuzz(func(t *testing.T, s1, s2 string, n uint8) { + if len(s1) > 128 || len(s2) > 128 { + t.SkipNow() + } + copy(memory[ptr1:], s1) + copy(memory[ptr2:], s2) + memory[ptr1+len(s1)] = 0 + memory[ptr2+len(s2)] = 0 + + got := call(strncmp, uint64(ptr1), uint64(ptr2), uint64(n)) + want := bytes.Compare( + term(memory[ptr1:][:n]), + term(memory[ptr2:][:n])) + + if sign(int32(got)) != want { + t.Errorf("strncmp(%q, %q, %d) = %d, want %d", + s1, s2, n, uint32(got), uint32(want)) + } + }) +} + +func Fuzz_strcasecmp(f *testing.F) { + const s1 = compareTest1 + const s2 = compareTest2 + + for i := range len(compareTest1) + 1 { + f.Add(term(s1[i:]), term(s2[i:])) + } + + f.Fuzz(func(t *testing.T, s1, s2 string) { + if len(s1) > 128 || len(s2) > 128 { + t.SkipNow() + } + copy(memory[ptr1:], s1) + copy(memory[ptr2:], s2) + memory[ptr1+len(s1)] = 0 + memory[ptr2+len(s2)] = 0 + + got := call(strcasecmp, uint64(ptr1), uint64(ptr2)) + want := bytes.Compare( + lower(term(memory[ptr1:])), + lower(term(memory[ptr2:]))) + + if sign(int32(got)) != want { + t.Errorf("strcasecmp(%q, %q) = %d, want %d", + s1, s2, uint32(got), uint32(want)) + } + }) +} + +func Fuzz_strncasecmp(f *testing.F) { + const s1 = compareTest1 + const s2 = compareTest2 + + for i := range len(compareTest1) + 1 { + f.Add(term(s1[i:]), term(s2[i:]), uint8(len(s1))) + } + + f.Fuzz(func(t *testing.T, s1, s2 string, n uint8) { + if len(s1) > 128 || len(s2) > 128 { + t.SkipNow() + } + copy(memory[ptr1:], s1) + copy(memory[ptr2:], s2) + memory[ptr1+len(s1)] = 0 + memory[ptr2+len(s2)] = 0 + + got := call(strncasecmp, uint64(ptr1), uint64(ptr2), uint64(n)) + want := bytes.Compare( + lower(term(memory[ptr1:][:n])), + lower(term(memory[ptr2:][:n]))) + + if sign(int32(got)) != want { + t.Errorf("strncasecmp(%q, %q, %d) = %d, want %d", + s1, s2, n, uint32(got), uint32(want)) + } + }) +} + +func Fuzz_strspn(f *testing.F) { + for _, t := range searchTests { + f.Add(t.haystk, t.needle) + } + + f.Fuzz(func(t *testing.T, text, chars string) { + if len(text) > 128 || len(chars) > 128 { + t.SkipNow() + } + copy(memory[ptr1:], text) + copy(memory[ptr2:], chars) + memory[ptr1+len(text)] = 0 + memory[ptr2+len(chars)] = 0 + + got := call(strspn, uint64(ptr1), uint64(ptr2)) + + text = term(text) + chars = term(chars) + want := strings.IndexFunc(text, func(r rune) bool { + if uint32(r) >= utf8.RuneSelf { + t.Skip() + } + return strings.IndexByte(chars, byte(r)) < 0 + }) + if want < 0 { + want = len(text) + } + + if uint32(got) != uint32(want) { + t.Errorf("strspn(%q, %q) = %d, want %d", + text, chars, uint32(got), uint32(want)) + } + }) +} + +func Fuzz_strcspn(f *testing.F) { + for _, t := range searchTests { + f.Add(t.haystk, t.needle) + } + + f.Fuzz(func(t *testing.T, text, chars string) { + if len(text) > 128 || len(chars) > 128 { + t.SkipNow() + } + copy(memory[ptr1:], text) + copy(memory[ptr2:], chars) + memory[ptr1+len(text)] = 0 + memory[ptr2+len(chars)] = 0 + + got := call(strcspn, uint64(ptr1), uint64(ptr2)) + + text = term(text) + chars = term(chars) + want := strings.IndexFunc(text, func(r rune) bool { + if uint32(r) >= utf8.RuneSelf { + t.Skip() + } + return strings.IndexByte(chars, byte(r)) >= 0 + }) + if want < 0 { + want = len(text) + } + + if uint32(got) != uint32(want) { + t.Errorf("strcspn(%q, %q) = %d, want %d", + text, chars, uint32(got), uint32(want)) + } + }) +} + func Fuzz_memmem(f *testing.F) { tt := append(searchTests, searchTest{"abcABCabc", "A", 3}, @@ -910,19 +1094,21 @@ func Fuzz_memmem(f *testing.F) { searchTest{"0000000000000000\x000123456789012345678901234567890", "0123456789012345", 17}, ) - for i := range tt { - f.Add(tt[i].haystk, tt[i].needle) + for _, t := range tt { + f.Add(t.haystk, t.needle) } f.Fuzz(func(t *testing.T, haystk, needle string) { - if len(haystk) > 128 || len(needle) > 32 { + if len(haystk) > 128 || len(needle) > 128 { t.SkipNow() } - clear(memory[ptr1 : ptr1+256]) - clear(memory[ptr2 : ptr2+256]) copy(memory[ptr1:], haystk) copy(memory[ptr2:], needle) + got := call(memmem, + uint64(ptr1), uint64(len(haystk)), + uint64(ptr2), uint64(len(needle))) + want := strings.Index(haystk, needle) if want >= 0 { want = ptr1 + want @@ -930,9 +1116,6 @@ func Fuzz_memmem(f *testing.F) { want = 0 } - got := call(memmem, - uint64(ptr1), uint64(len(haystk)), - uint64(ptr2), uint64(len(needle))) if uint32(got) != uint32(want) { t.Errorf("memmem(%q, %q) = %d, want %d", haystk, needle, uint32(got), uint32(want)) @@ -947,18 +1130,20 @@ func Fuzz_strstr(f *testing.F) { searchTest{"0000000000000000\x000123456789012345678901234567890", "0123456789012345", -1}, ) - for i := range tt { - f.Add(tt[i].haystk, tt[i].needle) + for _, t := range tt { + f.Add(t.haystk, t.needle) } f.Fuzz(func(t *testing.T, haystk, needle string) { - if len(haystk) > 128 || len(needle) > 32 { + if len(haystk) > 128 || len(needle) > 128 { t.SkipNow() } - clear(memory[ptr1 : ptr1+256]) - clear(memory[ptr2 : ptr2+256]) copy(memory[ptr1:], haystk) copy(memory[ptr2:], needle) + memory[ptr1+len(haystk)] = 0 + memory[ptr2+len(needle)] = 0 + + got := call(strstr, uint64(ptr1), uint64(ptr2)) want := strings.Index(term(haystk), term(needle)) if want >= 0 { @@ -967,7 +1152,6 @@ func Fuzz_strstr(f *testing.F) { want = 0 } - got := call(strstr, uint64(ptr1), uint64(ptr2)) if uint32(got) != uint32(want) { t.Errorf("strstr(%q, %q) = %d, want %d", haystk, needle, uint32(got), uint32(want)) @@ -975,10 +1159,52 @@ func Fuzz_strstr(f *testing.F) { }) } -func fill(s []byte, v byte) { - for i := range s { - s[i] = v +func Fuzz_strcasestr(f *testing.F) { + tt := append(searchTests, + searchTest{"A", "a", 0}, + searchTest{"a", "A", 0}, + searchTest{"Z", "z", 0}, + searchTest{"z", "Z", 0}, + searchTest{"@", "`", -1}, + searchTest{"`", "@", -1}, + searchTest{"[", "{", -1}, + searchTest{"{", "[", -1}, + searchTest{"abcABCabc", "A", 0}, + searchTest{"fofofofofofofoffofoobarfoo", "FoFFoF", 12}, + searchTest{"fofofofofofofOffOfoobarfoo", "FoFFoF", 12}, + searchTest{"fofofofofofo\x00foffofoobar", "foffof", -1}, + searchTest{"0000000000000000\x000123456789012345678901234567890", "0123456789012345", -1}, + ) + + for _, t := range tt { + f.Add(t.haystk, t.needle) } + + f.Fuzz(func(t *testing.T, haystk, needle string) { + if len(haystk) > 128 || len(needle) > 128 { + t.SkipNow() + } + copy(memory[ptr1:], haystk) + copy(memory[ptr2:], needle) + memory[ptr1+len(haystk)] = 0 + memory[ptr2+len(needle)] = 0 + + got := call(strcasestr, uint64(ptr1), uint64(ptr2)) + + want := bytes.Index( + lower(term(memory[ptr1:])), + lower(term(memory[ptr2:]))) + if want >= 0 { + want = ptr1 + want + } else { + want = 0 + } + + if uint32(got) != uint32(want) { + t.Errorf("strcasestr(%q, %q) = %d, want %d", + haystk, needle, uint32(got), uint32(want)) + } + }) } func sign(x int32) int { @@ -992,9 +1218,26 @@ func sign(x int32) int { } } -func term(s string) string { - if i := strings.IndexByte(s, 0); i >= 0 { - return s[:i] +func fill(s []byte, v byte) { + for i := range s { + s[i] = v + } +} + +func lower(s []byte) []byte { + for i, c := range s { + if 'A' <= c && c <= 'Z' { + s[i] = c - 'A' + 'a' + } + } + return s +} + +func term[T interface{ []byte | string }](s T) T { + for i, c := range []byte(s) { + if c == 0 { + return s[:i] + } } return s } diff --git a/sqlite3/libc/string.h b/sqlite3/libc/string.h index 98ce011..fed1c8f 100644 --- a/sqlite3/libc/string.h +++ b/sqlite3/libc/string.h @@ -463,8 +463,7 @@ size_t strcspn(const char *s, const char *c) { // as proposed by Horspool, Sunday and Raita. // // We augment the SIMD algorithm with Quick Search's -// bad-character shift. This does NOT depend on the order -// in which the window matched. +// bad-character shift. // // https://www-igm.univ-mlv.fr/~lecroq/string/node14.html // https://www-igm.univ-mlv.fr/~lecroq/string/node18.html @@ -483,6 +482,10 @@ static const char *__memmem(const char *haystk, size_t sh, while (i > 0 && needle[0] == needle[i]) i--; if (i == 0) i = sn - 1; + // Subtracting ensures sub_overflow overflows + // when we reach the end of the haystack. + if (sh != SIZE_MAX) sh -= sn; + const v128_t fst = wasm_i8x16_splat(needle[0]); const v128_t lst = wasm_i8x16_splat(needle[i]); @@ -505,7 +508,8 @@ static const char *__memmem(const char *haystk, size_t sh, for (uint32_t mask = wasm_i8x16_bitmask(cmp); mask; mask &= mask - 1) { size_t ctz = __builtin_ctz(mask); // The match may be after the end of the haystack. - if (ctz + sn > sh) return NULL; + if (ctz > sh) return NULL; + // We know the first character matches. if (!bcmp(haystk + ctz + 1, needle + 1, sn - 1)) { return haystk + ctz; } @@ -522,14 +526,12 @@ static const char *__memmem(const char *haystk, size_t sh, if (bmbc) skip += bmbc[(unsigned char)haystk[sn - 1 + sizeof(v128_t)]]; // Have we reached the end of the haystack? if (__builtin_sub_overflow(sh, skip, &sh)) return NULL; - // Is the needle longer than the haystack? - if (sn > sh) return NULL; } haystk += skip; } // Scalar algorithm. - for (size_t j = 0; j <= sh - sn; j++) { + for (size_t j = 0; j <= sh; j++) { for (size_t i = 0;; i++) { if (sn == i) return haystk; if (sh == SIZE_MAX && !haystk[i]) return NULL; @@ -581,8 +583,7 @@ void *memmem(const void *vh, size_t sh, const void *vn, size_t sn) { for (; i < sn; i++) { // One less than the usual offset because // we advance at least one vector at a time. - size_t t = sn - i - 1; - bmbc[(unsigned char)needle[i]] = t; + bmbc[(unsigned char)needle[i]] = sn - i - 1; } return (void *)__memmem(haystk, sh, needle, sn, bmbc); diff --git a/sqlite3/libc/strings.h b/sqlite3/libc/strings.h index 61f92b5..4cd92c9 100644 --- a/sqlite3/libc/strings.h +++ b/sqlite3/libc/strings.h @@ -35,7 +35,7 @@ int bcmp(const void *v1, const void *v2, size_t n) { return 0; } - // memcmpeq is allowed to read up to n bytes from each object. + // bcmp is allowed to read up to n bytes from each object. // Unaligned loads handle the case where the objects // have mismatching alignments. const v128_t *w1 = (v128_t *)v1;