This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: bun-ffi-zero-copy-lifetime-pinning

Bun 1.2 Zero-Copy FFI Pointer Pinning and GC Anchor Invariant

Mandates deterministic GC anchoring and buffer lifecycle management for all zero-copy pointers passed into native asynchronous or threaded C-ABI functions in Bun 1.2. Failure to pin the underlying ArrayBuffer in JavaScriptCore heap during native execution causes non-deterministic Use-After-Free (UAF) and memory corruption.

Prohibited Anti-Pattern: Passing Ephemeral TypedArray Pointers to Asynchronous Native FFI Functions Without GC Anchors

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Bun 1.2 Zero-Copy FFI Pointer Pinning and GC Anchor Invariant - Mandates deterministic GC anchoring and buffer lifecycle management for all zero-copy pointers passed into native asynchronous or threaded C-ABI functions in Bun 1.2. Failure to pin the underlying ArrayBuffer in JavaScriptCore heap during native execution causes non-deterministic Use-After-Free (UAF) and memory corruption.
globs: src/**/*.{ts,tsx}, lib/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/bun-ffi-zero-copy-lifetime-pinning"
---

# Bun 1.2 Zero-Copy FFI Pointer Pinning and GC Anchor Invariant

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Passing Ephemeral TypedArray Pointers to Asynchronous Native FFI Functions Without GC Anchors

## System Constraints
You are a Principal Engineer enforcing Bun 1.2 Zero-Copy FFI Memory Lifetime and Pointer Pinning Invariant. Mandate invariants that prevent JavaScriptCore garbage collection from reclaiming or moving TypedArray memory buffers while native C-ABI or Rust asynchronous tasks are accessing them.

## Strict Guidelines
- Engineers MUST ALWAYS anchor TypedArray and ArrayBuffer references in a strongly reachable scope (such as an active Promise closure or a module-level Pinning Set) for the entire duration of an asynchronous native FFI execution.
- Engineers MUST NOT pass inline-allocated TypedArrays directly into ptr() expressions when calling asynchronous foreign functions (e.g., ptr(new Uint8Array(1024))).
- Code MUST explicitly unpin and clear buffer references inside a finally block once the native task resolves or rejects to prevent unbounded memory leaks.
- Services handling high-throughput zero-copy transfers MUST use pre-allocated static ring buffers or Bun-managed native slabs rather than re-allocating transient JS buffers per invocation.
- Components NEVER cast raw returned native pointers into JS TypedArrays via toArrayBuffer() without strictly defining whether the native side or Bun owns deallocation.

## Bad vs Good Implementations
### Asynchronous Zero-Copy FFI Pointer Pinning Guard

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The 'payload' TypedArray has no strong reference retained by the JS runtime across the asynchronous boundary. JavaScriptCore's GC can collect the underlying ArrayBuffer during native execution, leading to Use-After-Free when the C-ABI worker thread dereferences the pointer.
```typescript
import { dlopen, ptr, FFIType } from "bun:ffi";

const { symbols } = dlopen("libcompress.so", {
  compress_async: {
    args: [FFIType.ptr, FFIType.u64, FFIType.ptr],
    returns: FFIType.void,
  },
});

// ANTI-PATTERN: The payload buffer is passed directly via ptr() without an anchor.
// Under high GC pressure in Bun 1.2, JSC may collect or relocate `payload` while
// the background C thread is executing compress_async, causing SIGSEGV or memory corruption.
export async function compressData(data: Uint8Array): Promise<void> {
  const payload = new Uint8Array(data); // Ephemeral allocation
  return new Promise((resolve) => {
    symbols.compress_async(ptr(payload), payload.byteLength, ptr(resolve));
  });
}
```

#### Production Standard (Correct)
> **Standard**: The payload buffer is explicitly anchored in ACTIVE_FFI_PINS before ptr() is invoked and held throughout the Promise lifecycle. The try/finally block guarantees that even on rejection or error, the GC pin is removed without leaking memory or exposing the native runtime to Use-After-Free.
```typescript
import { dlopen, ptr, FFIType, type Pointer } from "bun:ffi";

const { symbols } = dlopen("libcompress.so", {
  compress_async: {
    args: [FFIType.ptr, FFIType.u64, FFIType.ptr],
    returns: FFIType.void,
  },
});

// Retaining set to anchor active buffers in JSC heap until native completion
const ACTIVE_FFI_PINS = new Set<Uint8Array | ArrayBuffer>();

export async function compressData(data: Uint8Array): Promise<void> {
  // Clone or capture buffer to guarantee ownership
  const payload = new Uint8Array(data.byteLength);
  payload.set(data);

  // PIN: Register strong reference before obtaining native pointer
  ACTIVE_FFI_PINS.add(payload);
  const bufferPtr: Pointer = ptr(payload);

  try {
    await new Promise<void>((resolve, reject) => {
      try {
        symbols.compress_async(bufferPtr, payload.byteLength, ptr(resolve));
      } catch (err) {
        reject(err);
      }
    });
  } finally {
    // UNPIN: Guarantee cleanup once C thread completes
    ACTIVE_FFI_PINS.delete(payload);
  }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Bun 1.2 Zero-Copy FFI Pointer Pinning and GC Anchor Invariant

Bun 1.2 Zero-Copy FFI Pointer Pinning and GC Anchor Invariant defines an industrial-grade behavioral standard for backend engineering. Mandates deterministic GC anchoring and buffer lifecycle management for all zero-copy pointers passed into native asynchronous or threaded C-ABI functions in Bun 1.2. Failure to pin the underlying ArrayBuffer in JavaScriptCore heap during native execution causes non-deterministic Use-After-Free (UAF) and memory corruption. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Passing Ephemeral TypedArray Pointers to Asynchronous Native FFI Functions Without GC Anchors Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftPassing Ephemeral TypedArray Pointers to Asynchronous Native FFI Functions Without GC AnchorsCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS anchor TypedArray and ArrayBuffer references in a strongly reachable scope (such as an active Promise closure or a module-level Pinning Set) for the entire duration of an asynchronous native FFI execution.

Engineers MUST ALWAYS anchor TypedArray and ArrayBuffer references in a strongly reachable scope (such as an active Promise closure or a module-level Pinning Set) for the entire duration of an asynchronous native FFI execution.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT pass inline-allocated TypedArrays directly into ptr() expressions when calling asynchronous foreign functions (e.g., ptr(new Uint8Array(1024))).

Engineers MUST NOT pass inline-allocated TypedArrays directly into ptr() expressions when calling asynchronous foreign functions (e.g., ptr(new Uint8Array(1024))).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Code MUST explicitly unpin and clear buffer references inside a finally block once the native task resolves or rejects to prevent unbounded memory leaks.

Code MUST explicitly unpin and clear buffer references inside a finally block once the native task resolves or rejects to prevent unbounded memory leaks.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services handling high-throughput zero-copy transfers MUST use pre-allocated static ring buffers or Bun-managed native slabs rather than re-allocating transient JS buffers per invocation.

Services handling high-throughput zero-copy transfers MUST use pre-allocated static ring buffers or Bun-managed native slabs rather than re-allocating transient JS buffers per invocation.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER cast raw returned native pointers into JS TypedArrays via toArrayBuffer() without strictly defining whether the native side or Bun owns deallocation.

Components NEVER cast raw returned native pointers into JS TypedArrays via toArrayBuffer() without strictly defining whether the native side or Bun owns deallocation.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Bun 1.2 Zero-Copy FFI Pointer Pinning and GC Anchor Invariant critical for AI coding assistants?

Mandates deterministic GC anchoring and buffer lifecycle management for all zero-copy pointers passed into native asynchronous or threaded C-ABI functions in Bun 1.2. Failure to pin the underlying ArrayBuffer in JavaScriptCore heap during native execution causes non-deterministic Use-After-Free (UAF) and memory corruption. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Passing Ephemeral TypedArray Pointers to Asynchronous Native FFI Functions Without GC Anchors) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

Bun