This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: bun-ffi-pointer-lifecycle-ownership-invariant

Bun 1.2 Native C-FFI Pointer Lifecycle, Ownership Invariant, and Finalization Registry

Enforces strict pointer ownership boundaries, deterministic deallocation, and safe buffer wrapping when bridging native C-FFI dynamic libraries with Bun 1.2's JavaScriptCore (JSC) runtime. Prevents double-free vulnerabilities, use-after-free corruption, and untracked native heap exhaustion caused by mismatched allocator ownership and asynchronous garbage collection cycles.

Prohibited Anti-Pattern: Implicit Pointer Ownership and Untracked Native Deallocation in Bun FFI Interfaces

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Bun 1.2 Native C-FFI Pointer Lifecycle, Ownership Invariant, and Finalization Registry - Enforces strict pointer ownership boundaries, deterministic deallocation, and safe buffer wrapping when bridging native C-FFI dynamic libraries with Bun 1.2's JavaScriptCore (JSC) runtime. Prevents double-free vulnerabilities, use-after-free corruption, and untracked native heap exhaustion caused by mismatched allocator ownership and asynchronous garbage collection cycles.
globs: src/**/*.{ts,js}, lib/**/*.{ts,js}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/bun-ffi-pointer-lifecycle-ownership-invariant"
---

# Bun 1.2 Native C-FFI Pointer Lifecycle, Ownership Invariant, and Finalization Registry

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Implicit Pointer Ownership and Untracked Native Deallocation in Bun FFI Interfaces

## System Constraints
You are a Principal Systems Engineer enforcing Bun 1.2 Native C-FFI Pointer Lifecycle & Ownership Invariants. Mandate strict linear ownership models, explicit allocator-matched deallocators, and fail-safe FinalizationRegistry wrappers. Prohibit bare pointer exposure to caller modules and prevent double-free hazards under asynchronous JSC GC pressure.

## Strict Guidelines
- Engineers MUST ALWAYS wrap raw `bun:ffi` pointers (`Pointer` or `number`) inside an explicit RAII wrapper class or deterministic disposable struct implementing `Symbol.dispose` and `FinalizationRegistry` safety nets.
- Engineers MUST NOT rely solely on JavaScriptCore garbage collection to release native C memory allocations; native memory must be deterministically released as soon as the execution scope finishes.
- Code MUST explicitly decouple JavaScript view buffers (`toArrayBuffer`, `toBuffer`) from raw native ownership, ensuring the lifetime of the underlying pointer strictly supersedes the lifetime of any dependent typed array views.
- Services MUST ensure that pointer deallocation functions explicitly match the library's native allocator (e.g., custom library free functions like `duckdb_free` or `deflate_free` instead of generic `libc.free`) to avoid cross-allocator memory corruption.
- Components NEVER re-use, dereference, or release a pointer after its internal reference has been nullified (`ptr = null`), establishing absolute zeroing upon free to prevent use-after-free and double-free vulnerabilities.

## Bad vs Good Implementations
### Enforcing RAII Disposal and Nullification over Raw Pointer Exposure

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The raw native pointer is exposed across the execution scope without exception safety, scoped resource management, or nullification after deallocation. If process_payload throws, the pointer leaks indefinitely outside JSC's GC visibility. Furthermore, calling free_payload twice triggers an immediate double-free segmentation fault or heap corruption.
```typescript
import { dlopen, FFIType, ptr } from "bun:ffi";

const lib = dlopen("libnative.so", {
  alloc_payload: { args: [FFIType.u32], returns: FFIType.ptr },
  free_payload: { args: [FFIType.ptr], returns: FFIType.void },
  process_payload: { args: [FFIType.ptr], returns: FFIType.i32 }
});

export function runTask(size: number): number {
  // Anti-pattern: Raw pointer leaks if process_payload throws;
  // No explicit tracking, susceptible to GC delay and double-free.
  const rawPtr = lib.symbols.alloc_payload(size);
  const result = lib.symbols.process_payload(rawPtr);
  lib.symbols.free_payload(rawPtr);
  // If caller or concurrent process frees rawPtr again -> process crash / CVE
  lib.symbols.free_payload(rawPtr);
  return result;
}
```

#### Production Standard (Correct)
> **Standard**: Implements deterministic RAII using TypeScript's `using` declaration and `Symbol.dispose`, paired with a fallback `FinalizationRegistry` to prevent leaks if scope disposal is skipped. The internal pointer is set to `null` immediately upon free, guaranteeing prevention of double-free and use-after-free exploits even under exceptional control flows.
```typescript
import { dlopen, FFIType, Pointer } from "bun:ffi";

const lib = dlopen("libnative.so", {
  alloc_payload: { args: [FFIType.u32], returns: FFIType.ptr },
  free_payload: { args: [FFIType.ptr], returns: FFIType.void },
  process_payload: { args: [FFIType.ptr], returns: FFIType.i32 }
});

const finalizer = new FinalizationRegistry<Pointer>((heldPtr) => {
  if (heldPtr !== 0) {
    lib.symbols.free_payload(heldPtr);
  }
});

export class NativeBufferHandle implements Disposable {
  private rawPtr: Pointer | null = null;

  constructor(size: number) {
    const ptr = lib.symbols.alloc_payload(size);
    if (!ptr || ptr === 0) {
      throw new Error("Native memory allocation failed");
    }
    this.rawPtr = ptr;
    finalizer.register(this, ptr, this);
  }

  public get pointer(): Pointer {
    if (this.rawPtr === null) {
      throw new Error("Use-after-free: Pointer has already been released");
    }
    return this.rawPtr;
  }

  public [Symbol.dispose](): void {
    if (this.rawPtr !== null) {
      finalizer.unregister(this);
      lib.symbols.free_payload(this.rawPtr);
      this.rawPtr = null;
    }
  }
}

export function runTask(size: number): number {
  using handle = new NativeBufferHandle(size);
  return lib.symbols.process_payload(handle.pointer);
}
```

Recommended MCP Servers (mcp-serverlist.com)

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

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Bun 1.2 Native C-FFI Pointer Lifecycle, Ownership Invariant, and Finalization Registry

Bun 1.2 Native C-FFI Pointer Lifecycle, Ownership Invariant, and Finalization Registry defines an industrial-grade behavioral standard for backend engineering. Enforces strict pointer ownership boundaries, deterministic deallocation, and safe buffer wrapping when bridging native C-FFI dynamic libraries with Bun 1.2's JavaScriptCore (JSC) runtime. Prevents double-free vulnerabilities, use-after-free corruption, and untracked native heap exhaustion caused by mismatched allocator ownership and asynchronous garbage collection cycles. 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: Implicit Pointer Ownership and Untracked Native Deallocation in Bun FFI Interfaces 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 DriftImplicit Pointer Ownership and Untracked Native Deallocation in Bun FFI InterfacesCritical
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 wrap raw `bun

Engineers MUST ALWAYS wrap raw `bun:ffi` pointers (`Pointer` or `number`) inside an explicit RAII wrapper class or deterministic disposable struct implementing `Symbol.dispose` and `FinalizationRegistry` safety nets.

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 rely solely on JavaScriptCore garbage collection to release native C memory allocations

Engineers MUST NOT rely solely on JavaScriptCore garbage collection to release native C memory allocations; native memory must be deterministically released as soon as the execution scope finishes.

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 decouple JavaScript view buffers (`toArrayBuffer`, `toBuffer`) from raw native ownership, ensuring the lifetime of the underlying pointer strictly supersedes the lifetime of any dependent typed array views.

Code MUST explicitly decouple JavaScript view buffers (`toArrayBuffer`, `toBuffer`) from raw native ownership, ensuring the lifetime of the underlying pointer strictly supersedes the lifetime of any dependent typed array views.

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 MUST ensure that pointer deallocation functions explicitly match the library's native allocator (e.g., custom library free functions like `duckdb_free` or `deflate_free` instead of generic `libc.free`) to avoid cross-allocator memory corruption.

Services MUST ensure that pointer deallocation functions explicitly match the library's native allocator (e.g., custom library free functions like `duckdb_free` or `deflate_free` instead of generic `libc.free`) to avoid cross-allocator memory corruption.

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 re-use, dereference, or release a pointer after its internal reference has been nullified (`ptr = null`), establishing absolute zeroing upon free to prevent use-after-free and double-free vulnerabilities.

Components NEVER re-use, dereference, or release a pointer after its internal reference has been nullified (`ptr = null`), establishing absolute zeroing upon free to prevent use-after-free and double-free vulnerabilities.

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 Native C-FFI Pointer Lifecycle, Ownership Invariant, and Finalization Registry critical for AI coding assistants?

Enforces strict pointer ownership boundaries, deterministic deallocation, and safe buffer wrapping when bridging native C-FFI dynamic libraries with Bun 1.2's JavaScriptCore (JSC) runtime. Prevents double-free vulnerabilities, use-after-free corruption, and untracked native heap exhaustion caused by mismatched allocator ownership and asynchronous garbage collection cycles. 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 (Implicit Pointer Ownership and Untracked Native Deallocation in Bun FFI Interfaces) 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