>Synopsis:      connect(2) on loopback TCP can sleep forever since 7.8
>Category:      kernel
>Environment:
System      : OpenBSD 7.9
Details     : OpenBSD 7.9 (GENERIC.MP) #449: Wed May  6 13:17:25 MDT 2026
[email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP

Architecture: OpenBSD.amd64
Machine     : amd64
>Description:
A blocking connect(2) to a loopback TCP listener sometimes never
returns: the thread stays asleep on wait channel "netcon"
while netstat shows the connection ESTABLISHED, or CLOSE_WAIT once
the acceptor has accepted and closed it. The thread sleeps until a
signal arrives. Several threads connecting concurrently hit it within
seconds.
    Reproduced on 7.8, 7.9 and 8.0. 7.7 runs the same program without a hang.
>How-To-Repeat:
/* connect-hang.c
  cc -o connect-hang connect-hang.c -lpthread
  ./connect-hang
  Typical output:
listening on 127.0.0.1:13911, 4 threads connecting
connect() in thread 0 stuck for 10 s
tcp          0      0  127.0.0.1.13911        127.0.0.1.5527         FIN_WAIT_2
tcp          0      0  127.0.0.1.29765        127.0.0.1.13911        CLOSE_WAIT
tcp          0      0  127.0.0.1.41235        127.0.0.1.13911        CLOSE_WAIT
tcp          0      0  127.0.0.1.5527         127.0.0.1.13911        CLOSE_WAIT
tcp          0      0  127.0.0.1.29187        127.0.0.1.13911        CLOSE_WAIT
tcp          0      0  127.0.0.1.13911        127.0.0.1.29765        FIN_WAIT_2
tcp          0      0  127.0.0.1.13911        127.0.0.1.41235        FIN_WAIT_2
tcp          0      0  127.0.0.1.13911        127.0.0.1.29187        FIN_WAIT_2
tcp          0      0  127.0.0.1.13911        *.*                    LISTEN
   TID WCHAN   STAT
507699 netcon  S+
266118 wait    S+
473010 netacc  S+
554536 netcon  S+
408733 netcon  S+
581453 netcon  S+
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <err.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define THREADS 4
#define STUCK_SECONDS 10
#define RUN_SECONDS 60

static struct sockaddr_in addr;
static volatile time_t connecting[THREADS];

static void *
acceptor(void *arg)
{
   int lfd = *(int *)arg;

   for (;;) {
       int c = accept(lfd, NULL, NULL);
       if (c >= 0)
           close(c);
   }
   return NULL;
}

static void *
connector(void *arg)
{
   int i = *(int *)arg;
   char c;

   for (;;) {
       int s = socket(AF_INET, SOCK_STREAM, 0);
       if (s < 0)
           err(1, "socket");
       connecting[i] = time(NULL);
       if (connect(s, (struct sockaddr *)&addr, sizeof addr) < 0)
           err(1, "connect");
       connecting[i] = 0;
       /* Let the acceptor close first, so TIME_WAIT stays on its side. */
       (void)read(s, &c, 1);
       close(s);
   }
   return NULL;
}

int
main(void)
{
   int lfd, ids[THREADS], i;
   socklen_t len = sizeof addr;
   pthread_t t;
   time_t start = time(NULL);
   char cmd[128];

   lfd = socket(AF_INET, SOCK_STREAM, 0);
   if (lfd < 0)
       err(1, "socket");
   addr.sin_family = AF_INET;
   addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
   if (bind(lfd, (struct sockaddr *)&addr, sizeof addr) < 0)
       err(1, "bind");
   if (listen(lfd, 128) < 0)
       err(1, "listen");
   if (getsockname(lfd, (struct sockaddr *)&addr, &len) < 0)
       err(1, "getsockname");
   printf("listening on 127.0.0.1:%u, %d threads connecting\n",
       ntohs(addr.sin_port), THREADS);

   if (pthread_create(&t, NULL, acceptor, &lfd) != 0)
       err(1, "pthread_create");
   for (i = 0; i < THREADS; i++) {
       ids[i] = i;
       if (pthread_create(&t, NULL, connector, &ids[i]) != 0)
           err(1, "pthread_create");
   }

   while (time(NULL) - start < RUN_SECONDS) {
       sleep(1);
       for (i = 0; i < THREADS; i++) {
           time_t since = connecting[i];
           if (since != 0 && time(NULL) - since >= STUCK_SECONDS) {
               printf("connect() in thread %d stuck for %lld s\n",
                   i, (long long)(time(NULL) - since));
               fflush(stdout);
               snprintf(cmd, sizeof cmd,
                   "netstat -an -p tcp | grep '\\.%u ' | grep -v TIME_WAIT",
                   ntohs(addr.sin_port));
               (void)system(cmd);
               snprintf(cmd, sizeof cmd,
                   "ps -H -o tid,wchan,state -p %d", getpid());
               (void)system(cmd);
               return 1;
           }
       }
   }
   printf("no hang after %d s\n", RUN_SECONDS);
   return 0;
}
>Fix:
Not known.

dmesg:
OpenBSD 7.9 (GENERIC.MP) #449: Wed May  6 13:17:25 MDT 2026
    [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 8573091840 (8175MB)
avail mem = 8285696000 (7901MB)
random: good seed from bootblocks
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 2.5 @ 0xe1000 (10 entries)
bios0: vendor innotek GmbH version "VirtualBox" date 12/01/2006
bios0: innotek GmbH VirtualBox
acpi0 at bios0: ACPI 4.0
acpi0: sleep states S0 S5
acpi0: tables DSDT FACP APIC SSDT
acpi0: wakeup devices
acpitimer0 at acpi0: 3579545 Hz, 32 bits
acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: AMD Ryzen AI 7 350 w/ Radeon 860M, 2023.92 MHz, 1a-60-00, patch 0b600037
cpu0: cpuid 1 
edx=178bfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT>
ecx=76d83203<SSE3,PCLMUL,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND>
cpu0: cpuid 6 eax=4<ARAT>
cpu0: cpuid 7.0
ebx=208c0529<FSGSBASE,BMI1,AVX2,BMI2,INVPCID,RDSEED,ADX,CLFLUSHOPT,SHA>
edx=10000000<L1DF>
cpu0: cpuid 80000001 edx=2bd3fb7f<NXE,MMXX,FFXSR,RDTSCP,LONG>
ecx=1f3<LAHF,CMPLEG,AMCR8,ABM,SSE4A,MASSE,3DNOWP>
cpu0: cpuid 80000007 edx=100<ITSC>
cpu0: cpuid 80000008 ebx=24001000<IBPB,SSBDNR>
cpu0: cpuid 8000001F eax=1<SME>
cpu0: 48KB 64b/line 12-way D-cache, 32KB 64b/line 8-way I-cache
cpu0: 1MB 64b/line 16-way L2 cache
cpu0: smt 0, core 0, package 0, type P
mtrr: Pentium Pro MTRR support, 16 var ranges, 88 fixed ranges
cpu0: apic clock running at 1000MHz
cpu1 at mainbus0: apid 1 (application processor)
cpu1: AMD Ryzen AI 7 350 w/ Radeon 860M, 2024.01 MHz, 1a-60-00, patch 0b600037
cpu1: smt 0, core 0, package 1, type P
cpu2 at mainbus0: apid 2 (application processor)
cpu2: AMD Ryzen AI 7 350 w/ Radeon 860M, 2024.06 MHz, 1a-60-00, patch 0b600037
cpu2: smt 0, core 0, package 2, type P
cpu3 at mainbus0: apid 3 (application processor)
cpu3: AMD Ryzen AI 7 350 w/ Radeon 860M, 2024.20 MHz, 1a-60-00, patch 0b600037
cpu3: smt 0, core 0, package 3, type P
cpu4 at mainbus0: apid 4 (application processor)
cpu4: AMD Ryzen AI 7 350 w/ Radeon 860M, 2024.28 MHz, 1a-60-00, patch 0b600037
cpu4: smt 0, core 0, package 4, type P
cpu5 at mainbus0: apid 5 (application processor)
cpu5: AMD Ryzen AI 7 350 w/ Radeon 860M, 2026.19 MHz, 1a-60-00, patch 0b600037
cpu5: smt 0, core 0, package 5, type P
cpu6 at mainbus0: apid 6 (application processor)
cpu6: AMD Ryzen AI 7 350 w/ Radeon 860M, 2024.60 MHz, 1a-60-00, patch 0b600037
cpu6: smt 0, core 0, package 6, type P
cpu7 at mainbus0: apid 7 (application processor)
cpu7: AMD Ryzen AI 7 350 w/ Radeon 860M, 2026.53 MHz, 1a-60-00, patch 0b600037
cpu7: smt 0, core 0, package 7, type P
ioapic0 at mainbus0: apid 8 pa 0xfec00000, version 20, 24 pins, remapped
acpiprt0 at acpi0: bus 0 (PCI0)
acpipci0 at acpi0 PCI0: 0x00000000 0x00000011 0x00000001
"PNP0303" at acpi0 not configured
"PNP0F03" at acpi0 not configured
acpibat0 at acpi0: BAT0 model "1" serial 0 type VBOX oem "innotek"
acpiac0 at acpi0: AC unit online
acpicpu0 at acpi0: C1(@1 halt!)
acpicpu1 at acpi0: C1(@1 halt!)
acpicpu2 at acpi0: C1(@1 halt!)
acpicpu3 at acpi0: C1(@1 halt!)
acpicpu4 at acpi0: C1(@1 halt!)
acpicpu5 at acpi0: C1(@1 halt!)
acpicpu6 at acpi0: C1(@1 halt!)
acpicpu7 at acpi0: C1(@1 halt!)
acpivideo0 at acpi0: GFX0
pci0 at mainbus0 bus 0
pchb0 at pci0 dev 0 function 0 "Intel 82441FX" rev 0x02
pcib0 at pci0 dev 1 function 0 "Intel 82371SB ISA" rev 0x00
pciide0 at pci0 dev 1 function 1 "Intel 82371AB IDE" rev 0x01: DMA,
channel 0 configured to compatibility, channel 1 configured to
compatibility
wd0 at pciide0 channel 0 drive 0: <VBOX HARDDISK>
wd0: 128-sector PIO, LBA, 81920MB, 167772160 sectors
wd0(pciide0:0:0): using PIO mode 4, Ultra-DMA mode 2
atapiscsi0 at pciide0 channel 1 drive 0
scsibus1 at atapiscsi0: 2 targets
cd0 at scsibus1 targ 0 lun 0: <VBOX, CD-ROM, 1.0> removable
cd0(pciide0:1:0): using PIO mode 4, Ultra-DMA mode 2
vga1 at pci0 dev 2 function 0 "VMware SVGA II" rev 0x00
wsdisplay0 at vga1 mux 1: console (80x25, vt100 emulation)
wsdisplay0: screen 1-5 added (80x25, vt100 emulation)
em0 at pci0 dev 3 function 0 "Intel 82540EM" rev 0x02: apic 8 int 19,
address 08:00:27:c2:e7:d9
"InnoTek Guest Service" rev 0x00 at pci0 dev 4 function 0 not configured
auich0 at pci0 dev 5 function 0 "Intel 82801AA AC97" rev 0x01: apic 8
int 21, ICH
ac97: codec id 0x83847600 (SigmaTel STAC9700)
audio0 at auich0
ohci0 at pci0 dev 6 function 0 "Apple Intrepid USB" rev 0x00: apic 8
int 22, version 1.0
piixpm0 at pci0 dev 7 function 0 "Intel 82371AB Power" rev 0x08: apic 8 int 23
iic0 at piixpm0
ehci0 at pci0 dev 11 function 0 "Intel 82801FB USB" rev 0x00: apic 8 int 19
usb0 at ehci0: USB revision 2.0
uhub0 at usb0 configuration 1 interface 0 "Intel EHCI root hub" rev
2.00/1.00 addr 1
isa0 at pcib0
isadma0 at isa0
pckbc0 at isa0 port 0x60/5 irq 1 irq 12
pckbd0 at pckbc0 (kbd slot)
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pms0 at pckbc0 (aux slot)
wsmouse0 at pms0 mux 0
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
usb1 at ohci0: USB revision 1.0
uhub1 at usb1 configuration 1 interface 0 "Apple OHCI root hub" rev
1.00/1.00 addr 1
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
scsibus3 at softraid0: 256 targets
root on wd0a (9f8f56d70b6c5cbe.a) swap on wd0b dump on wd0b
WARNING: clock gained 77 days
WARNING: CHECK AND RESET THE DATE!

usbdevs:
Controller /dev/usb0:
addr 01: 8086:0000 Intel, EHCI root hub
high speed, self powered, config 1, rev 1.00
driver: uhub0
Controller /dev/usb1:
addr 01: 106b:0000 Apple, OHCI root hub
full speed, self powered, config 1, rev 1.00
driver: uhub1

Reply via email to