Master the fundamental concepts of pipelining & out-of-order execution through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksSpectre and Meltdown exploit speculative execution and cache timing. The CPU may transiently execute instructions that should never commit; microarchitectural side effects (cached lines) remain measurable.
cLoading…
Even when x is out of bounds and the branch later rolls back, the probe line may enter cache, revealing secret[x] via timing.
For this exercise, you will study a toy flush+reload or speculative load demo in a controlled sandbox. This task asks you to explain why fences alone do not fix speculation, connecting pipeline speculation from earlier tasks to CVE-2017-5753/5754.
Keep the relevant datasheet, ISA manual, or architecture textbook chapter open while you implement. When your output disagrees with the reference trace on the same program, the bug is usually a mis-decoded opcode, a stale register read, or a flag bit left unchanged after arithmetic.
For this exercise, you will use those habits while implementing the requirement in the starter code. Microarchitectural product names change across CPU generations, but the control ideas (fetch, bypass, cache lines, vector lanes) stay stable enough to debug from first principles.
Build the measuring instrument behind Spectre and Meltdown: a flush+reload cache side channel, and the speculative execution that leaks into it. The CPU speculatively runs past a bounds check, touches an array element chosen by secret data, and then rolls the architectural state back: but the cache line it loaded stays warm. Timing the probe array afterwards recovers the secret byte.
cLoading…
The probe array has 256 slots; slot k starts at byte k · S. INDEX ≥ SIZE refers to secret byte INDEX − SIZE. The in-bounds array holds array[i] = i.
flush evicts every probe slot (all slots become cold).attack INDEX:
INDEX < SIZE, the access is architectural: value INDEX, and probe slot value becomes cached.W instructions past it: it reads the secret byte and touches its probe slot, so that slot becomes cached, and then the pipeline is flushed. The architectural result is (nothing — squashed).index-masking clamps the index with index & (SIZE − 1) before the access, so nothing out of bounds is ever touched (SIZE is a power of two in the tests). lfence stops speculation entirely: an out-of-bounds access touches nothing.H cycles, an uncached one M. The recovered byte is the slot with the lowest time; ties go to the lowest slot number.For each attack:
cLoading…
The probe: line follows every attack. When more than one slot is cached, list them all as slot A = H cycles, slot B = H cycles. When none is cached, print probe: no cached slot -> leak failed. The character is shown for printable bytes (32..126) and omitted otherwise. flush prints flush: N slots evicted. At the end:
cLoading…
An attack is leaked when it was out of bounds and the probe recovered the correct secret byte, and blocked when a mitigation stopped it.
Input:
cLoading…
Output:
cLoading…
Hidden tests cover lfence, index-masking (whose probe reveals only the masked index), a probe with several slots still cached because flush was skipped, and a non-printable secret byte.