DeferTask/DeferImmediateTask return bool (nothrow OOM); wait_que and
sql_que free the BQUE and refund quota/waitcost when enqueue fails.
db_write_object reports stream status via ferror; db_write returns -1
on I/O failure after header/object/end/flush checks, and dump/dbconvert
callers refuse to publish a truncated flatfile.
Maintainer direction: prefer int64_t over long/int for parsed softcode
and attribute integers so LLP64 and LP64 behave the same.
This first slice covers the leftovers called out on the issue:
- quota: store/show/set paths (avoids @quota/all 2^32 writing 0)
- A_CHARGES in set/levels/predicates (RUNOUT vs wrap-to-positive)
- semaphore counts and @ps/queue kick/warp parsing
- IDLETIMEOUT attribute seconds
Bounded API edges (RunTasks(int), optional int *pnum) clamp after the
full-width parse. pot: quota notify formats use %lld.
Three player-visible notify sites still computed English morphology in C
and passed it as %s — the #1622 shape:
%d queue entr%s removed. y / ies (cque, two sites)
%d orphaned attribute name%s purged. "" / s (@dbclean)
MN_(singular, plural, n) sends the count to the catalogue. Regenerates
the pot and fills xx.po; ko.po leaves the new entries untranslated.
Replace ~900 typographic \xE2\x80\x.. escapes (curly quotes, en dashes)
and a few \xE2\x80\230 octal workarounds with real UTF-8 in message
strings under mux/modules and mux/src. Leave stringutil and convert
charset mapping tables as explicit byte sequences.
Completes the sweep the issue called for. mux_atol returns long, which
is 32-bit on LLP64, so every caller silently truncated on Windows. Two
of those were real defects (the truthiness family and cf_size, fixed in
the preceding commits); the rest were latent, waiting for a value large
enough to matter.
Rather than audit 290 sites for whether each can reach 2^31 today, use
the 64-bit parser everywhere and remove the class. A dbref cannot
overflow now, but nothing stops a later caller passing that same site a
timestamp or a byte count.
Pure 1:1 substitution: 285 lines changed, and every removed line
contained mux_atol while every added line contains mux_atoi64. No
control flow, no types, no behaviour beyond the wider parse.
This is a NO-OP on LP64 -- long is already 64-bit on Linux and macOS, so
the generated code there is unchanged. It only widens the parse on
Windows. Narrowing destinations are unaffected either way: `int x =
mux_atoi64(s)` truncates exactly as `int x = mux_atol(s)` did, on both
models.
Left alone: mux_atol itself in mathutil, its declaration, and three
comments that name it. Callers that genuinely want 32-bit semantics can
still ask for them; none appear to.
Verified on Windows: full solution builds clean with no new warnings,
smoke is 1418 passed / 16 failed / 0 crashes / 306 of 306 dispatched --
identical to before the sweep, with the same 16 build-configuration
failures (exp3 module not loaded, hmac/digest behind UNIX_DIGEST).
Spot checks after the change: the boolean family returns 1 for multiples
of 2^32, cf_size round-trips 3000000000 and still reads -1 as unlimited,
and arithmetic, string and list functions are unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restart (#1039–#1043): zero process-local DESC fields after load,
restore peer via getpeername, strip non-survivable TLS/WS flags,
drop TLS and WebSocket before exec, tear down adopt failures with
shutdownsock, abort partial restart loads cleanly.
DB (#1044–#1047): cache_flush_writes returns success only after
Commit; leave dirty queue on failure; atr_head union SQLite with
pending cache/queue; set mudstate.bStandAlone in DbConvert; flush
attr queue before import Commit.
Queue (#1048–#1052): setup_que refunds on OOM; sql_que frees BQUE
on Query fail and inits waittime; do_wait rolls back semaphore if
wait_que fails; include nest depth limit 50; CPU halt_que uses
Owner+object for machines.
JIT (#1053–#1057): full 64-bit rv_load_i64; setq/r single-char
RegisterSet; decline long CARGS; accumulate inline u() watermarks;
bounded guest_strnlen on ECALL paths.
Conf/convert (#1058–#1061): @enable/@disable sync g_dc; live
driver knobs for output/retry/max_players/timeouts/quota; safe
heap encode for t5x/t6h/r7h attributes.
Queue review (docs/survey-queue.md): the design holds up — two heaps
with a monotone-ticket tie-break making FIFO-within-cycle a hard
guarantee, priorities as a dequeue floor, and the scheduler deadline
feeding the network poll timeout so an idle server does nothing.
Context shipped per BQUE is reference-based everywhere semantics
permit: the command+env snapshot is ONE exact-sized allocation,
%q registers are refcounted (RegAddRef), the named-register map is
null-when-empty and shares refcounted values, and dispatch is pure
move semantics. Exactly one copy problem existed:
iter_token/switch_token (the ##/#$ context of queued @dolist/@switch)
each held a full 32KB pool LBUF per entry from enqueue to dispatch,
for strings that are typically a few bytes. Measured before/after
with @list allocations at 5,000 queued entries: 5,002 -> 2 Lbufs in
use; max RSS of a 20k-entry @dolist: 244MB -> 21MB. Fix is
StringClone (exact-size) at the single allocation site, MEMFREE at
the four free sites; ##/#$ content is byte-identical through queued
dispatch.
Also recorded in the survey, no action: safer_iter gates iter_token
shipping entirely; muxscript's EOF drain is paced and time-capped
(~15s) so queue THROUGHPUT needs a live-netmux stress harness (the
natural next hardening step); setup_que's static scratch locals are
single-threaded-only.
Tests: smoke 1319/1319 both toggles; oracle 9/9; jit_diff 400/0
LOGIC; ##/#$ queued-dispatch probes byte-identical.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When a command exceeds max_cmdsecs, the runaway guard abbreviates it
(via the polled alarm flag) and then HALTs both the enactor and the
executor. The HALT fires after process_command has already returned,
so it never protects the current timeslice -- it only quarantines
future work. That is the right response for a machine object, whose
future work is more of the same runaway loop, but wrong for a wizard
player, whose future work is the next typed command -- often the one
that fixes the problem. Classic casualty: an admin running @dbclean
as God left #1 HALTED, with its queue flushed and wait_que refusing
new entries, until the flag was cleared by hand.
Both guard sites now skip the HALT flag and the halt_que flush,
per-object, when the target is a wizard player (God included): the
queue-side guard in Task_RunQueueEntry and the interactive guard in
the network command path. Machine objects -- even wizard-owned ones --
and mortal players quarantine exactly as before, and abbreviation
itself is untouched for everyone. A LOG_PROBLEMS line records each
suppressed HALT, closing the visibility gap where the default
rpt_cmdsecs (120s) exceeds max_cmdsecs (60s).
This also fixes a latent no-op: the executor-side s_Flags call used
point->executor, which the runner sets to NOTHING before executing,
so it stamped the db[-1] sentinel slot (and issued a junk SQLite
UpdateFlags(-1)) instead of the real executor. The enactor line was
what actually darked #1. The guard now uses the correct local.
No smoke case: exercising the guard needs a multi-second burn against
a lowered lag_limit, which is timing-dependent and wrong for the
harness. Verified by direct muxscript probes across all three lanes
(wizard player exempt and live; machine object HALTed; mortal player
HALTed) plus a clean full smoke run.
Closes#896.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Correctness sweep of the command-side verb handlers. Five confirmed bugs
plus a help-text correction, verified by dual-lens review and code reading
(the read-only smoke harness can't exercise these verbs directly):
- @clone/cost on an exit bypassed the "must control current location"
check (it lived only on the non-/cost path), letting a builder splice a
cloned exit into a room they do not control. (#855)
- The @mark/@mark_all/@apply_marked DB-cleaning refusal cited @unmark_all,
which does not exist (produces "Huh?"); corrected to @mark_all/clear.
(#856)
- @ps <object> reported nothing for a controlled object owned by another
player; do_ps was missing the non-player-target else clause that the
sibling @halt has (clear the owner filter). (#857)
- whisper "<quoted name>" skipped the locality/connected gate the unquoted
form applies, giving a success confirmation plus a delivery error and
polluting A_LASTWHISPER; also fixed an adjacent quoted-name continue that
did not advance the parser. (#858)
- @flag/remove of an unknown/empty flag name was silent; now reports an
error like the other flag-name failure paths. (#859)
- report help said 8-hour segments but the code uses 4 (deliberately, per
4a845139f); corrected the help. (#860)
Also restores the "## JIT / DBT Engine" CHANGES heading dropped during an
earlier 2.14.0.8 edit. Build clean, all 1264 smoke tests still pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two follow-ups to the @dolist/now rewrite (37e18bef5):
- New /break switch: an @break inside the body still stops the loop,
but with /break it also propagates to the enclosing command list,
aborting the commands after the @dolist. This restores the one
ability the containment change removed (using a break inside the
loop to abort the rest of a $-command), with sane loop-stop
semantics, and mirrors @include (propagate by default, /nobreak to
contain). Without /now the switch is inert.
- ;| pipe segments now work in inline command lists. The queued
runner has always special-cased '|' after ';' to capture the
previous command's output as %|; the inline loops in @dolist/now
and @include treated such a segment as a literal command starting
with '|' ("Huh?"). The splitting/pipe/break loop is factored into
process_command_list_inline() in cque.cpp, shared by both callers
and kept next to its queued twin so the semantics cannot drift.
The inline list is its own pipe domain (save/restore of the
enclosing pipe context), matching how each queued entry starts with
a clean pipe state -- an inline list running inside a piped segment
cannot corrupt the outer capture.
help @dolist documents /break and the ;| support.
Verified: default containment, /break propagation, and /break with no
inner break all behave as specified; pipes carry %| through inline
dolist and include bodies; smoke 1115/0/0 with three new test cases;
2x200 jit_diff clean.
Closes#788.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Use the new LBuf_Adopt() macro to take RAII ownership of caller-owned
pool buffers returned by atr_get, atr_pget, and atr_get_LEN. This
eliminates ~82 explicit free_lbuf calls and automatically covers
early-return paths that previously required careful manual placement
of the free.
Heaviest conversions: player.cpp (13), comsys.cpp (14), command.cpp (9).
Complex interleaved patterns (did_it charge/runout swaps, PureName
reassignment, process_cmdent loops) left manual for now.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Second wave: convert manual alloc/free pairs in cque (1), db_rw (4),
conf (5), db (2), engine_com (6), help (7), levels (2), predicates (5),
player (7), funmath (8). Eliminates ~80 explicit free_lbuf calls
including multi-exit error paths in getboolexp1 (5 frees → 0),
get_list, AnnounceConnect/Disconnect, and the eight NOEVAL function
variants (cand/cor/firstof/allof and bool variants).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>