Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions atch.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ struct packet
struct winsize ws;
} u;
};
_Static_assert(sizeof(((struct packet *)0)->u.buf) <= 255,
"packet buffer must fit in uint8_t length");

/*
** The master sends a simple stream of text to the attaching clients, without
Expand Down
2 changes: 2 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#ifndef SCROLLBACK_SIZE
#define SCROLLBACK_SIZE (128 * 1024)
#endif
_Static_assert(SCROLLBACK_SIZE > 0 && (SCROLLBACK_SIZE & (SCROLLBACK_SIZE - 1)) == 0,
"SCROLLBACK_SIZE must be a positive power of two");

/* Maximum size of the on-disk session log; older bytes are trimmed on open */
#ifndef LOG_MAX_SIZE
Expand Down
21 changes: 14 additions & 7 deletions master.c
Original file line number Diff line number Diff line change
Expand Up @@ -802,29 +802,29 @@ int
openpty(int *amaster, int *aslave, char *name, struct termios *termp,
struct winsize *winp)
{
int master, slave;
int master = -1, slave = -1;
char *buf;

master = open("/dev/ptmx", O_RDWR);
if (master < 0)
return -1;
if (grantpt(master) < 0)
return -1;
goto fail;
if (unlockpt(master) < 0)
return -1;
goto fail;
buf = ptsname(master);
if (!buf)
return -1;
goto fail;

slave = open(buf, O_RDWR | O_NOCTTY);
if (slave < 0)
return -1;
goto fail;

#ifdef I_PUSH
if (ioctl(slave, I_PUSH, "ptem") < 0)
return -1;
goto fail;
if (ioctl(slave, I_PUSH, "ldterm") < 0)
return -1;
goto fail;
#endif

*amaster = master;
Expand All @@ -836,6 +836,13 @@ openpty(int *amaster, int *aslave, char *name, struct termios *termp,
if (winp)
ioctl(slave, TIOCSWINSZ, winp);
return 0;

fail:
if (master >= 0)
close(master);
if (slave >= 0)
close(slave);
return -1;
}

pid_t
Expand Down
28 changes: 28 additions & 0 deletions tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,34 @@ assert_contains "no args: shows Usage:" "Usage:" "$out"
run "$ATCH" --help
assert_contains "help: shows tail command" "tail" "$out"

# ── 23. fd leak: rapid session cycling under low fd limit ──────────────────
# openpty fallback leaks fds on error paths. Under a tight fd limit,
# leaked fds accumulate and eventually prevent new sessions from starting.

(
ulimit -n 64 2>/dev/null || true
LEAK_FAIL=0
i=0
while [ $i -lt 50 ]; do
out=$("$ATCH" start "leak-$i" sleep 999 2>&1)
lrc=$?
if [ "$lrc" -ne 0 ]; then
LEAK_FAIL=1
break
fi
"$ATCH" kill "leak-$i" >/dev/null 2>&1
sleep 0.02
i=$((i + 1))
done
i=0; while [ $i -lt 50 ]; do "$ATCH" kill "leak-$i" >/dev/null 2>&1; i=$((i + 1)); done
exit $LEAK_FAIL
)
if [ $? -eq 0 ]; then
ok "fd-leak: 50 create/destroy cycles under ulimit -n 64"
else
fail "fd-leak: session failed under low fd limit (possible fd leak)" "50 cycles" "failed early"
fi

# ── summary ──────────────────────────────────────────────────────────────────

printf "\n1..%d\n" "$T"
Expand Down