mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-20 02:27:21 +01:00
f53c8d6e91
Test AddressIterator for the absence of panics, nil addresses, and empty lists. This fuzz test finds https://github.com/lightningnetwork/lnd/issues/7552 in seconds. No other panics found after 300+ CPU-hours of fuzzing.
121 lines
2.7 KiB
Go
121 lines
2.7 KiB
Go
package wtclient
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// getAddress generates an address from the input data or returns nil if there
|
|
// aren't enough bytes remaining in the input data.
|
|
func getAddress(data *[]byte) net.Addr {
|
|
if len(*data) < 6 {
|
|
return nil
|
|
}
|
|
|
|
addr := &net.TCPAddr{
|
|
IP: net.IP((*data)[0:4]),
|
|
Port: int(binary.BigEndian.Uint16((*data)[4:6])),
|
|
}
|
|
|
|
*data = (*data)[6:]
|
|
|
|
return addr
|
|
}
|
|
|
|
// getAddressIterator returns an AddressIterator pre-filled with addresses
|
|
// generated from the input data.
|
|
func getAddressIterator(data *[]byte) AddressIterator {
|
|
var addrs []net.Addr
|
|
|
|
// Always attempt to generate at least one address from the input data.
|
|
// Continue generating addresses if the next data byte is 0xff.
|
|
for addr := getAddress(data); addr != nil; addr = getAddress(data) {
|
|
addrs = append(addrs, addr)
|
|
|
|
// Only read another address if the next byte is 0xff.
|
|
if len(*data) < 1 || (*data)[0] != 0xff {
|
|
break
|
|
}
|
|
*data = (*data)[1:]
|
|
}
|
|
|
|
iter, err := newAddressIterator(addrs...)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return iter
|
|
}
|
|
|
|
// FuzzAddressIterator tests that addressIterator does not panic for any
|
|
// sequence of methods called and that the iterator's list is never empty and
|
|
// never contains a nil address.
|
|
func FuzzAddressIterator(f *testing.F) {
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
iter := getAddressIterator(&data)
|
|
if iter == nil {
|
|
return
|
|
}
|
|
|
|
// Use the next byte in data to determine the next method call.
|
|
for len(data) >= 1 {
|
|
cmd := data[0]
|
|
data = data[1:]
|
|
|
|
switch cmd {
|
|
case 0x00:
|
|
addr, err := iter.Next()
|
|
if err == nil {
|
|
require.NotNil(t, addr)
|
|
}
|
|
case 0x01:
|
|
addr, err := iter.NextAndLock()
|
|
if err == nil {
|
|
require.NotNil(t, addr)
|
|
}
|
|
case 0x02:
|
|
addr := iter.Peek()
|
|
require.NotNil(t, addr)
|
|
case 0x03:
|
|
addr := iter.PeekAndLock()
|
|
require.NotNil(t, addr)
|
|
case 0x04:
|
|
if addr := getAddress(&data); addr != nil {
|
|
iter.ReleaseLock(addr)
|
|
}
|
|
case 0x05:
|
|
if addr := getAddress(&data); addr != nil {
|
|
iter.Add(addr)
|
|
}
|
|
case 0x06:
|
|
if addr := getAddress(&data); addr != nil {
|
|
_ = iter.Remove(addr)
|
|
}
|
|
case 0x07:
|
|
_ = iter.HasLocked()
|
|
case 0x08:
|
|
addrs := iter.GetAll()
|
|
require.NotEmpty(t, addrs)
|
|
for _, addr := range addrs {
|
|
require.NotNil(t, addr)
|
|
}
|
|
case 0x09:
|
|
iter.Reset()
|
|
case 0x0a:
|
|
iter = iter.Copy()
|
|
default:
|
|
// By returning instead of continuing, we
|
|
// provide backwards compatibility for our
|
|
// corpus. If we continued here, some current
|
|
// inputs would cause a different sequence of
|
|
// events if we later added a new case to the
|
|
// switch.
|
|
return
|
|
}
|
|
}
|
|
})
|
|
}
|