Commit graph

13 commits

Author SHA1 Message Date
Stephen Dennis
5f43951f46 fix(tables): pot for C* labels; no %* width on mux_sprintf
Regenerate pot/xx/ko after Phase 4 C* (drop blob headers; add per-label
msgids).  Row right-just must use RightJustifyNumber — mux_vsnprintf does
not implement %* width (#1429), so the filed %*d/%*lld path would echo
literally and drop the rest of each stats line.
2026-07-28 17:34:14 +00:00
Stephen Dennis
5cee6cb721 feat(tables): staff list layouts via mux_table (#1667 Phase 4 C*) 2026-07-28 11:31:23 -06:00
Stephen Dennis
c5dbbb71d8 nls: mark libmux alloc buffer-stats notify prose with M_ (#1419)
Two constant alloc_notify chrome lines in alloc.cpp (corruption abort
banner and buffer-stats header). Leave tprintf formats as T().
Regenerate pot/xx without fuzzy entries.
2026-07-27 12:58:59 +00:00
Stephen Dennis
21f3496319 docs: cite #1290 for B1/H1 residual fix 2026-07-25 20:10:18 -06:00
Stephen Dennis
c928184379 fix(ganl/alloc/alarm): freelist, alarm ms, dual-stack warn (#1289)
Pass B1 + H1 residual — bugs 2.13-era code often just lived with.

H1: pool freelist corruption used to clear the *entire* free stack
(leaking every still-valid free buffer). Drop only the bad entry.

H1: mux_alarm set/sleep used long ReturnMilliseconds() (Win32 truncate
for long deltas). Use int64_t from 100ns ticks and clamp.

B1: kqueue/IOCP/wselect now warn when IPV6_V6ONLY dual-stack fails,
matching epoll/select (#739 family).

Closes #1289.
2026-07-25 20:10:03 -06:00
Stephen Dennis
24f731e96c fix: review follow-ups for JIT toggle-on and defense suggestions
JIT: document dispatch-only alarm polling; emit #-1 CPU LIMITED on
wall-clock abort (shared_heap/run_compiled/run_cached_program); static
invocation-count watermark (bail_invk) analogous to #1002 depth; note
bail_longreg as legacy after the longbit diamond.

Defense: site_connection_count and forbid_site use same_source_key /
nospam_connect; graduated list text distinguishes exemption vs restrict
thresholds; pool budget policy matches permanent soft-ceiling reality;
login-throttle indent and input_limit hysteresis edge fixed.
2026-07-23 19:49:49 -06:00
Stephen Dennis
47582605d9 fix(net): close four front-door defense review bugs
Pre-auth cap now keys on same_source_key (IPv4 host / IPv6 /64) so a
single /64 cannot fan out past max_preauth_sitecons. connect_rate_charge
runs only after pre-auth acceptance, matching the "charge accepted only"
invariant. Equal-subnet site inserts adopt ulThreshold so graduated
thresholds can be reconfigured without reset_site. Defense knobs use
cf_live_driver_int + a libmux driver-config sync callback so @admin
updates g_dc without a restart.
2026-07-23 19:43:29 -06:00
Stephen Dennis
c44c908d74 feat(alloc): pool memory footprint budget (defense-in-depth, off by default)
Backstop for the pool_alloc -> fatal OutOfMemory cliff
(docs/survey-resource-defenses.md gap #3).  pool_alloc/pool_alloc_lbuf
take memory from the system only on the slow path (freelist empty) and
never return it, so the process's pool footprint is its PEAK CONCURRENT
buffer count.  New pool_memory_limit config (bytes; K/M/G suffixes;
0=unlimited) caps that footprint: on the slow path, crossing it trips
the same cooperative per-command abort the wall-clock alarm uses
(alarm_clock.alarmed, reachable from alloc.cpp — both are libmux) so a
runaway command unwinds and frees its buffers back to the freelist
instead of the server aborting on OutOfMemory.  Composes with the JIT
wall-clock alarm (same flag).  cf_pool_limit pushes the value to the
libmux global on load and @readcache reload.

Off by default, and honestly so: measurement showed the cliff is HARD
TO REACH, which is the point — the interpreter's alloc-and-free
discipline, bounded nesting (func_nest_lim/nStackLimit), and freelist
reuse keep peak pool footprint tiny (a short session didn't cross even
256KB).  And no non-zero default is safe across deployments (a 256MB
VPS vs a 32GB host want different ceilings), so the admin sizes it.
Note: the nested-iter OS-OOM crash seen while building the JIT alarm is
a DIFFERENT path (JIT arena/guest growth, bounded by max_dispatch=10M
by default), not this one.

Verified default-off is a true no-op: smoke 1319/1319, oracle 9/9,
jit_diff 400/0, stress 8/8; the trip path is wired (server survives +
stays responsive when the budget is crossed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 00:08:59 -06:00
Stephen Dennis
369f92495c Remove ISOUTOFMEMORY macro; add per-site OOM recovery and fix g_dump_child_pid
Eliminate the ISOUTOFMEMORY macro that unconditionally aborted on allocation
failure. Each of the 23 call sites now handles OOM appropriately:
- Fatal sites (buffer pools, db array, anum table): mux_assert or OutOfMemory
- Recoverable sites (queue, mail, commands, guests, vattrs, config, restart,
  forward lists): log the failure and return gracefully

Also fix g_dump_child_pid portability: volatile pid_t -> volatile sig_atomic_t
with explicit casts in ganl_adapter.cpp.

Close integer overflow issue as false alarm (getstring_noalloc uses a bounded
static buffer, so nBuffer+1 cannot wrap).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:31:20 -06:00
Stephen Dennis
7ec8d738ea Unify pool + refcount layers: shared_ptr replaces manual lbuf_ref/reg_ref
Replace the two-level manual reference counting system (lbuf_ref + reg_ref
with BufAddRef/BufRelease/RegAddRef/RegRelease) with std::shared_ptr:

- RegBuffer: new shared buffer struct, managed by shared_ptr — replaces
  lbuf_ref which was a manual refcount wrapper around a pool-allocated lbuf
- reg_ref: now contains shared_ptr<RegBuffer> instead of lbuf_ref pointer;
  allocated with new/delete instead of POOL_REGREF
- RegAssign: uses make_shared<RegBuffer> instead of alloc_lbuf + alloc_lbufref;
  packing optimization preserved (multiple values in one RegBuffer)
- RegRelease: simplified to decrement + delete (shared_ptr destructor
  handles buffer lifecycle automatically)
- BufAddRef/BufRelease: eliminated entirely — shared_ptr copy/destroy
  handles all buffer reference counting
- POOL_LBUFREF, POOL_REGREF: eliminated (NUM_POOLS 9 → 7)
- JIT arena: uses shared_ptr<RegBuffer> instead of lbuf_ref

The pool allocator (POOL_LBUF) remains for the 323 temporary-buffer call
sites — that's the "blindingly fast" layer. The refcount layer above it
is now automatic via shared_ptr.

Net: −103 deleted, +51 added across 6 files. All 551 smoke tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:27:48 -06:00
Stephen Dennis
47af5f9dc3 Pool allocator: replace intrusive linked lists with std::vector
Modernize the buffer pool allocator internals while keeping the
public API (alloc.h macros/functions) completely unchanged:

- POOLHDR: removed next/nxtfree intrusive list pointers (−16 bytes/buffer)
- POOL: chain_head/free_head → vector<char*> all_buffers/free_stack
- Alloc: pop_back from free_stack (O(1)), or new char[] + push to all_buffers
- Free: validate header/footer, push_back to free_stack (O(1))
- pool_vfy: iterate all_buffers vector — no longer silently truncates
  the chain on corruption (the old "clearing freelist" behavior leaked
  memory and was essentially untested defensive code)
- pool_reset: build unordered_set of free pointers, remove_if + delete[]
- pool_trace/list_bufstats: iterate all_buffers vector

Zero changes to alloc.h or any caller. All 551 smoke tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:08:37 -06:00
Stephen Dennis
68acbd2eea Rework Windows build for component-based directory layout
Adapt all vcxproj files and solution to the new directory structure
(src/ driver, lib/ shared library, modules/engine/ game logic,
modules/{comsys,mail,exp3,sqlproxy,sqlslave}/ loadable modules).

Key changes:
- libmux.dll exports utility symbols via LIBMUX_API macro
  (__declspec(dllexport) when BUILDING_LIBMUX, dllimport otherwise)
- LIBMUX_API added to all shared headers: stringutil.h, timeutil.h,
  mathutil.h, utf8tables.h, svdhash.h, svdrand.h, sha1.h, alloc.h,
  dbutil.h, core.h
- Per-file PreprocessorDefinitions in libmux.vcxproj inherit from
  project-level via %(PreprocessorDefinitions)
- Driver factory declarations (CDriverControlFactory,
  CConnectionManagerFactory) guarded with BUILDING_DRIVER
- PCG-XSH-RR-64/32 (pcg32) for Windows (no __int128 needed);
  Unix PCG-XSL-RR-128/64 unchanged
- MSVC portability fixes: _strnicmp, _BitScanForward64, (std::min)(),
  HAVE_WORKING_FORK guards, WINDOWS_FILES/UNIX_FILES ModuleAdd paths
- Remove stubslave.cpp and slave.cpp from netmux.vcxproj (separate
  processes)
- Fix sqlproxy/sqlslave vcxproj relative paths for new layout
- Add ws2_32.lib to engine.vcxproj for socket functions
- Add strcasecmp/strtok_r/strndup compat shims for comsys/mail

Builds successfully: libmux.dll, engine.dll, netmux.exe, exp3.dll,
sqlproxy.dll, sqlslave.dll. Comsys/mail blocked on sqlite3 linking
architecture (need COM-mediated or independent sqlite3 linkage).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:38:57 -06:00
Stephen Dennis
4ff1398de1 Restructure mux/ directory: component-based layout with proper build root
Move from flat mux/src/ layout to clean component hierarchy:
- mux/ is now the autoconf/automake build root (configure.ac lives here)
- mux/include/ — shared headers used by multiple components
- mux/lib/ — libmux.so (core utilities, no game state)
- mux/src/ — netmux driver only (thin networking shell)
- mux/modules/engine/ — engine.so (game logic)
- mux/modules/{comsys,mail,exp3,sqlproxy,sqlslave}/ — external modules
- mux/ganl/ — GANL networking library
- mux/sqlite/ — SQLite amalgamation (builds libsqlite3.a)
- mux/announce/ — announce tool (was mux/src/tools/)

Build changes:
- SUBDIRS ordering: ganl sqlite lib src modules announce
- libmux.so gets -Wl,-soname,libmux.so; netmux links via -L -lmux
- engine.so links libsqlite3.a and libmux.so with -Wl,--no-undefined
- RPATH uses $ORIGIN for portable .so resolution
- Install hooks use absolute paths for game/bin symlinks

Bug fixes:
- engine.so mux_Register() now passes nullptr to mux_RegisterClassObjects
  (matches all other modules; libmux already has the factory via dlsym)
- DbConvert() now calls pcache_init() before db_write, fixing a latent
  crash (free(): invalid pointer) when exporting from SQLite databases

411/411 smoke tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:38:37 -06:00
Renamed from mux/src/alloc.cpp (Browse further)