Skip to content
Back to skills

2570 Ownership And Memory Ae9edde7

ASecurity

Detailed reference for ownership transfer and `moonbit_incref`/`moonbit_decref` rules. For basic `#borrow`/`#owned` usage and the external object / value-as-bytes patterns, see SKILL.md Phase 2.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
business

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2570-ownership-and-memory_ae9edde7 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2570 Ownership And Memory Ae9edde7?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2570 Ownership And Memory Ae9edde7
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2570-ownership-and-memory-ae9edde7/badge)](https://www.skillsdirectory.com/skills/tools-only-2570-ownership-and-memory-ae9edde7)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Ownership Semantics and Memory Management

Detailed reference for ownership transfer and `moonbit_incref`/`moonbit_decref`
rules. For basic `#borrow`/`#owned` usage and the external object / value-as-bytes
patterns, see SKILL.md Phase 2.

## `#owned(param)` Semantics

The `#owned` annotation explicitly declares that ownership of the parameter
transfers to C. C must call `moonbit_decref()` when done. Leaving parameters
without an ownership annotation is deprecated — new code should use
`#owned(param)` explicitly.

**Primitives** (`Int`, `UInt`, `Bool`, `Double`, `Int64`, `UInt64`, `Byte`,
`Float`): passed by value. No ownership concerns — no annotation needed.

**GC-managed objects** (`Bytes`, `String`, `FixedArray[T]`, external objects,
struct wrappers): use `#owned` to transfer ownership to C. C must call
`moonbit_decref()` when done.

**Objects allocated in C** via `moonbit_make_external_object`,
`moonbit_make_bytes`, etc.: the C code owns the newly created object. It must
either return it to MoonBit (transferring ownership) or call
`moonbit_decref()` when done. Treat these as `#owned` from the C side.

## Operation Tables

What refcount operations are required for each action on a parameter:

**`#borrow` parameters:**

| Operation | Required action |
|---|---|
| Read field/element | nothing |
| Store into data structure | `moonbit_incref` |
| Pass to MoonBit function | `moonbit_incref` |
| Pass to other C function | nothing |
| Return | `moonbit_incref` |
| End of scope | nothing |

**`#owned` parameters (default if no annotation):**

| Operation | Required action |
|---|---|
| Read field/element | nothing |
| Store into data structure | nothing (already owned) |
| Pass to MoonBit function | `moonbit_incref` |
| Pass to other C function | nothing |
| Return | nothing |
| End of scope (not returned) | `moonbit_decref` |

Practical rules for `#owned`:

- Call `moonbit_decref()` exactly once per owned parameter before the function returns.
- If storing the object longer-term, decref when the storage is torn down.
- Every early-return path must still decref all owned parameters.

Example:

```c
MOONBIT_FFI_EXPORT
int32_t
moonbit_process(void *handle, moonbit_bytes_t data) {
  size_t len = Moonbit_array_length(data);
  int32_t result = lib_process(handle, (const char *)data, len);
  moonbit_decref(handle);  // Decrement after use
  moonbit_decref(data);    // Decrement byte data
  return result;
}
```

## `Ref[T]` Output Parameters

`Ref[T]` cells let C write values back. Borrow them since C does not retain
the cell — it only writes into it.

```mbt nocheck
///|
#borrow(major, minor, patch)
extern "C" fn __llvm_get_version(
  major : Ref[UInt],
  minor : Ref[UInt],
  patch : Ref[UInt],
) = "LLVMGetVersion"

///|
pub fn llvm_get_version() -> (UInt, UInt, UInt) {
  let major = Ref::new(0U)
  let minor = Ref::new(0U)
  let patch = Ref::new(0U)
  __llvm_get_version(major, minor, patch)
  (major.val, minor.val, patch.val)
}
```

## `moonbit_incref` / `moonbit_decref` Pairing

When C holds a reference to a MoonBit object beyond a single call (e.g., storing
it in a C struct or passing it to a callback later), use `moonbit_incref` to
prevent GC collection:

```c
// Store a MoonBit object in a C struct
void store_callback(MyState *state, void *moonbit_closure) {
  moonbit_incref(moonbit_closure);  // prevent GC
  state->callback = moonbit_closure;
}

// Release when no longer needed
void clear_callback(MyState *state) {
  moonbit_decref(state->callback);  // allow GC
  state->callback = NULL;
}
```

Rules:

- Every `moonbit_incref` must have a matching `moonbit_decref`.
- Incref before storing; decref when the storage is torn down or overwritten.
- When C calls back into MoonBit, the GC may run. Ensure all C-held MoonBit
  objects are incref'd before the callback invocation.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.