-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Open
Description
Version: v0.42.1-0.20250702212416-7b7c3ed4ce0
Stack trace:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x9abe95]
goroutine 1 [running]:
github.com/libp2p/go-libp2p/p2p/transport/quicreuse.(*refcountedTransport).Listen(0x13e6618?, 0x0?, 0xc000000001?)
/home/ddz/go/pkg/mod/github.com/libp2p/go-libp2p@v0.42.1-0.20250702212416-7b7c3ed4ce04/p2p/transport/quicreuse/reuse.go:149 +0x15
github.com/libp2p/go-libp2p/p2p/transport/quicreuse.newQuicListener({0x13f3b30, 0xc000487140}, 0xc000139680)
/home/ddz/go/pkg/mod/github.com/libp2p/go-libp2p@v0.42.1-0.20250702212416-7b7c3ed4ce04/p2p/transport/quicreuse/listener.go:74 +0x264
github.com/libp2p/go-libp2p/p2p/transport/quicreuse.(*ConnManager).ListenQUICAndAssociate(0xc0003f8a50, {0x0, 0x0}, {0xc0004a4200?, 0x1?, 0x13f36d0?}, 0xc0004a83c0, 0x12cbd28)
/home/ddz/go/pkg/mod/github.com/libp2p/go-libp2p@v0.42.1-0.20250702212416-7b7c3ed4ce04/p2p/transport/quicreuse/connmgr.go:231 +0x3ec
github.com/libp2p/go-libp2p/p2p/transport/quicreuse.(*ConnManager).ListenQUIC(...)
/home/ddz/go/pkg/mod/github.com/libp2p/go-libp2p@v0.42.1-0.20250702212416-7b7c3ed4ce04/p2p/transport/quicreuse/connmgr.go:202
main.main.func1({0xc3, 0x85, 0xf, 0x39, 0x3e, 0x3a, 0xa2, 0x76, 0x19, 0xb1, ...}, ...)
/home/ddz/Lab/nunet/go-libp2p-duplicate-quic-bug/main.go:128 +0x317
reflect.Value.call({0xe96840?, 0x12cbd20?, 0x416f14?}, {0x1039b73, 0x4}, {0xc0004a7860, 0x2, 0x500010000000003?})
/snap/go/10907/src/reflect/value.go:584 +0xca6
reflect.Value.Call({0xe96840?, 0x12cbd20?, 0x0?}, {0xc0004a7860?, 0xc00029d1d8?, 0x471b93?})
/snap/go/10907/src/reflect/value.go:368 +0xb9
go.uber.org/fx.paramTagsAnnotation.build.func1({0xc0004a7860?, 0x2?, 0x2?})
/home/ddz/go/pkg/mod/go.uber.org/fx@v1.24.0/annotated.go:258 +0x54
reflect.Value.call({0xe96840?, 0xc00049ce40?, 0x30?}, {0x1039b73, 0x4}, {0xc0004a73e0, 0x2, 0x10?})
/snap/go/10907/src/reflect/value.go:584 +0xca6
reflect.Value.Call({0xe96840?, 0xc00049ce40?, 0x4179a5?}, {0xc0004a73e0?, 0xf345c0?, 0xc0004a7801?})
/snap/go/10907/src/reflect/value.go:368 +0xb9
go.uber.org/dig.defaultInvoker({0xe96840?, 0xc00049ce40?, 0xc00029deb0?}, {0xc0004a73e0?, 0x2?, 0x13fe770?})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/container.go:257 +0x25
go.uber.org/dig.(*constructorNode).Call(0xc000485a00, {0x13fe770, 0xc00015b600})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/constructor.go:198 +0x472
go.uber.org/dig.paramSingle.Build({{0x0, 0x0}, 0x0, {0x1403340, 0xfd6020}}, {0x13fe770, 0xc00015b600})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/param.go:288 +0x34d
go.uber.org/dig.paramList.BuildList({{0x1403340, 0xea2c40}, {0xc0003a3440, 0x3, 0x3}}, {0x13fe770, 0xc00015b600})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/param.go:151 +0xad
go.uber.org/dig.(*constructorNode).Call(0xc0001172b0, {0x13fe770, 0xc00015b600})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/constructor.go:160 +0x137
go.uber.org/dig.paramSingle.Build({{0x0, 0x0}, 0x0, {0x1403340, 0x1021140}}, {0x13fe770, 0xc00015b600})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/param.go:288 +0x34d
go.uber.org/dig.paramObjectField.Build(...)
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/param.go:485
go.uber.org/dig.paramObject.Build({{0x1403340, 0xc000486f00}, {0xc000137b80, 0x2, 0x2}, {0x0, 0x0, 0x0}}, {0x13fe770, 0xc00015b600})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/param.go:413 +0x5d2
go.uber.org/dig.paramList.BuildList({{0x1403340, 0xc000137b30}, {0xc0004ae4e0, 0x1, 0x1}}, {0x13fe770, 0xc00015b600})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/param.go:151 +0xad
go.uber.org/dig.(*Scope).Invoke(0xc00015b600, {0xc000137b30, 0xc0004a6cf0}, {0x0, 0x0, 0x470c01?})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/invoke.go:123 +0x313
go.uber.org/dig.(*Container).Invoke(0xc0003f88f0?, {0xc000137b30?, 0xc0004a6cf0?}, {0x0?, 0x20?, 0xc00029e9f8?})
/home/ddz/go/pkg/mod/go.uber.org/dig@v1.19.0/invoke.go:83 +0x25
go.uber.org/fx.runInvoke({0x776a10c89998, 0xc00011c4d8}, {{0xfdc9c0, 0xc00015b4a0}, {0xc0003a0b40, 0x6, 0x7}})
/home/ddz/go/pkg/mod/go.uber.org/fx@v1.24.0/invoke.go:107 +0x129
go.uber.org/fx.(*module).invoke(0xc000116dd0, {{0xfdc9c0, 0xc00015b4a0}, {0xc0003a0b40, 0x6, 0x7}})
/home/ddz/go/pkg/mod/go.uber.org/fx@v1.24.0/module.go:335 +0x145
go.uber.org/fx.(*module).invokeAll(0xc000116dd0)
/home/ddz/go/pkg/mod/go.uber.org/fx@v1.24.0/module.go:321 +0xda
go.uber.org/fx.New({0xc0003ae008, 0x24, 0x7?})
/home/ddz/go/pkg/mod/go.uber.org/fx@v1.24.0/app.go:507 +0x8b8
github.com/libp2p/go-libp2p/config.(*Config).NewNode(0xc000164508)
/home/ddz/go/pkg/mod/github.com/libp2p/go-libp2p@v0.42.1-0.20250702212416-7b7c3ed4ce04/config/config.go:610 +0x13d6
github.com/libp2p/go-libp2p.NewWithoutDefaults({0xc0003961c0, 0xf, 0x1c})
/home/ddz/go/pkg/mod/github.com/libp2p/go-libp2p@v0.42.1-0.20250702212416-7b7c3ed4ce04/libp2p.go:67 +0x65
github.com/libp2p/go-libp2p.New(...)
/home/ddz/go/pkg/mod/github.com/libp2p/go-libp2p@v0.42.1-0.20250702212416-7b7c3ed4ce04/libp2p.go:53
main.main()
/home/ddz/Lab/nunet/go-libp2p-duplicate-quic-bug/main.go:199 +0xf6d
exit status 2
Script to reproduce:
package main
import (
"context"
"crypto/rand"
"crypto/tls"
"fmt"
"log"
"net"
"time"
"github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/libp2p/go-libp2p/core/routing"
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem"
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
"github.com/libp2p/go-libp2p/p2p/net/connmgr"
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
"github.com/libp2p/go-libp2p/p2p/security/noise"
libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
ma "github.com/multiformats/go-multiaddr"
"github.com/quic-go/quic-go"
)
func main() {
// Generate a private key for testing
privKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
}
// Create the libp2p config with duplicate QUIC listen addresses
listenAddresses := []string{
"/ip4/0.0.0.0/tcp/0",
"/ip4/0.0.0.0/udp/1234/quic-v1", // First QUIC address
// "/ip4/0.0.0.0/udp/1234/quic-v1", // Duplicate QUIC address - this triggers the bug
}
// Create connection manager
connmgr, err := connmgr.NewConnManager(
100,
400,
connmgr.WithGracePeriod(10*time.Second),
)
if err != nil {
log.Fatalf("Failed to create connection manager: %v", err)
}
// Create peerstore
ps, err := pstoremem.NewPeerstore()
if err != nil {
log.Fatalf("Failed to create peerstore: %v", err)
}
// Set up resource manager
mem := int64(1024 * 1024 * 1024) // 1GB
fds := 512
limits := rcmgr.DefaultLimits
limits.SystemBaseLimit.ConnsInbound = 512
limits.SystemBaseLimit.ConnsOutbound = 512
limits.SystemBaseLimit.Conns = 1024
limits.SystemBaseLimit.StreamsInbound = 8192
limits.SystemBaseLimit.StreamsOutbound = 8192
limits.SystemBaseLimit.Streams = 16384
scaled := limits.Scale(mem, fds)
mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(scaled))
if err != nil {
log.Fatalf("Failed to create resource manager: %v", err)
}
// Create QUIC reuse function that demonstrates the bug
newReuse := func(statelessResetKey quic.StatelessResetKey, tokenGeneratorKey quic.TokenGeneratorKey) (*quicreuse.ConnManager, error) {
udpConn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 1234})
if err != nil {
return nil, fmt.Errorf("failed to create UDP listener: %w", err)
}
reuse, err := quicreuse.NewConnManager(statelessResetKey, tokenGeneratorKey)
if err != nil {
return nil, fmt.Errorf("failed to create reuse: %w", err)
}
// This is where the bug should occur - trying to lend the same transport twice
trDone, err := reuse.LendTransport("udp4", nil, udpConn)
if err != nil {
return nil, fmt.Errorf("failed to add transport to reuse: %w", err)
}
go func() {
<-trDone
fmt.Println("closing UDP connection")
udpConn.Close()
}()
_, err = reuse.ListenQUIC(
ma.StringCast(fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1", 1234)),
&tls.Config{NextProtos: []string{"raw"}},
func(*quic.Conn, uint64) bool { return false },
)
if err != nil {
return nil, fmt.Errorf("failed to listen quic: %w", err)
}
return reuse, nil
}
// Create libp2p options
var libp2pOpts []libp2p.Option
dhtOpts := []dht.Option{
dht.ProtocolPrefix(protocol.ID("/nunet")),
dht.Mode(dht.ModeAutoServer),
}
libp2pOpts = append(libp2pOpts,
libp2p.ListenAddrStrings(listenAddresses...),
libp2p.ResourceManager(mgr),
libp2p.Identity(privKey),
libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) {
idht, err := dht.New(context.Background(), h, dhtOpts...)
return idht, err
}),
libp2p.Peerstore(ps),
libp2p.Security(libp2ptls.ID, libp2ptls.New),
libp2p.Security(noise.ID, noise.New),
libp2p.ChainOptions(
libp2p.Transport(tcp.NewTCPTransport),
libp2p.Transport(libp2pquic.NewTransport),
libp2p.Transport(webtransport.New),
libp2p.Transport(ws.New),
),
libp2p.ConnectionManager(connmgr),
libp2p.EnableRelay(),
libp2p.EnableHolePunching(),
libp2p.EnableRelayService(
relay.WithLimit(&relay.RelayLimit{
Duration: 5 * time.Minute,
Data: 1 << 21, // 2 MiB
}),
),
libp2p.EnableAutoRelayWithPeerSource(
func(ctx context.Context, num int) <-chan peer.AddrInfo {
r := make(chan peer.AddrInfo)
go func() {
defer close(r)
for i := 0; i < num; i++ {
select {
case <-ctx.Done():
return
default:
// No peers to provide
}
}
}()
return r
},
autorelay.WithBootDelay(time.Minute),
autorelay.WithBackoff(30*time.Second),
autorelay.WithMinCandidates(2),
autorelay.WithMaxCandidates(3),
autorelay.WithNumRelays(2),
),
libp2p.QUICReuse(newReuse),
)
// This is where the bug should occur
host, err := libp2p.New(libp2pOpts...)
if err != nil {
fmt.Printf("Error creating libp2p host: %v\n", err)
fmt.Println("This confirms the bug is reproducible with duplicate QUIC addresses!")
return
}
// Clean up
if host != nil {
host.Close()
}
}
Metadata
Metadata
Assignees
Labels
No labels