spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

Add educational Rowhammer DRAM self-testBrowse files
A standalone C program that demonstrates the Rowhammer DRAM disturbance
effect on the local machine's own memory. It hammers pairs of addresses
with CLFLUSH/MFENCE to force DRAM row activations, then scans an all-1s
buffer for induced bit flips. Includes build/run instructions and notes
on x86-only flush, probabilistic results, and ARM porting.

https://claude.ai/code/session_01WsBb1UNSn1Ta9H6aBYVYGe
Claude authored on Jun 9, 2026 parent f967b36 · commit 5b451bd39dc1
1 changed file+134 -0compared with f967b36
Arowhammer.c
Arowhammer.c+134 -0
@@ -1,0 +1,134 @@
1+// rowhammer.c — a minimal, educational Rowhammer self-test.
2+//
3+// What it does
4+// ------------
5+// Rowhammer is a DRAM disturbance effect: repeatedly activating ("hammering")
6+// the same DRAM rows can flip bits in physically adjacent rows. This program
7+// demonstrates the effect on *your own* machine's memory so you can learn how
8+// it works and check whether your RAM is susceptible. It does not attack any
9+// remote target — it only reads/writes a buffer this process allocated itself.
10+//
11+// How it works
12+// ------------
13+// 1. Allocate a large buffer and fill it with a known pattern (all 1s).
14+// 2. Repeatedly read from two addresses that are likely to live in different
15+// rows of the same DRAM bank. Each read is followed by clflush so the CPU
16+// cache is bypassed and the access actually reaches DRAM, forcing row
17+// activations.
18+// 3. After many millions of hammer iterations, scan the buffer for any bit
19+// that is no longer 1. Any such bit is a Rowhammer-induced flip.
20+//
21+// This is a probabilistic test: vulnerable hardware may need many runs and
22+// different address pairs before a flip appears; robust hardware (e.g. with
23+// ECC or target-row-refresh mitigations) may never flip.
24+//
25+// Build (x86-64, Linux/macOS with clflush support):
26+// cc -O2 -o rowhammer rowhammer.c
27+//
28+// Run:
29+// ./rowhammer # default: 256 MiB, 2,000,000 hammers per pair
30+// ./rowhammer 512 4000000
31+//
32+// Notes
33+// -----
34+// * Uses the x86 CLFLUSH instruction; on ARM you would need a cache-clean
35+// equivalent (e.g. DC CIVAC) instead.
36+// * For a serious test you want physically-contiguous, address-mapping-aware
37+// pairs (huge pages, knowledge of the DRAM bank/row geometry). This sample
38+// keeps things simple and portable at the cost of hit rate.
39+
40+#include <stdint.h>
41+#include <stdio.h>
42+#include <stdlib.h>
43+#include <string.h>
44+#include <time.h>
45+
46+#if defined(__x86_64__) || defined(__i386__)
47+#include <x86intrin.h>
48+static inline void flush(volatile void *p) { _mm_clflush((const void *)p); }
49+static inline void fence(void) { _mm_mfence(); }
50+#else
51+#error "This sample uses x86 CLFLUSH; port flush()/fence() for your ISA."
52+#endif
53+
54+// Hammer two addresses: read each, flush each from cache, repeat. The flushes
55+// guarantee the next read misses cache and reactivates the DRAM row.
56+static void hammer(volatile uint64_t *a, volatile uint64_t *b, uint64_t iters) {
57+ for (uint64_t i = 0; i < iters; i++) {
58+ (void)*a;
59+ (void)*b;
60+ flush((void *)a);
61+ flush((void *)b);
62+ fence();
63+ }
64+}
65+
66+// Scan the buffer for any bit that is not set; report flips.
67+static uint64_t count_flips(const uint8_t *buf, size_t bytes) {
68+ uint64_t flips = 0;
69+ for (size_t i = 0; i < bytes; i++) {
70+ uint8_t v = buf[i];
71+ if (v != 0xFF) {
72+ for (int bit = 0; bit < 8; bit++) {
73+ if (!((v >> bit) & 1)) {
74+ flips++;
75+ fprintf(stderr, " bit flip at offset %zu, bit %d\n", i, bit);
76+ }
77+ }
78+ }
79+ }
80+ return flips;
81+}
82+
83+int main(int argc, char **argv) {
84+ size_t mib = (argc > 1) ? (size_t)strtoull(argv[1], NULL, 10) : 256;
85+ uint64_t iters = (argc > 2) ? strtoull(argv[2], NULL, 10) : 2000000ULL;
86+
87+ size_t bytes = mib * 1024 * 1024;
88+ uint8_t *buf = aligned_alloc(4096, bytes);
89+ if (!buf) {
90+ perror("aligned_alloc");
91+ return 1;
92+ }
93+
94+ printf("Allocated %zu MiB at %p\n", mib, (void *)buf);
95+ printf("Filling with all-1s pattern...\n");
96+ memset(buf, 0xFF, bytes);
97+
98+ // Choose hammer pairs that straddle the buffer. A real test would derive
99+ // these from the DRAM row geometry; here we step through with a stride
100+ // large enough to likely cross row boundaries.
101+ const size_t stride = 256 * 1024; // 256 KiB apart
102+ size_t pairs = 0, total_flips = 0;
103+
104+ struct timespec t0;
105+ clock_gettime(CLOCK_MONOTONIC, &t0);
106+
107+ for (size_t off = 0; off + 2 * stride < bytes; off += stride) {
108+ volatile uint64_t *a = (volatile uint64_t *)(buf + off);
109+ volatile uint64_t *b = (volatile uint64_t *)(buf + off + stride);
110+ hammer(a, b, iters);
111+ pairs++;
112+ if (pairs % 64 == 0) {
113+ printf(" hammered %zu pairs...\n", pairs);
114+ }
115+ }
116+
117+ struct timespec t1;
118+ clock_gettime(CLOCK_MONOTONIC, &t1);
119+ double secs = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;
120+
121+ printf("Hammered %zu pairs in %.1f s. Scanning for flips...\n", pairs, secs);
122+ total_flips = count_flips(buf, bytes);
123+
124+ if (total_flips == 0) {
125+ printf("No bit flips detected. Try more iterations, more memory, or "
126+ "a different stride.\n");
127+ } else {
128+ printf("DETECTED %zu bit flip(s) — this memory is susceptible.\n",
129+ total_flips);
130+ }
131+
132+ free(buf);
133+ return 0;
134+}