More fuzzing.

This commit is contained in:
Nuno Cruces
2025-05-20 11:58:40 +01:00
parent f765882670
commit 341bd063e8
6 changed files with 424 additions and 173 deletions

View File

@@ -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 }}

Binary file not shown.

View File

@@ -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)
)

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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;