Skip to main content

Crate pager_lang

Crate pager_lang 

Source
Expand description

§pager_lang

Virtual and executable memory management for JIT compilers and language runtimes.

A just-in-time compiler emits machine code at run time and then jumps into it. To do that it needs memory the operating system will let the CPU execute, which ordinary heap allocations are not. pager-lang is the small, focused layer that hands out that memory: page-aligned regions whose access permissions — read, write, execute — can be changed on demand, with optional guard pages, and nothing more.

The whole surface is three types and one function:

  • Region — an owned block of page-aligned virtual memory, freed when dropped.
  • Protection — the access a region permits: read, write, execute, in the useful combinations.
  • PagerError — the reason an operation failed.
  • page_size — the host page size, the unit regions are measured in.

§Write xor execute

The intended flow is write xor execute (W^X), the discipline that keeps memory from ever being writable and executable at the same time. A region is born ReadWrite; you write code into it; you flip it to ReadExecute; then you run it. At no point is the same page both writable and runnable, which closes off a large class of exploits.

use pager_lang::{Protection, Region};

// Reserve a writable page.
let mut code = Region::new(4096)?;

// Write some bytes (here a harmless pattern — real code is target-specific).
code.write(0, &[0x90, 0x90, 0xC3])?; // x86: nop; nop; ret

// Flip to read+execute. The region is no longer writable.
code.protect(Protection::ReadExecute)?;
assert!(code.as_mut_slice().is_none());

// `code.as_ptr()` now points at executable memory. Transmuting it to a function
// pointer and calling it is `unsafe` and the caller's responsibility — see
// `examples/jit_function.rs` for a complete, runnable example on x86-64.

§Guard pages

Region::with_guard_pages flanks the usable region with inaccessible pages, so a write that runs off either end faults immediately instead of silently corrupting adjacent memory — cheap insurance for a code buffer a compiler is filling.

§Platforms

Regions are backed by mmap/mprotect/munmap on Unix and VirtualAlloc/VirtualProtect/VirtualFree on Windows, reached through direct FFI with no third-party dependencies. Linux, macOS, and Windows (x86-64 and ARM64) are the supported targets; a target with no operating system cannot provide these calls and will not compile.

Getting memory into an executable state is portable; running freshly written code is not entirely. On architectures with separate instruction and data caches — AArch64, for instance — code written into a region must have the instruction cache synchronized before it is executed. On x86 and x86-64 this is automatic. This crate manages the memory and its protections; instruction-cache synchronization for the architectures that need it is the caller’s responsibility at the point of execution.

§Features

  • std (default) — links the standard library. Without it the crate is #![no_std] and needs only core; it reaches the operating system through FFI either way, so behavior is identical.
  • serde — derives Serialize / Deserialize for Protection and PagerError, so a region’s configuration and failure reasons can cross a serialization boundary.

§Stability

The public surface is frozen and stable as of 1.0.0: it follows Semantic Versioning, with no breaking changes before 2.0. PagerError is #[non_exhaustive], so a new failure variant is an additive, non-breaking change. The full surface and the SemVer promise are catalogued in docs/API.md.

Structs§

Region
An owned region of page-aligned virtual memory, freed when it is dropped.

Enums§

PagerError
The reason a Region operation failed.
Protection
The access a page range permits: which of read, write, and execute the CPU will allow.

Functions§

page_size
The size of a memory page on the host, in bytes.