Each MOAD now has a synthetic defective specimen and fixed specimen proven from first principles across three test tiers: Unit (tests/unit/Moad000X*.java): - Correctness: defective and fixed produce identical functional output - Defect behavior: defective specimen exhibits the defect (measurable) - Fix behavior: fixed specimen eliminates the defect Integration (tests/integration/AllMoadsIntegrationTest.java): - All 9 MOADs proven at medium scale (N=500-2000) - MOAD-0001: O(N^2) vs O(N) list scan at N=1000 - MOAD-0002: 500 sessions trample each other (defective) vs coexist (fixed) - MOAD-0003: 250 anonymous requests leak auth identity (defective) vs zero (fixed) - MOAD-0004: 3000 credential exposures across 1000 requests (defective) vs zero (fixed) - MOAD-0005: 500 computes for 500 concurrent misses vs exactly 1 - MOAD-0006: all 500 passwords extractable from DB (defective) vs unextractable (fixed) - MOAD-0007: N=2000 spatial objects, defective visits all 2000 vs O(log N + k) - MOAD-0009: 990 wasted firings for 1000 ticks / 10 events vs zero waste - MOAD-0011: 10240 NFA steps vs 13 steps on N=12 adversarial input (788x) Functional (tests/functional/AllMoadsFunctionalTest.java): - MOAD-0005: real-thread contention proves herd (defective >1 compute, fixed exactly 1) - MOAD-0007: N=50000 spatial objects, 50M defective probes vs 516K fixed (97x speedup) - MOAD-0009: 10000 ticks / 10 events, 9990 wasted firings vs zero (1000x ratio) - MOAD-0011: N=16 adversarial, 163840 defective steps vs 17 fixed (9638x ratio) Support algorithms (tests/support/Moad000X*.java): - Moad0002Algorithm: shared mutable global state (DefectiveAudioSystem / FixedAudioSystem + Context) - Moad0003Algorithm: ThreadLocal not cleared (handleDefective / handleFixed with finally) - Moad0004Algorithm: HTTP headers logged verbatim (logDefective / logFixed with CREDENTIAL_HEADERS denylist) - Moad0005Algorithm: get+null+compute+put (DefectiveCache HashMap / FixedCache ConcurrentHashMap.computeIfAbsent) - Moad0006Algorithm: Base64 password storage (DefectiveCredentialStore / FixedCredentialStore SHA-256+salt) - Moad0007Algorithm: linear spatial scan (queryDefective list / queryFixed sorted array + binary search) - Moad0009Algorithm: timer-driven polling (runDefectiveScheduler / runFixedEventDriven) - Moad0011Algorithm: PCRE nested quantifiers (matchDefective backtracking NFA / matchFixed linear NFA) Makefile: added unit-moad-0002 through unit-moad-0011 targets, integration-all-moads, functional-all-moads. integration and functional targets now depend on all-MOADs variants.
86 lines
3.2 KiB
Java
86 lines
3.2 KiB
Java
package support;
|
|
|
|
/**
|
|
* MOAD-0003: A Leaked Context.
|
|
*
|
|
* Defect: request-scoped identity (user principal, tenant ID, transaction state)
|
|
* stored in a ThreadLocal whose lifetime is the thread, not the unit of work.
|
|
* When a thread-pool thread is reused for a second request, stale identity from
|
|
* the first request bleeds into the second — even though the second request
|
|
* never set any identity.
|
|
*
|
|
* Fix: always call ThreadLocal.remove() in a finally block after the request
|
|
* completes. Alternatively, pass context explicitly as a parameter (preferred).
|
|
*
|
|
* Scanner detects: ThreadLocal fields without a paired remove() call in a
|
|
* finally block on the same code path that calls set().
|
|
*/
|
|
public class Moad0003Algorithm {
|
|
|
|
/** The ambient carrier — shared across the simulated thread pool. */
|
|
public static final ThreadLocal<String> REQUEST_IDENTITY = new ThreadLocal<>();
|
|
|
|
// ── Defective: ThreadLocal set but never removed ───────────────────────
|
|
|
|
/**
|
|
* Simulates handling one HTTP request in the defective pattern.
|
|
* Sets the ThreadLocal to 'identity' and processes the request.
|
|
* DEFECT: never calls remove() — stale identity remains on the thread.
|
|
*
|
|
* @return the identity seen during this request
|
|
*/
|
|
public static String handleDefective(String identity) {
|
|
if (identity != null) {
|
|
REQUEST_IDENTITY.set(identity);
|
|
}
|
|
// ... simulate request processing ...
|
|
return REQUEST_IDENTITY.get();
|
|
// DEFECT: no REQUEST_IDENTITY.remove() — next request sees this identity
|
|
}
|
|
|
|
/**
|
|
* Simulates the next request on the same pooled thread.
|
|
* The caller does NOT set an identity (anonymous request).
|
|
* DEFECT: returns whatever the previous request left behind.
|
|
*
|
|
* @return the identity seen — should be null but is the previous caller's identity
|
|
*/
|
|
public static String handleDefectiveAnonymous() {
|
|
// Does not call REQUEST_IDENTITY.set() — anonymous request
|
|
return REQUEST_IDENTITY.get(); // DEFECT: returns stale identity from previous request
|
|
}
|
|
|
|
// ── Fixed: ThreadLocal always removed in finally ───────────────────────
|
|
|
|
/**
|
|
* Simulates handling one HTTP request in the fixed pattern.
|
|
* Sets the ThreadLocal, processes, then ALWAYS removes in finally.
|
|
*
|
|
* @return the identity seen during this request
|
|
*/
|
|
public static String handleFixed(String identity) {
|
|
if (identity != null) {
|
|
REQUEST_IDENTITY.set(identity);
|
|
}
|
|
try {
|
|
return REQUEST_IDENTITY.get();
|
|
} finally {
|
|
REQUEST_IDENTITY.remove(); // FIX: always clean up, even on exception
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Simulates the next request on the same pooled thread (anonymous).
|
|
* After the fixed handler ran, the ThreadLocal is null.
|
|
*
|
|
* @return the identity seen — null (clean)
|
|
*/
|
|
public static String handleFixedAnonymous() {
|
|
return REQUEST_IDENTITY.get(); // FIX: null — previous request cleaned up
|
|
}
|
|
|
|
/** Reset ThreadLocal between test cases. */
|
|
public static void reset() {
|
|
REQUEST_IDENTITY.remove();
|
|
}
|
|
}
|