/* Step 6: does OCaml's collector touch memory it does not own? * * Flan's arenas, Vecs and Maps are plain malloc'd memory. The claim is that * OCaml never sees them, so a compaction cannot move or scribble on them. The * probe: fill an arena with a checkable pattern, hold raw interior pointers * into it across a full major collection AND a compaction, then verify every * byte and every pointer. * * What this proves is narrow and worth stating narrowly: OCaml traces its own * roots only. It does NOT license storing an OCaml `value` in this arena -- * that would need caml_register_global_root, and is the way the assumption * actually breaks. */ #include #include #include #include #include #include #define ARENA (8u << 20) /* 8 MiB, the shape of a Flan arena */ static uint8_t *arena; static uint64_t *interior[64]; CAMLprim value spike_note_arena(value p) { (void)p; return Val_unit; } static uint8_t pattern(size_t i) { return (uint8_t)(i * 31u + 7u); } int main(int argc, char **argv) { const value *f; size_t i, bad = 0; uint8_t *before; (void)argc; arena = malloc(ARENA); if (!arena) return 1; for (i = 0; i < ARENA; i++) arena[i] = pattern(i); for (i = 0; i < 64; i++) interior[i] = (uint64_t *)(arena + i * 4096); before = arena; caml_startup(argv); f = caml_named_value("spike_churn"); if (!f) { fprintf(stderr, "spike: churn not registered\n"); return 1; } printf("%s\n", String_val(caml_callback(*f, Val_int(200)))); for (i = 0; i < ARENA; i++) if (arena[i] != pattern(i)) bad++; printf("arena base %s (%p -> %p)\n", before == arena ? "unmoved" : "MOVED", (void *)before, (void *)arena); printf("arena bytes altered by the GC: %zu of %u\n", bad, ARENA); bad = 0; for (i = 0; i < 64; i++) if (interior[i] != (uint64_t *)(arena + i * 4096)) bad++; printf("raw interior pointers invalidated: %zu of 64\n", bad); printf("spike: %s\n", bad == 0 ? "foreign memory is invisible to the collector" : "FOREIGN MEMORY WAS DISTURBED"); free(arena); return 0; }