UBA on macOS leaves port 7001 occupied after UbaAgent exits

Summary

UBA on macOS can leave TCP port 7001 occupied after UbaAgent exits, causing later UbaAgent instances to fail with exit code 255 because they cannot bind the listen port.

What Type of Bug are you experiencing?

Foundation (C++ Tools, Profiling, & Pipeline)

Steps to Reproduce

  1. Use Horde remote execution with Unreal Build Accelerator on a macOS worker.
  2. Launch UbaAgent through Horde with -Listen=7001.
  3. Run a build that spawns clang++ compiler child processes through UBA.
  4. Let UbaAgent exit while compiler child processes may still be alive.
  5. Start another UBA remote worker on the same macOS machine.

Expected Result

Compiler child processes should not inherit UbaAgent’s listening socket. After UbaAgent exits, port 7001 should be released, and a later UbaAgent instance should be able to bind and listen on port 7001 normally.

Observed Result

UbaAgent exits with code 255. Agent-side logs show:

UbaClient (…) - bind 0.0.0.0:7001 failed because address/port is in use.
Failed to get start listening on port 7001

After UbaAgent exits, lsof still shows clang++ child processes listening on TCP port 7001. These clang++ processes are orphaned with PPID 1, which suggests they inherited UbaAgent’s listening socket.

Example:

clang++ (…) TCP *:7001 (LISTEN)

Additional source-code observation:

In UE 5.8 source, UbaProcess.cpp appears to contain a fix-intent for macOS. spawnFlags includes POSIX_SPAWN_CLOEXEC_DEFAULT under PLATFORM_MAC, but the actual posix_spawnattr_setflags() call still passes POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGMASK directly instead of spawnFlags.

As a result, POSIX_SPAWN_CLOEXEC_DEFAULT is added to spawnFlags but never actually applied on macOS. This seems related to the observed issue where clang++ child processes inherit UbaAgent’s listening socket and keep port 7001 open after UbaAgent exits.

Affects Versions

5.8

Platform(s)

Mac

Upload an image