Stage 3 — Ownership

Copy Markdown View Source

Verdict on this Mac: PASS, with the limits below. Linux: PENDING.

Mojoler.Own registers three resource types plus a pin type, in load. unload destroys the mutex and frees the private box. The upgrade callback returns 1. No test performed an OTP upgrade.

ObjectAllocatorOwnerFreed by
Counter / blob / retained / pin objectenif_alloc_resourceBEAM resource refcountresource destructor after the last ref
Blob bytescallocthe blob resourcefree in blob_dtor
Retained termenif_alloc_env plus enif_make_copythe retained resourceenif_free_env in retained_dtor
Entry and function tablecallocOTP, after nif_initnot freed; bounded by the reload refusal

counter_add takes the module mutex. Close is idempotent. A closed counter returns {:error, :closed}. The destructor sends :counter_destroyed once. Twenty concurrent adds of 1 land on 20.

open_blob copies the input into a calloc buffer and stores a token. blob_poke writes that buffer in place. The token does not change. Freeze fails while borrows != 0, then enif_make_resource_binary publishes the same bytes. A second freeze is {:error, :frozen}. Poke after freeze is {:error, :not_mutable}. Closing the handle leaves an already created resource binary readable.

blob_pin calls enif_keep_resource. Dropping the blob term does not run blob_dtor while the pin term is alive. Dropping the pin does. blob_dtors/0 is the counter.

retain_binary copies into an independent env. The test reads <<9, 8, 7>> after the creating process has exited.

Elixir functions return terms. They do not return pointers. A strict no-copy request on a non-binary is Mojoler.Dsl.Bytes.borrow_len/1, which returns {:error, :not_binary}.

scripts/probe-abort.sh runs abort in a child BEAM (E26). That path is not in the product libraries.