June 16, 2026
I Wrote 30 Lines of C and Watched My CPU Leak Secrets
I spent my day measuring how many CPU cycles it takes to fetch a single byte from memory.
ZarxhNebula
3 min read
And honestly, it was one of the coolest things I've done so far.
As someone learning cybersecurity and computer architecture, I kept hearing terms like:
- Cache
- Cache Hits
- Cache Misses
- Spectre
- Meltdown
- Side-Channel Attacks
But they all felt abstract.
Then I wrote a tiny C program and watched my CPU reveal one of its secrets.
The Program
#include <stdio.h>
#include <stdint.h>
#include <x86intrin.h>
volatile unsigned char data[1024];
volatile unsigned char temp;
int main() {
printf("=== CACHE TIMING DEMO ===\n\n");
// STEP 1: Put the value into cache
data[0] = 42;
// Access once so CPU loads it into cache
temp = data[0];
// STEP 2: Measure CACHE HIT
unsigned int aux;
uint64_t start_hit = __rdtscp(&aux);
temp = data[0];
uint64_t end_hit = __rdtscp(&aux);
// STEP 3: Force CPU to remove this cache line
_mm_clflush((void*)&data[0]);
// STEP 4: Measure CACHE MISS
uint64_t start_miss = __rdtscp(&aux);
temp = data[0];
uint64_t end_miss = __rdtscp(&aux);
printf("Cache HIT : %llu cycles\n", end_hit - start_hit);
printf("Cache MISS : %llu cycles\n", end_miss - start_miss);
return 0;
}#include <stdio.h>
#include <stdint.h>
#include <x86intrin.h>
volatile unsigned char data[1024];
volatile unsigned char temp;
int main() {
printf("=== CACHE TIMING DEMO ===\n\n");
// STEP 1: Put the value into cache
data[0] = 42;
// Access once so CPU loads it into cache
temp = data[0];
// STEP 2: Measure CACHE HIT
unsigned int aux;
uint64_t start_hit = __rdtscp(&aux);
temp = data[0];
uint64_t end_hit = __rdtscp(&aux);
// STEP 3: Force CPU to remove this cache line
_mm_clflush((void*)&data[0]);
// STEP 4: Measure CACHE MISS
uint64_t start_miss = __rdtscp(&aux);
temp = data[0];
uint64_t end_miss = __rdtscp(&aux);
printf("Cache HIT : %llu cycles\n", end_hit - start_hit);
printf("Cache MISS : %llu cycles\n", end_miss - start_miss);
return 0;
}When I ran it, I got something similar to:
Cache HIT : 271 cycles
Cache MISS : 813 cyclesCache HIT : 271 cycles
Cache MISS : 813 cyclesThe exact numbers change every run, but one thing remains consistent:
The cache hit is much faster than the cache miss.
What Is The CPU Actually Doing?
When the CPU needs data, it doesn't immediately go to RAM.
That would be far too slow.
Instead it checks a hierarchy:
CPU
↓
L1 Cache
↓
L2 Cache
↓
L3 Cache
↓
RAMCPU
↓
L1 Cache
↓
L2 Cache
↓
L3 Cache
↓
RAMThe closer the data is, the faster it can be accessed.
Step 1: Loading Data Into Cache
This line:
data[0] = 42;data[0] = 42;stores the value 42 in memory.
Then:
temp = data[0];temp = data[0];forces the CPU to fetch it.
If the value isn't already cached, the CPU retrieves it from RAM and stores a copy in cache for future use.
At this point:
data[0]data[0]is sitting inside the cache.
Step 2: Measuring A Cache Hit
Now we measure how long it takes to access the same byte again.
uint64_t start_hit = __rdtscp(&aux);
temp = data[0];
uint64_t end_hit = __rdtscp(&aux);uint64_t start_hit = __rdtscp(&aux);
temp = data[0];
uint64_t end_hit = __rdtscp(&aux);The CPU already has the data nearby.
It doesn't need to travel all the way to RAM.
This is called a cache hit.
The access is fast because the data is already waiting close to the processor.
Step 3: Kicking It Out Of Cache
This line is the interesting one:
_mm_clflush((void*)&data[0]);_mm_clflush((void*)&data[0]);It tells the CPU:
Remove this cache line.
Now the cached copy disappears.
The next access can't use the fast path anymore.
Step 4: Measuring A Cache Miss
Now we measure again:
uint64_t start_miss = __rdtscp(&aux);
temp = data[0];
uint64_t end_miss = __rdtscp(&aux);uint64_t start_miss = __rdtscp(&aux);
temp = data[0];
uint64_t end_miss = __rdtscp(&aux);This time the CPU checks cache.
Nothing.
So it has to fetch the data from lower levels of memory.
That extra journey costs time.
This is called a cache miss.
And that's exactly why the cycle count increases.
The Crazy Part Most Beginners Don't Know
The CPU doesn't fetch one byte.
Even though we requested:
data[0]data[0]the processor actually loads an entire cache line.
Typically:
64 bytes64 bytesMeaning:
data[0]
data[1]
data[2]
...
data[63]data[0]
data[1]
data[2]
...
data[63]all get pulled into cache together.
The CPU is essentially making an educated guess:
If you needed byte 0, you might need nearby bytes too.
This optimization is called spatial locality.
Modern processors are constantly making these predictions to improve performance.
Why Does The Timing Change Every Run?
One thing that confused me was seeing different numbers every time.
For example:
271 cycles
813 cycles271 cycles
813 cyclesthen later:
220 cycles
700 cycles220 cycles
700 cyclesor
310 cycles
900 cycles310 cycles
900 cyclesThe reason is simple.
Your program isn't running alone.
While you're measuring:
- Windows is running
- Browser tabs are running
- VS Code is running
- Antivirus is running
- CPU frequency is changing
- Other applications are using cache
The important thing is the pattern:
Cache Hit < Cache MissCache Hit < Cache MissEvery single time.
Why Hackers Care About This
At first this just looks like a performance trick.
It's actually much more important.
Imagine a victim program accesses:
array[7];array[7];You cannot directly see what it accessed.
But if you can measure memory timings, you might notice:
array[0] → slow
array[1] → slow
array[2] → slow
array[7] → fastarray[0] → slow
array[1] → slow
array[2] → slow
array[7] → fastThat timing difference leaks information.
You never read the secret directly.
You inferred it from how long memory access took.
That's the foundation behind cache side-channel attacks.
The attack doesn't steal information through normal program output.
It steals information through timing.
Final Thoughts
Before this experiment, cache was just a word I saw in textbooks.
Now I've actually measured it.
I've watched a CPU retrieve data from cache versus memory and observed the difference in real time. You can do too!
For me, that's what makes computer architecture fascinating.
The deeper you go, the more you realize that cybersecurity isn't just about websites and networks.
Sometimes it's about understanding what happens in the tiny fraction of a second between a processor asking for data and memory responding.
And sometimes, that tiny timing difference is enough to leak secrets.
This was ZarxhNebula :)
Follow if you feel like.