• src/xpdev/genwrap.c

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thursday, September 24, 2026 21:22:49
    https://gitlab.synchro.net/main/sbbs/-/commit/18ddb2e73bed00cece5f829a
    Modified Files:
    src/xpdev/genwrap.c
    Log Message:
    xp_popen(): don't reuse the output buffer after a failed realloc

    On Windows, xp_popen() grows its output buffer with realloc_or_free(),
    which frees the old buffer when realloc() fails. The failure branch broke
    out of the read loop without clearing the pointer, so the line-splitting
    loop that follows read freed memory and the free() at the end released
    it a second time.

    The pointer is now cleared, leaving the same state as a command that
    produced no output. The POSIX side reads straight into the string list
    and never reallocates, so it is unaffected.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Tuesday, November 10, 2026 20:49:05
    https://gitlab.synchro.net/main/sbbs/-/commit/d98f0eaeb863ee3093720750
    Modified Files:
    src/xpdev/genwrap.c
    Log Message:
    xp_popen(), xp_pipe_open(): the child inherits only its standard handles

    On Windows, both ran their command with plain handle inheritance, which
    gives the child every inheritable handle open anywhere in the process at
    that moment, including each file another thread has fopen()ed. The child
    then holds those files open until it exits, so the owning thread's
    remove() after fclose() fails with a sharing violation.

    Symptom: the FTP server packing a QWK packet at the same moment another
    server thread ran a command (most likely the web server's "lsar", via system.popen() in filecontents_lib.js, for an archive view):

    !ERROR 13 (Permission denied) (WinError 32) in pack_qwk.cpp line 660
    (sbbs_t::pack_qwk) removing ".../PERSONAL.NDX"

    Name the standard handles in a PROC_THREAD_ATTRIBUTE_HANDLE_LIST so that nothing else is inherited. Where that isn't available (pre-Vista headers, Borland) or is refused, the command runs with plain inheritance as before.

    xp_system() is unchanged: services.cpp relies on it to pass a native
    service its socket.

    Introduced with xp_popen() in 5de72e0995 (2026-09-20) and with
    xp_pipe_open() in 17981f079f (2026-09-20).

    Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net