Differential fuzzing.

This commit is contained in:
Nuno Cruces
2025-05-15 14:55:34 +01:00
parent fccc6c10a7
commit 54877a53cd
4 changed files with 483 additions and 564 deletions

Binary file not shown.

View File

@@ -2374,7 +2374,7 @@
)
(then
(return
(call $__memmem_raita
(call $__memmem
(local.get $4)
(local.get $8)
(local.get $2)
@@ -2584,7 +2584,7 @@
)
)
(local.set $6
(call $__memmem_raita
(call $__memmem
(local.get $4)
(local.get $8)
(local.get $2)
@@ -2595,7 +2595,7 @@
)
(local.get $6)
)
(func $__memmem_raita (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32)
(func $__memmem (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32)
(local $5 i32)
(local $6 i32)
(local $7 i32)
@@ -2617,8 +2617,8 @@
(local.get $2)
)
)
(local.set $6
(local.tee $8
(local.set $5
(local.tee $9
(i32.sub
(local.get $3)
(i32.const 1)
@@ -2634,16 +2634,16 @@
(i32.load8_u
(i32.add
(local.get $2)
(local.get $6)
(local.get $5)
)
)
)
)
)
(br_if $label
(local.tee $6
(local.tee $5
(i32.sub
(local.get $6)
(local.get $5)
(i32.const 1)
)
)
@@ -2653,12 +2653,12 @@
(i32.load8_u
(i32.add
(local.get $2)
(local.get $8)
(local.get $9)
)
)
)
(local.set $6
(local.get $8)
(local.set $5
(local.get $9)
)
)
(block $block5
@@ -2672,7 +2672,7 @@
(memory.size)
(i32.const 16)
)
(local.get $6)
(local.get $5)
)
(i32.const 16)
)
@@ -2720,7 +2720,7 @@
(v128.load align=1
(i32.add
(local.get $0)
(local.get $6)
(local.get $5)
)
)
)
@@ -2764,14 +2764,30 @@
)
)
(loop $label3
(local.set $9
(if
(i32.lt_u
(local.get $1)
(i32.add
(local.tee $6
(i32.ctz
(local.get $11)
)
)
(local.get $3)
)
)
(then
(return
(i32.const 0)
)
)
)
(local.set $8
(i32.add
(local.tee $12
(i32.add
(local.get $0)
(i32.ctz
(local.get $11)
)
(local.get $6)
)
)
(i32.const 1)
@@ -2786,8 +2802,8 @@
(local.set $7
(local.get $10)
)
(local.set $5
(local.get $8)
(local.set $6
(local.get $9)
)
(loop $label1
(br_if $block4
@@ -2797,7 +2813,7 @@
(local.get $7)
)
(v128.load align=1
(local.get $9)
(local.get $8)
)
)
)
@@ -2809,7 +2825,7 @@
(i32.add
(i32.and
(i32.sub
(local.get $5)
(local.get $6)
(i32.const 1)
)
(i32.const 15)
@@ -2819,16 +2835,16 @@
)
)
)
(local.set $9
(local.set $8
(i32.add
(local.get $9)
(local.get $8)
(local.get $13)
)
)
(br_if $label1
(local.tee $5
(local.tee $6
(i32.sub
(local.get $5)
(local.get $6)
(local.get $13)
)
)
@@ -2837,8 +2853,8 @@
(br $block5)
)
)
(local.set $5
(local.get $8)
(local.set $6
(local.get $9)
)
(local.set $7
(local.get $10)
@@ -2847,7 +2863,7 @@
(br_if $block4
(i32.ne
(i32.load8_u
(local.get $9)
(local.get $8)
)
(i32.load8_u
(local.get $7)
@@ -2860,16 +2876,16 @@
(i32.const 1)
)
)
(local.set $9
(local.set $8
(i32.add
(local.get $9)
(local.get $8)
(i32.const 1)
)
)
(br_if $label2
(local.tee $5
(local.tee $6
(i32.sub
(local.get $5)
(local.get $6)
(i32.const 1)
)
)
@@ -2890,78 +2906,82 @@
)
)
)
(local.set $5
(if (result i32)
(local.get $4)
(then
(i32.add
(i32.load8_u
(i32.add
(local.get $4)
(i32.load8_u
(i32.add
(local.get $0)
(local.get $15)
)
)
)
)
(i32.const 16)
)
)
(else
(i32.const 16)
)
)
)
(block $block6
(if
(i32.ne
(i32.eq
(local.get $1)
(i32.const -1)
)
(then
(local.set $12
(if
(i8x16.all_true
(local.get $17)
)
(then
(local.set $8
(i32.const 16)
)
(local.set $1
(i32.const -1)
)
(br $block6)
)
)
(return
(i32.const 0)
)
(br_if $block5
(i32.lt_u
)
)
(local.set $12
(i32.const 0)
)
(br_if $block5
(i32.lt_u
(local.get $1)
(local.tee $1
(i32.sub
(local.get $1)
(local.tee $1
(i32.sub
(local.get $1)
(local.get $5)
(local.tee $8
(if (result i32)
(local.get $4)
(then
(i32.add
(i32.load8_u
(i32.add
(local.get $4)
(i32.load8_u
(i32.add
(local.get $0)
(local.get $15)
)
)
)
)
(i32.const 16)
)
)
(else
(i32.const 16)
)
)
)
)
)
(br_if $block5
(i32.lt_u
(local.get $1)
(local.get $3)
)
)
(br $block6)
)
)
(local.set $1
(i32.const -1)
)
(br_if $block6
(i8x16.all_true
(local.get $17)
(br_if $block5
(i32.lt_u
(local.get $1)
(local.get $3)
)
)
(return
(i32.const 0)
)
)
(br_if $label4
(i32.le_u
(local.tee $0
(i32.add
(local.get $0)
(local.get $5)
(local.get $8)
)
)
(local.get $14)
@@ -2969,13 +2989,13 @@
)
)
)
(local.set $8
(local.set $9
(i32.sub
(local.get $1)
(local.get $3)
)
)
(local.set $5
(local.set $6
(i32.const 0)
)
(local.set $4
@@ -2984,93 +3004,88 @@
(i32.const -1)
)
)
(loop $label5
(local.set $6
(loop $label6
(local.set $5
(i32.const 0)
)
(loop $label6
(local.set $12
(i32.const 0)
)
(br_if $block5
(i32.eqz
(i32.or
(local.get $4)
(local.tee $1
(i32.load8_u
(i32.add
(local.get $0)
(local.get $6)
(block $block7
(loop $label5
(local.set $12
(i32.const 0)
)
(br_if $block5
(i32.eqz
(i32.or
(local.get $4)
(local.tee $1
(i32.load8_u
(i32.add
(local.get $0)
(local.get $5)
)
)
)
)
)
)
)
(if
(i32.ne
(local.get $1)
(i32.load8_u
(i32.add
(local.get $2)
(local.get $6)
)
)
)
(then
(local.set $0
(i32.add
(local.get $0)
(i32.const 1)
)
)
(br_if $label5
(i32.le_u
(local.tee $5
(i32.add
(local.get $5)
(i32.const 1)
)
(br_if $block7
(i32.ne
(i32.load8_u
(i32.add
(local.get $2)
(local.get $5)
)
)
(local.get $1)
)
)
(br_if $label5
(i32.ne
(local.get $3)
(local.tee $5
(i32.add
(local.get $5)
(i32.const 1)
)
(local.get $8)
)
)
(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 $6
(i32.add
(local.get $6)
(i32.const 1)
)
)
(local.get $9)
)
)
)
(local.set $12
(local.get $0)
)
)
(local.get $12)
)
(func $strstr (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
(local $3 i32)
(local $2 v128)
(local $3 v128)
(local $4 i32)
(local $5 i32)
(local $6 i32)
(local $7 i32)
(local $8 i32)
(local $9 v128)
(local $10 v128)
(block $block
(br_if $block
(i32.eqz
(local.tee $4
(local.tee $5
(i32.load8_u
(local.get $1)
)
@@ -3080,12 +3095,12 @@
(block $block1
(if
(v128.any_true
(local.tee $9
(local.tee $2
(v128.or
(i8x16.eq
(local.tee $9
(local.tee $2
(v128.load
(local.tee $2
(local.tee $4
(i32.and
(local.get $0)
(i32.const -16)
@@ -3096,10 +3111,10 @@
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(i8x16.eq
(local.get $9)
(local.tee $10
(local.get $2)
(local.tee $3
(i8x16.splat
(local.get $4)
(local.get $5)
)
)
)
@@ -3108,10 +3123,10 @@
)
(then
(br_if $block1
(local.tee $3
(local.tee $6
(i32.and
(i8x16.bitmask
(local.get $9)
(local.get $2)
)
(i32.shl
(i32.const -1)
@@ -3126,29 +3141,29 @@
)
)
(loop $label
(local.set $9
(local.set $2
(v128.load offset=16
(local.get $2)
(local.get $4)
)
)
(local.set $2
(local.set $4
(i32.add
(local.get $2)
(local.get $4)
(i32.const 16)
)
)
(br_if $label
(i32.eqz
(v128.any_true
(local.tee $9
(local.tee $2
(v128.or
(i8x16.eq
(local.get $9)
(local.get $2)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(i8x16.eq
(local.get $9)
(local.get $10)
(local.get $2)
(local.get $3)
)
)
)
@@ -3156,9 +3171,9 @@
)
)
)
(local.set $3
(local.set $6
(i8x16.bitmask
(local.get $9)
(local.get $2)
)
)
)
@@ -3167,13 +3182,13 @@
)
(br_if $block
(i32.ne
(local.get $4)
(local.get $5)
(i32.load8_u
(local.tee $7
(local.tee $4
(i32.add
(local.get $2)
(local.get $4)
(i32.ctz
(local.get $3)
(local.get $6)
)
)
)
@@ -3188,240 +3203,19 @@
)
(then
(return
(local.get $7)
)
)
)
(if
(i32.le_u
(i32.add
(local.tee $5
(call $strlen
(local.get $1)
)
)
(i32.const 16)
)
(i32.const 31)
)
(then
(return
(call $__memmem_raita
(local.get $7)
(i32.const -1)
(local.get $1)
(local.get $5)
(i32.const 0)
)
)
)
)
(memory.fill
(i32.const 4112)
(select
(i32.const -1)
(local.tee $6
(i32.sub
(local.get $5)
(i32.const 1)
)
)
(local.tee $0
(i32.gt_s
(local.get $6)
(i32.const 254)
)
)
)
(i32.const 256)
)
(block $block2
(br_if $block2
(i32.ge_u
(local.tee $2
(select
(i32.sub
(local.get $5)
(i32.const 256)
)
(i32.const 0)
(local.get $0)
)
)
(local.get $6)
)
)
(local.set $3
(i32.sub
(i32.sub
(local.get $5)
(local.get $2)
)
(i32.const 2)
)
)
(if
(local.tee $4
(i32.and
(i32.add
(local.get $5)
(i32.xor
(local.get $2)
(i32.const -1)
)
)
(i32.const 3)
)
)
(then
(local.set $0
(local.get $3)
)
(loop $label1
(i32.store8
(i32.add
(i32.load8_u
(i32.add
(local.get $1)
(local.get $2)
)
)
(i32.const 4112)
)
(local.get $0)
)
(local.set $0
(i32.sub
(local.get $0)
(i32.const 1)
)
)
(local.set $2
(i32.add
(local.get $2)
(i32.const 1)
)
)
(br_if $label1
(local.tee $4
(i32.sub
(local.get $4)
(i32.const 1)
)
)
)
)
)
)
(br_if $block2
(i32.lt_u
(local.get $3)
(i32.const 3)
)
)
(local.set $0
(i32.sub
(local.get $5)
(local.get $2)
)
)
(local.set $3
(local.get $1)
)
(loop $label2
(i32.store8
(i32.add
(i32.load8_u
(local.tee $8
(i32.add
(local.get $2)
(local.get $3)
)
)
)
(i32.const 4112)
)
(i32.sub
(local.get $0)
(i32.const 2)
)
)
(i32.store8
(i32.add
(i32.load8_u
(i32.add
(local.get $8)
(i32.const 1)
)
)
(i32.const 4112)
)
(i32.sub
(local.get $0)
(i32.const 3)
)
)
(i32.store8
(i32.add
(i32.load8_u
(i32.add
(local.get $8)
(i32.const 2)
)
)
(i32.const 4112)
)
(local.tee $4
(i32.sub
(local.get $0)
(i32.const 4)
)
)
)
(i32.store8
(i32.add
(i32.load8_u
(i32.add
(local.get $8)
(i32.const 3)
)
)
(i32.const 4112)
)
(i32.sub
(local.get $0)
(i32.const 5)
)
)
(local.set $3
(i32.add
(local.get $3)
(i32.const 4)
)
)
(local.set $0
(local.get $4)
)
(br_if $label2
(i32.ne
(local.get $2)
(local.tee $6
(i32.sub
(local.get $6)
(i32.const 4)
)
)
)
)
)
)
(local.set $0
(call $__memmem_raita
(local.get $7)
(call $__memmem
(local.get $4)
(i32.const -1)
(local.get $1)
(local.get $5)
(i32.const 4112)
(call $strlen
(local.get $1)
)
(i32.const 0)
)
)
)

View File

@@ -28,6 +28,7 @@ var (
memcpy api.Function
memchr api.Function
memcmp api.Function
memmem api.Function
strlen api.Function
strchr api.Function
strcmp api.Function
@@ -64,6 +65,7 @@ func TestMain(m *testing.M) {
memcpy = mod.ExportedFunction("memcpy")
memchr = mod.ExportedFunction("memchr")
memcmp = mod.ExportedFunction("memcmp")
memmem = mod.ExportedFunction("memmem")
strlen = mod.ExportedFunction("strlen")
strchr = mod.ExportedFunction("strchr")
strcmp = mod.ExportedFunction("strcmp")
@@ -246,9 +248,11 @@ func Benchmark_strcspn(b *testing.B) {
var source string
func Benchmark_strstr(b *testing.B) {
needle := "memcpy(dest, src, slen)"
clear(memory)
copy(memory[ptr1:], source)
copy(memory[ptr2:], "memcpy(dest, src, slen)")
copy(memory[ptr2:], needle)
b.SetBytes(int64(len(source)))
b.ResetTimer()
@@ -257,6 +261,20 @@ func Benchmark_strstr(b *testing.B) {
}
}
func Benchmark_memmem(b *testing.B) {
needle := "memcpy(dest, src, slen)"
clear(memory)
copy(memory[ptr1:], source)
copy(memory[ptr2:], needle)
b.SetBytes(int64(len(source)))
b.ResetTimer()
for range b.N {
call(memmem, ptr1, uint64(len(source)), ptr2, uint64(len(needle)))
}
}
func Test_memcmp(t *testing.T) {
const s1 string = "" +
"\x94\x63\x8f\x01\x74\x63\x8f\x01\x54\x63\x8f\x01\x34\x63\x8f\x01" +
@@ -639,143 +657,153 @@ func Test_strcspn(t *testing.T) {
}
}
type searchTest struct {
haystk string
needle string
out int
}
var searchTests = []searchTest{
{"", "", 0},
{"", "a", -1},
{"", "foo", -1},
{"fo", "foo", -1},
{"foo", "baz", -1},
{"foo", "foo", 0},
{"oofofoofooo", "f", 2},
{"oofofoofooo", "foo", 4},
{"barfoobarfoo", "foo", 3},
{"foo", "", 0},
{"foo", "o", 1},
{"abcABCabc", "A", 3},
{"jrzm6jjhorimglljrea4w3rlgosts0w2gia17hno2td4qd1jz", "jz", 47},
{"ekkuk5oft4eq0ocpacknhwouic1uua46unx12l37nioq9wbpnocqks6", "ks6", 52},
{"999f2xmimunbuyew5vrkla9cpwhmxan8o98ec", "98ec", 33},
{"9lpt9r98i04k8bz6c6dsrthb96bhi", "96bhi", 24},
{"55u558eqfaod2r2gu42xxsu631xf0zobs5840vl", "5840vl", 33},
{"", "a", -1},
{"x", "a", -1},
{"x", "x", 0},
{"abc", "a", 0},
{"abc", "b", 1},
{"abc", "c", 2},
{"abc", "x", -1},
{"", "ab", -1},
{"bc", "ab", -1},
{"ab", "ab", 0},
{"xab", "ab", 1},
{"xab"[:2], "ab", -1},
{"", "abc", -1},
{"xbc", "abc", -1},
{"abc", "abc", 0},
{"xabc", "abc", 1},
{"xabc"[:3], "abc", -1},
{"xabxc", "abc", -1},
{"", "abcd", -1},
{"xbcd", "abcd", -1},
{"abcd", "abcd", 0},
{"xabcd", "abcd", 1},
{"xyabcd"[:5], "abcd", -1},
{"xbcqq", "abcqq", -1},
{"abcqq", "abcqq", 0},
{"xabcqq", "abcqq", 1},
{"xyabcqq"[:6], "abcqq", -1},
{"xabxcqq", "abcqq", -1},
{"xabcqxq", "abcqq", -1},
{"", "01234567", -1},
{"32145678", "01234567", -1},
{"01234567", "01234567", 0},
{"x01234567", "01234567", 1},
{"x0123456x01234567", "01234567", 9},
{"xx01234567"[:9], "01234567", -1},
{"", "0123456789", -1},
{"3214567844", "0123456789", -1},
{"0123456789", "0123456789", 0},
{"x0123456789", "0123456789", 1},
{"x012345678x0123456789", "0123456789", 11},
{"xyz0123456789"[:12], "0123456789", -1},
{"x01234567x89", "0123456789", -1},
{"", "0123456789012345", -1},
{"3214567889012345", "0123456789012345", -1},
{"0123456789012345", "0123456789012345", 0},
{"x0123456789012345", "0123456789012345", 1},
{"x012345678901234x0123456789012345", "0123456789012345", 17},
{"", "01234567890123456789", -1},
{"32145678890123456789", "01234567890123456789", -1},
{"01234567890123456789", "01234567890123456789", 0},
{"x01234567890123456789", "01234567890123456789", 1},
{"x0123456789012345678x01234567890123456789", "01234567890123456789", 21},
{"xyz01234567890123456789"[:22], "01234567890123456789", -1},
{"", "0123456789012345678901234567890", -1},
{"321456788901234567890123456789012345678911", "0123456789012345678901234567890", -1},
{"0123456789012345678901234567890", "0123456789012345678901234567890", 0},
{"x0123456789012345678901234567890", "0123456789012345678901234567890", 1},
{"x012345678901234567890123456789x0123456789012345678901234567890", "0123456789012345678901234567890", 32},
{"xyz0123456789012345678901234567890"[:33], "0123456789012345678901234567890", -1},
{"", "01234567890123456789012345678901", -1},
{"32145678890123456789012345678901234567890211", "01234567890123456789012345678901", -1},
{"01234567890123456789012345678901", "01234567890123456789012345678901", 0},
{"x01234567890123456789012345678901", "01234567890123456789012345678901", 1},
{"x0123456789012345678901234567890x01234567890123456789012345678901", "01234567890123456789012345678901", 33},
{"xyz01234567890123456789012345678901"[:34], "01234567890123456789012345678901", -1},
{"xxxxxx012345678901234567890123456789012345678901234567890123456789012", "012345678901234567890123456789012345678901234567890123456789012", 6},
{"", "0123456789012345678901234567890123456789", -1},
{"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456789", 2},
{"xx012345678901234567890123456789012345678901234567890123456789012"[:41], "0123456789012345678901234567890123456789", -1},
{"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx", -1},
{"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65},
{"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33},
{"fofofofooofoboo", "oo", 7},
{"fofofofofofoboo", "ob", 11},
{"fofofofofofoboo", "boo", 12},
{"fofofofofofoboo", "oboo", 11},
{"fofofofofoooboo", "fooo", 8},
{"fofofofofofoboo", "foboo", 10},
{"fofofofofofoboo", "fofob", 8},
{"fofofofofofofoffofoobarfoo", "foffof", 12},
{"fofofofofoofofoffofoobarfoo", "foffof", 13},
{"fofofofofofofoffofoobarfoo", "foffofo", 12},
{"fofofofofoofofoffofoobarfoo", "foffofo", 13},
{"fofofofofoofofoffofoobarfoo", "foffofoo", 13},
{"fofofofofofofoffofoobarfoo", "foffofoo", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoob", 13},
{"fofofofofofofoffofoobarfoo", "foffofoob", 12},
{"fofofofofoofofoffofoobarfoo", "foffofooba", 13},
{"fofofofofofofoffofoobarfoo", "foffofooba", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoobar", 13},
{"fofofofofofofoffofoobarfoo", "foffofoobar", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoobarf", 13},
{"fofofofofofofoffofoobarfoo", "foffofoobarf", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoobarfo", 13},
{"fofofofofofofoffofoobarfoo", "foffofoobarfo", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoobarfoo", 13},
{"fofofofofofofoffofoobarfoo", "foffofoobarfoo", 12},
{"fofofofofoofofoffofoobarfoo", "ofoffofoobarfoo", 12},
{"fofofofofofofoffofoobarfoo", "ofoffofoobarfoo", 11},
{"fofofofofoofofoffofoobarfoo", "fofoffofoobarfoo", 11},
{"fofofofofofofoffofoobarfoo", "fofoffofoobarfoo", 10},
{"fofofofofoofofoffofoobarfoo", "foobars", -1},
{"foofyfoobarfoobar", "y", 4},
{"oooooooooooooooooooooo", "r", -1},
{"oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22},
{"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1},
{"oxoxoxoxoxoxoxoxoxoxox☺", "☺", 22},
{"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx\xed\x9f\xc0", "\xed\x9f\xc0", 105},
{"000000000000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000001", 5},
}
func Test_strstr(t *testing.T) {
var tt = []struct {
h string
n string
out int
}{
{"", "", 0},
{"", "a", -1},
{"", "foo", -1},
{"fo", "foo", -1},
{"foo", "foo", 0},
{"oofofoofooo", "f", 2},
{"oofofoofooo", "foo", 4},
{"barfoobarfoo", "foo", 3},
{"foo", "", 0},
{"foo", "o", 1},
{"abcABCabc", "A", 3},
{"jrzm6jjhorimglljrea4w3rlgosts0w2gia17hno2td4qd1jz", "jz", 47},
{"ekkuk5oft4eq0ocpacknhwouic1uua46unx12l37nioq9wbpnocqks6", "ks6", 52},
{"999f2xmimunbuyew5vrkla9cpwhmxan8o98ec", "98ec", 33},
{"9lpt9r98i04k8bz6c6dsrthb96bhi", "96bhi", 24},
{"55u558eqfaod2r2gu42xxsu631xf0zobs5840vl", "5840vl", 33},
{"", "a", -1},
{"x", "a", -1},
{"x", "x", 0},
{"abc", "a", 0},
{"abc", "b", 1},
{"abc", "c", 2},
{"abc", "x", -1},
{"", "ab", -1},
{"bc", "ab", -1},
{"ab", "ab", 0},
{"xab", "ab", 1},
{"xab"[:2], "ab", -1},
{"", "abc", -1},
{"xbc", "abc", -1},
{"abc", "abc", 0},
{"xabc", "abc", 1},
{"xabc"[:3], "abc", -1},
{"xabxc", "abc", -1},
{"", "abcd", -1},
{"xbcd", "abcd", -1},
{"abcd", "abcd", 0},
{"xabcd", "abcd", 1},
{"xyabcd"[:5], "abcd", -1},
{"xbcqq", "abcqq", -1},
{"abcqq", "abcqq", 0},
{"xabcqq", "abcqq", 1},
{"xyabcqq"[:6], "abcqq", -1},
{"xabxcqq", "abcqq", -1},
{"xabcqxq", "abcqq", -1},
{"", "01234567", -1},
{"32145678", "01234567", -1},
{"01234567", "01234567", 0},
{"x01234567", "01234567", 1},
{"x0123456x01234567", "01234567", 9},
{"xx01234567"[:9], "01234567", -1},
{"", "0123456789", -1},
{"3214567844", "0123456789", -1},
{"0123456789", "0123456789", 0},
{"x0123456789", "0123456789", 1},
{"x012345678x0123456789", "0123456789", 11},
{"xyz0123456789"[:12], "0123456789", -1},
{"x01234567x89", "0123456789", -1},
{"", "0123456789012345", -1},
{"3214567889012345", "0123456789012345", -1},
{"0123456789012345", "0123456789012345", 0},
{"x0123456789012345", "0123456789012345", 1},
{"x012345678901234x0123456789012345", "0123456789012345", 17},
{"", "01234567890123456789", -1},
{"32145678890123456789", "01234567890123456789", -1},
{"01234567890123456789", "01234567890123456789", 0},
{"x01234567890123456789", "01234567890123456789", 1},
{"x0123456789012345678x01234567890123456789", "01234567890123456789", 21},
{"xyz01234567890123456789"[:22], "01234567890123456789", -1},
{"", "0123456789012345678901234567890", -1},
{"321456788901234567890123456789012345678911", "0123456789012345678901234567890", -1},
{"0123456789012345678901234567890", "0123456789012345678901234567890", 0},
{"x0123456789012345678901234567890", "0123456789012345678901234567890", 1},
{"x012345678901234567890123456789x0123456789012345678901234567890", "0123456789012345678901234567890", 32},
{"xyz0123456789012345678901234567890"[:33], "0123456789012345678901234567890", -1},
{"", "01234567890123456789012345678901", -1},
{"32145678890123456789012345678901234567890211", "01234567890123456789012345678901", -1},
{"01234567890123456789012345678901", "01234567890123456789012345678901", 0},
{"x01234567890123456789012345678901", "01234567890123456789012345678901", 1},
{"x0123456789012345678901234567890x01234567890123456789012345678901", "01234567890123456789012345678901", 33},
{"xyz01234567890123456789012345678901"[:34], "01234567890123456789012345678901", -1},
{"xxxxxx012345678901234567890123456789012345678901234567890123456789012", "012345678901234567890123456789012345678901234567890123456789012", 6},
{"", "0123456789012345678901234567890123456789", -1},
{"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456789", 2},
{"xx012345678901234567890123456789012345678901234567890123456789012"[:41], "0123456789012345678901234567890123456789", -1},
{"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx", -1},
{"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65},
{"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33},
{"fofofofooofoboo", "oo", 7},
{"fofofofofofoboo", "ob", 11},
{"fofofofofofoboo", "boo", 12},
{"fofofofofofoboo", "oboo", 11},
{"fofofofofoooboo", "fooo", 8},
{"fofofofofofoboo", "foboo", 10},
{"fofofofofofoboo", "fofob", 8},
{"fofofofofofofoffofoobarfoo", "foffof", 12},
{"fofofofofoofofoffofoobarfoo", "foffof", 13},
{"fofofofofofofoffofoobarfoo", "foffofo", 12},
{"fofofofofoofofoffofoobarfoo", "foffofo", 13},
{"fofofofofoofofoffofoobarfoo", "foffofoo", 13},
{"fofofofofofofoffofoobarfoo", "foffofoo", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoob", 13},
{"fofofofofofofoffofoobarfoo", "foffofoob", 12},
{"fofofofofoofofoffofoobarfoo", "foffofooba", 13},
{"fofofofofofofoffofoobarfoo", "foffofooba", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoobar", 13},
{"fofofofofofofoffofoobarfoo", "foffofoobar", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoobarf", 13},
{"fofofofofofofoffofoobarfoo", "foffofoobarf", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoobarfo", 13},
{"fofofofofofofoffofoobarfoo", "foffofoobarfo", 12},
{"fofofofofoofofoffofoobarfoo", "foffofoobarfoo", 13},
{"fofofofofofofoffofoobarfoo", "foffofoobarfoo", 12},
{"fofofofofoofofoffofoobarfoo", "ofoffofoobarfoo", 12},
{"fofofofofofofoffofoobarfoo", "ofoffofoobarfoo", 11},
{"fofofofofoofofoffofoobarfoo", "fofoffofoobarfoo", 11},
{"fofofofofofofoffofoobarfoo", "fofoffofoobarfoo", 10},
{"fofofofofoofofoffofoobarfoo", "foobars", -1},
{"fofofofofofo\x00foffofoobar", "foffof", -1},
{"foofyfoobarfoobar", "y", 4},
{"oooooooooooooooooooooo", "r", -1},
{"oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22},
{"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1},
}
tt := append(searchTests,
searchTest{"fofofofofofo\x00foffofoobar", "foffof", -1},
searchTest{"0000000000000000\x000123456789012345678901234567890", "0123456789012345", -1},
)
for i := range tt {
ptr1 := uint64(len(memory) - len(tt[i].h) - 1)
ptr1 := uint64(len(memory) - len(tt[i].haystk) - 1)
clear(memory)
copy(memory[ptr1:], tt[i].h)
copy(memory[ptr2:], tt[i].n)
copy(memory[ptr1:], tt[i].haystk)
copy(memory[ptr2:], tt[i].needle)
var want uint64
if tt[i].out >= 0 {
@@ -785,11 +813,111 @@ func Test_strstr(t *testing.T) {
got := call(strstr, uint64(ptr1), uint64(ptr2))
if got != want {
t.Errorf("strstr(%q, %q) = %d, want %d",
tt[i].h, tt[i].n, uint32(got), uint32(want))
tt[i].haystk, tt[i].needle,
uint32(got), uint32(want))
}
}
}
func Test_memmem(t *testing.T) {
tt := append(searchTests,
searchTest{"fofofofofofo\x00foffofoobar", "foffof", 13},
searchTest{"0000000000000000\x000123456789012345678901234567890", "0123456789012345", 17},
)
for i := range tt {
ptr1 := uint64(len(memory) - len(tt[i].haystk))
clear(memory)
copy(memory[ptr1:], tt[i].haystk)
copy(memory[ptr2:], tt[i].needle)
var want uint64
if tt[i].out >= 0 {
want = ptr1 + uint64(tt[i].out)
}
got := call(memmem,
uint64(ptr1), uint64(len(tt[i].haystk)),
uint64(ptr2), uint64(len(tt[i].needle)))
if got != want {
t.Errorf("memmem(%q, %q) = %d, want %d",
tt[i].haystk, tt[i].needle,
uint32(got), uint32(want))
}
}
}
func Fuzz_strstr(f *testing.F) {
tt := append(searchTests,
searchTest{"fofofofofofo\x00foffofoobar", "foffof", -1},
searchTest{"0000000000000000\x000123456789012345678901234567890", "0123456789012345", -1},
)
for i := range tt {
f.Add(tt[i].haystk, tt[i].needle)
}
f.Fuzz(func(t *testing.T, haystk, needle string) {
if len(haystk) > 128 || len(needle) > 32 {
t.SkipNow()
}
clear(memory[ptr1 : ptr1+256])
clear(memory[ptr2 : ptr2+256])
copy(memory[ptr1:], haystk)
copy(memory[ptr2:], needle)
want := strings.Index(term(haystk), term(needle))
if want >= 0 {
want = ptr1 + want
} else {
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))
}
})
}
func Fuzz_memmem(f *testing.F) {
tt := append(searchTests,
searchTest{"fofofofofofo\x00foffofoobar", "foffof", 13},
searchTest{"0000000000000000\x000123456789012345678901234567890", "0123456789012345", 17},
)
for i := range tt {
f.Add(tt[i].haystk, tt[i].needle)
}
f.Fuzz(func(t *testing.T, haystk, needle string) {
if len(haystk) > 128 || len(needle) > 32 {
t.SkipNow()
}
clear(memory[ptr1 : ptr1+256])
clear(memory[ptr2 : ptr2+256])
copy(memory[ptr1:], haystk)
copy(memory[ptr2:], needle)
want := strings.Index(haystk, needle)
if want >= 0 {
want = ptr1 + want
} else {
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))
}
})
}
func fill(s []byte, v byte) {
for i := range s {
s[i] = v

View File

@@ -507,9 +507,9 @@ size_t strcspn(const char *s, const char *c) {
#undef _WASM_SIMD128_CHKBITS
#undef _WASM_SIMD128_BITMAP256_T
static const char *__memmem_raita(const char *haystk, size_t sh,
const char *needle, size_t sn,
uint8_t bmbc[256]) {
static const char *__memmem(const char *haystk, size_t sh,
const char *needle, size_t sn,
uint8_t bmbc[256]) {
// https://www-igm.univ-mlv.fr/~lecroq/string/node22.html
// http://0x80.pl/notesen/2016-11-28-simd-strfind.html
@@ -543,6 +543,8 @@ static const char *__memmem_raita(const char *haystk, size_t sh,
// Each iteration clears that bit, tries again.
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 (!__memcmpeq(haystk + ctz + 1, needle + 1, sn - 1)) {
return haystk + ctz;
}
@@ -550,17 +552,17 @@ static const char *__memmem_raita(const char *haystk, size_t sh,
}
size_t skip = sizeof(v128_t);
// Apply the bad-character rule to the last checked
// character of the haystack.
if (bmbc) skip += bmbc[(unsigned char)haystk[sn + 14]];
if (sh != SIZE_MAX) {
if (sh == SIZE_MAX) {
// Have we reached the end of the haystack?
if (!wasm_i8x16_all_true(blk_fst)) return NULL;
} else {
// Apply the bad-character rule to the last checked
// character of the haystack.
if (bmbc) skip += bmbc[(unsigned char)haystk[sn - 1 + 15]];
// 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;
} else if (!wasm_i8x16_all_true(blk_fst)) {
// We found a terminator.
return NULL;
}
haystk += skip;
}
@@ -577,11 +579,27 @@ static const char *__memmem_raita(const char *haystk, size_t sh,
return NULL;
}
static const char *__memmem(const char *haystk, size_t sh, //
const char *needle, size_t sn) {
__attribute__((weak))
void *memmem(const void *vh, size_t sh, const void *vn, size_t sn) {
// Return immediately on empty needle.
if (sn == 0) return (void *)vh;
// Return immediately when needle is longer than haystack.
if (sn > sh) return NULL;
// Skip to the first matching character using memchr,
// handling single character needles.
const char *needle = (char *)vn;
const char *haystk = (char *)memchr(vh, *needle, sh);
if (!haystk || sn == 1) return (void *)haystk;
// The haystack got shorter, is the needle now longer?
sh -= haystk - (char *)vh;
if (sn > sh) return NULL;
// Is Boyer-Moore's bad-character rule useful?
if (sn < sizeof(v128_t) || sh - sn < sizeof(v128_t)) {
return __memmem_raita(haystk, sh, needle, sn, NULL);
return (void *)__memmem(haystk, sh, needle, sn, NULL);
}
// https://www-igm.univ-mlv.fr/~lecroq/string/node14.html
@@ -613,28 +631,7 @@ static const char *__memmem(const char *haystk, size_t sh, //
bmbc[(unsigned char)needle[i]] = t;
}
return __memmem_raita(haystk, sh, needle, sn, bmbc);
}
__attribute__((weak))
void *memmem(const void *vh, size_t sh, const void *vn, size_t sn) {
// Return immediately on empty needle.
if (sn == 0) return (void *)vh;
// Return immediately when needle is longer than haystack.
if (sn > sh) return NULL;
// Skip to the first matching character using memchr,
// handling single character needles.
const char *needle = (char *)vn;
const char *haystk = (char *)memchr(vh, *needle, sh);
if (!haystk || sn == 1) return (void *)haystk;
// The haystack got shorter, is the needle now longer?
sh -= haystk - (char *)vh;
if (sn > sh) return NULL;
return (void *)__memmem(haystk, sh, needle, sn);
return (void *)__memmem(haystk, sh, needle, sn, bmbc);
}
__attribute__((weak))
@@ -647,7 +644,7 @@ char *strstr(const char *haystk, const char *needle) {
haystk = strchr(haystk, *needle);
if (!haystk || !needle[1]) return (char *)haystk;
return (char *)__memmem(haystk, SIZE_MAX, needle, strlen(needle));
return (char *)__memmem(haystk, SIZE_MAX, needle, strlen(needle), NULL);
}
// Given the above SIMD implementations,