CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
ProcessMemoryConcFuzz.cpp File Reference

Phase 2: CONCURRENT + CROSS-PROCESS fuzz of the ProcessMemory ring. More...

#include "ProcessMemory.h"
#include "MemoryManager.h"
#include "ThreadManager.h"
#include "UnitTestFramework.h"
#include <map>
#include <vector>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
Include dependency graph for ProcessMemoryConcFuzz.cpp:

Go to the source code of this file.

Classes

struct  cmlabs::ConcRand
 Deterministic xorshift64* — same as Phase 1 so seeds behave comparably. More...
struct  cmlabs::ConcOracle
struct  cmlabs::ConcCtx

Namespaces

namespace  cmlabs

Functions

static uint32 cmlabs::ConcEnvU32 (const char *name, uint32 def)
static bool cmlabs::ConcEnvFlag (const char *name)
static uint32 cmlabs::ConcChecksum (const char *p, uint32 len)
 FNV-1a — identical to Phase 1's so payload checks are comparable.
static void cmlabs::ConcFillPayload (char *buf, uint32 len, uint32 serial)
static DataMessagecmlabs::ConcMakeMsg (uint32 serial, uint32 len, uint32 &sumOut)
 Build one message carrying its own serial + payload, so a reader can re-derive what it SHOULD have received and prove corruption rather than infer it.
static THREAD_RET THREAD_FUNCTION_CALL cmlabs::ConcWriter (THREAD_ARG arg)
static THREAD_RET THREAD_FUNCTION_CALL cmlabs::ConcReader (THREAD_ARG arg)
static THREAD_RET THREAD_FUNCTION_CALL cmlabs::ConcResizer (THREAD_ARG arg)
 Tier C helper: grow the segment repeatedly while readers are live, so resize() unmaps and repoints header underneath them.
static bool cmlabs::ConcCrossProcessChild ()
 Tier B child half: open() the existing segment and drain, appending every serial read.
static bool cmlabs::ConcRunThreaded (const char *label, uint32 readers, uint32 msgs, uint32 payload, uint32 burst, uint64 seed, bool resizeStress, bool blockingReads, bool dupSelftest, bool lostSelftest)
 Run one in-process tier.
static bool cmlabs::ConcRunCrossProcess (uint32 msgs, uint32 payload, uint64 seed)
 Tier B: two OS processes on one segment.

Detailed Description

Phase 2: CONCURRENT + CROSS-PROCESS fuzz of the ProcessMemory ring.

Phase 1 (ProcessMemoryFuzz.cpp) is deliberately single-process/single-threaded so a failing seed replays byte-for-byte. It is green over 12.8M+ ops on Linux AND macOS, which clears the ring's integer arithmetic — and clears nothing else.

This file covers the dimension Phase 1 excludes. It was written to hunt the BakeLive Anomaly (

See also
BakeLiveBug.md in the psyclone2 root) and ALL FOUR TIERS CAME BACK CLEAN, which is why the ring is now considered exonerated rather than merely un-convicted. It is kept as a permanent regression test: this queue carries every high-volume path in the system, so the coverage is worth having regardless of that investigation.

Tier A MULTIPLE READER THREADS on ONE queue. PsySpace::threadPoolDispatch runs a thread POOL, all calling waitForMsgQ on the same queue. waitForQ gates on if (qHeader->count), reads at startPos, then advances it — so if two readers could straddle that gate, one message would be returned TWICE while startPos advanced ONCE. Result: clean, up to 16 concurrent readers. Tier A' BURST-DRAIN: fill to ~64 entries at the real 2314-byte message size, then let the readers drain the lot at once. This reproduces the shape of the failing case rather than a random op mix. Result: clean, to 100k messages. Tier B TWO OS PROCESSES on one segment: the real contended cross-process mutex and two independent header mappings. Result: clean. Tier C resize() UNDER A CONCURRENT READER. resize() does not grow in place: it creates a new segment, memcpy's, unmaps the old one and repoints header, and waitForQ's fast path (queue non-empty on entry) skips the re-fetch its wait path performs. Result: clean. Tier D THE BLOCKING PATH. Phase 1 only reads when its model is non-empty, so waitForQ never waits on the named semaphore, never releases the mutex mid-call and never re-enters. Result: clean.

⚠️ ORACLE STRENGTH IS LOWER THAN PHASE 1, ON PURPOSE. With concurrent readers there is no total order to check against, so this cannot assert sequence. It asserts SET equality: every serial written is read exactly once, payload intact. A green result here is therefore weaker evidence than a green Phase 1 — say so when reporting it.

Every checker has a positive control that MUST fail (PSY_CONC_*SELFTEST), following the Phase 1 convention. That convention matters: the BakeLive investigation lost far more time to FOURTEEN separate instrument defects than to the bug itself, and the ones caught early were caught by controls. Run the controls before trusting a green result.

Env: PSY_CONC_TIER=A|A2|B|C|D|ALL which tier (default ALL; A2 is the burst-drain tier) PSY_CONC_READERS=<n> reader threads for tier A/C (default 4) PSY_CONC_MSGS=<n> messages per run (default 20000) PSY_CONC_BURST=<n> tier A' burst size; 0 = steady mix (default 64) PSY_CONC_PAYLOAD=<n> payload bytes, 0 = mixed (default 2280 ~ the real 2314-byte wire size) PSY_CONC_SEED=<n> RNG seed (default 0x2000) PSY_CONC_DUPSELFTEST=1 inject a duplicate -> MUST fail PSY_CONC_LOSTSELFTEST=1 inject a loss -> MUST fail PSY_CONC_CHILD=<mode> INTERNAL: re-exec entry point for tier B

Definition in file ProcessMemoryConcFuzz.cpp.