diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-30 13:30:28 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-30 13:30:28 +0300 |
| commit | 4f8e26db8f645e8d50a9a9b31e5935c6967de55d (patch) | |
| tree | c6985cc28c9a59e2ecc4f6b37850f1cc0b82f60f /yhttpd/src/thrd/thro.cpp | |
| parent | a0a881fb8ddd48a51292af1af85708b4c3593804 (diff) | |
Implement the timer/garbage-collector (was disabled/unfinished)
wrap.cpp had '//TIMR->run(); // TODO' but timr::run() was never defined
(wouldn't compile if uncommented), and the intended timer thread
(timr::start) ran in a pthread and would race with the single-threaded
libevent main loop (no locking on the shared room/user maps). Net effect:
idle timeouts never ran, ghost users lingered in the online list forever
after disconnect, and message timestamps were always 00:00:00 (s_time
was only updated by the never-run timer).
Also, even single-threaded, check_timeout was unsafe: user::set_online(false)
does p_room->del_elem during hashmap::run_func's live begin/end iteration
-> iterator invalidation/crash.
Fix:
- hashmap::run_func (both overloads): snapshot the values into a vector
before invoking the callback, so callbacks may safely delete from the map
during iteration.
- timr::tick(): single-threaded 1s-cadence tick (called from the libevent
main loop) that updates s_time/s_uptime every tick, and at the top of
each minute runs check_timeout (idle timeout + auto-away), posts a PING
keepalive to all streams, every 10 min cleans the ip cache, hourly runs
garbage collection.
- main.cpp: register a periodic libevent timer (1s, EV_PERSIST) calling
timr::tick() in the event loop - no new thread.
B1 use-after-free (found by independent review, fixed): when an idle user is
reaped it moves to garbage while its long-lived stream context is still
alive; the hourly remove_garbage would delete the user, leaving the
context's p_user dangling (UAF on later disconnect). Fixed by:
- gcol::remove_garbage now keeps garbage users whose stream is still open
(get_stream_fd() >= 0) until the stream closes, deleting only closed-stream
users (collected via a new collect_users_ helper since the hash_map base
is privately inherited and not directly iterable).
- handle_stream_read now reaps the disconnecting user from its room
(set_online(false), a no-op if already idle-reaped) so a clean disconnect
immediately clears the online list instead of lingering until idle-reap.
Also removed the debug 'cout << SETTING OFFLINE' spam in set_online.
Verified: timestamps now real (e.g. 10:29:20 vs old 00:00:00); idle users
reaped at the next top-of-minute tick (no crash); clean disconnect removes
the user from the online list; idle-reaped-then-stream-closed does not UAF
(0 restarts); normal multi-user chat still works. Two independent
fresh-context reviews: APPROVE-WITH-NITS; the B1 UAF and disconnect-reap
findings were addressed; the pre-existing flush_stream hard-error UAF edge
was filed as a separate follow-up.
Diffstat (limited to 'yhttpd/src/thrd/thro.cpp')
0 files changed, 0 insertions, 0 deletions
