• JS Socket.connect() callback thread cannot be cancelled and may act on

    From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Sun Oct 25 13:36:55 2026
    open https://gitlab.synchro.net/main/sbbs/-/work_items/1299

    `js_connect_event_thread()` (`src/sbbs3/js_socket.cpp`), the thread behind `Socket.connect(host, port, callback)`, runs `getaddrinfo()` and a blocking `connect()` on a copy of the Socket's descriptor. Nothing stops or waits for the thread when the Socket is closed, finalized, or its JS context destroyed while the connect is still in flight.

    Once the main side has closed the descriptor, the same handle value can be reissued to another thread in the process. The connect thread then:

    1. sets that unrelated socket to blocking mode (`ioctlsocket(FIONBIO, 0)`),
    2. calls `connect()` on it toward the pending host, and
    3. resets its blocking mode to whatever the dead script's Socket had.

    The window is the duration of a failing connect (the SYN retry timeout: roughly 20 s on Windows, up to ~2 min on Linux) overlapping an explicit `close()`, a GC finalize, or a server recycle. The ircd under `services` is the most exposed caller: an auto-connect to an unreachable hub is in flight for most of its retry cycle, and a recycle during that window hands the hub connect to whichever socket next reuses the handle.

    The thread was introduced in 1928973941 (2021-04-02).

    Proposed fix, either of:

    - **Transfer descriptor ownership to the thread while a connect is pending.** Mark the Socket private as connect-pending when the thread starts; `close()`/finalize on a pending Socket only invalidates its copy of the handle instead of closing it. After `connect()` returns, the thread checks whether the read end of its socketpair is still open (it already owns the write end, and the main side closes the read end when the event is dropped). If the owner is gone, the thread closes the descriptor itself. No new synchronization: the socketpair already carries the signal.
    - **Drive a nonblocking `connect()` from the event loop** and only put `getaddrinfo()` on a thread. Cleaner, but a larger change to the event engine.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.38-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Deucе@1:103/705 to GitLab note in main/sbbs on Sun Oct 25 15:24:16 2026
    https://gitlab.synchro.net/main/sbbs/-/work_items/1299#note_10712

    This was actually broken by 118984e9af (2024-01-19) when it changed the int-sized `BOOL` to one-byte `bool`.
    --- SBBSecho 3.38-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)