Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/libAtomVM/erl_nif.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,14 @@ int enif_release_resource(void *resource);
* usage confusion, users should rather call `term_from_resource` and should
* not decrement the reference counter.
*
* @deprecated This function aborts on out of memory. Use
* `memory_erl_nif_env_ensure_free` followed by `term_from_resource` instead.
*
* @param env current environment
* @param obj resource
* @return a new term representing the resource
*/
ERL_NIF_TERM enif_make_resource(ErlNifEnv *env, void *obj);
ERL_NIF_TERM enif_make_resource(ErlNifEnv *env, void *obj) __attribute__((deprecated("use memory_erl_nif_env_ensure_free + term_from_resource instead")));

/**
* @brief create a binary term memory managed by a resource.
Expand All @@ -225,13 +228,17 @@ ERL_NIF_TERM enif_make_resource(ErlNifEnv *env, void *obj);
* resource. The resource destructor will only be called when all binaries
* are garbage collected.
*
* @deprecated This function aborts on out of memory. Use
* `memory_erl_nif_env_ensure_free` followed by `term_from_resource_binary`
* instead.
*
* @param env current environment
* @param obj resource
* @param data binary data to encapsulate
* @param size size of the data
* @return a new binary term
*/
ERL_NIF_TERM enif_make_resource_binary(ErlNifEnv *env, void *obj, const void *data, size_t size);
ERL_NIF_TERM enif_make_resource_binary(ErlNifEnv *env, void *obj, const void *data, size_t size) __attribute__((deprecated("use memory_erl_nif_env_ensure_free + term_from_resource_binary instead")));

/**
* @brief Run a POSIX-like select on a given object (event) and send a message
Expand Down
6 changes: 5 additions & 1 deletion src/libAtomVM/jit_stream_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,11 @@ static term nif_jit_stream_flash_new(Context *ctx, int argc, term argv[])
RAISE_ERROR(BADARG_ATOM);
}

term obj = enif_make_resource(erl_nif_env_from_context(ctx), js);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
enif_release_resource(js);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = term_from_resource(js, &ctx->heap);
enif_release_resource(js); // decrement refcount after enif_alloc_resource
return obj;
}
Expand Down
13 changes: 10 additions & 3 deletions src/libAtomVM/otp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ static term nif_socket_open(Context *ctx, int argc, term argv[])
AVM_LOGW(TAG, "Failed to allocate memory: %s:%i.", __FILE__, __LINE__);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = enif_make_resource(erl_nif_env_from_context(ctx), rsrc_obj);
term obj = term_from_resource(rsrc_obj, &ctx->heap);
enif_release_resource(rsrc_obj); // decrement refcount after enif_alloc_resource

size_t requested_size = TUPLE_SIZE(2) + TUPLE_SIZE(2) + REF_SIZE;
Expand Down Expand Up @@ -1814,7 +1814,10 @@ static term nif_socket_listen(Context *ctx, int argc, term argv[])
#if OTP_SOCKET_LWIP
static term make_accepted_socket_term(Context *ctx, struct SocketResource *conn_rsrc_obj)
{
term obj = enif_make_resource(erl_nif_env_from_context(ctx), conn_rsrc_obj);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE + TUPLE_SIZE(2) + REF_SIZE) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = term_from_resource(conn_rsrc_obj, &ctx->heap);
enif_release_resource(conn_rsrc_obj); // decrement refcount after enif_allocate_resource in make_accepted_socket_resource

term socket_term = term_alloc_tuple(2, &ctx->heap);
Expand Down Expand Up @@ -1899,7 +1902,11 @@ static term nif_socket_accept(Context *ctx, int argc, term argv[])
#endif
TRACE("nif_socket_accept: Created socket on accept fd=%i\n", rsrc_obj->fd);

term new_resource = enif_make_resource(erl_nif_env_from_context(ctx), conn_rsrc_obj);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
AVM_LOGW(TAG, "Failed to allocate memory: %s:%i.", __FILE__, __LINE__);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term new_resource = term_from_resource(conn_rsrc_obj, &ctx->heap);
enif_release_resource(conn_rsrc_obj); // decrement refcount after enif_alloc_resource

size_t requested_size = TUPLE_SIZE(2) + TUPLE_SIZE(2) + REF_SIZE;
Expand Down
24 changes: 20 additions & 4 deletions src/libAtomVM/otp_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,11 @@ static term nif_ssl_entropy_init(Context *ctx, int argc, term argv[])
AVM_LOGW(TAG, "Failed to allocate memory: %s:%i.\n", __FILE__, __LINE__);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = enif_make_resource(erl_nif_env_from_context(ctx), rsrc_obj);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
enif_release_resource(rsrc_obj);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = term_from_resource(rsrc_obj, &ctx->heap);
enif_release_resource(rsrc_obj); // decrement refcount after enif_alloc_resource

mbedtls_entropy_init(&rsrc_obj->context);
Expand All @@ -258,7 +262,11 @@ static term nif_ssl_ctr_drbg_init(Context *ctx, int argc, term argv[])
AVM_LOGW(TAG, "Failed to allocate memory: %s:%i.\n", __FILE__, __LINE__);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = enif_make_resource(erl_nif_env_from_context(ctx), rsrc_obj);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
enif_release_resource(rsrc_obj);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = term_from_resource(rsrc_obj, &ctx->heap);
enif_release_resource(rsrc_obj); // decrement refcount after enif_alloc_resource

mbedtls_ctr_drbg_init(&rsrc_obj->context);
Expand Down Expand Up @@ -310,7 +318,11 @@ static term nif_ssl_init(Context *ctx, int argc, term argv[])
AVM_LOGW(TAG, "Failed to allocate memory: %s:%i.\n", __FILE__, __LINE__);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = enif_make_resource(erl_nif_env_from_context(ctx), rsrc_obj);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
enif_release_resource(rsrc_obj);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = term_from_resource(rsrc_obj, &ctx->heap);
enif_release_resource(rsrc_obj); // decrement refcount after enif_alloc_resource

mbedtls_ssl_init(&rsrc_obj->context);
Expand Down Expand Up @@ -363,7 +375,11 @@ static term nif_ssl_config_init(Context *ctx, int argc, term argv[])
AVM_LOGW(TAG, "Failed to allocate memory: %s:%i.\n", __FILE__, __LINE__);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = enif_make_resource(erl_nif_env_from_context(ctx), rsrc_obj);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
enif_release_resource(rsrc_obj);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = term_from_resource(rsrc_obj, &ctx->heap);
enif_release_resource(rsrc_obj); // decrement refcount after enif_alloc_resource

mbedtls_ssl_config_init(&rsrc_obj->config);
Expand Down
8 changes: 6 additions & 2 deletions src/libAtomVM/posix_nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,11 @@ static term make_posix_fd_resource(Context *ctx, int fd)
}
fd_obj->fd = fd;
fd_obj->selecting_process_id = INVALID_PROCESS_ID;
term obj = enif_make_resource(erl_nif_env_from_context(ctx), fd_obj);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
enif_release_resource(fd_obj);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = term_from_resource(fd_obj, &ctx->heap);
enif_release_resource(fd_obj); // decrement refcount after enif_alloc_resource
return obj;
}
Expand Down Expand Up @@ -847,7 +851,7 @@ static term nif_atomvm_posix_opendir(Context *ctx, int argc, term argv[])
!= MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = enif_make_resource(erl_nif_env_from_context(ctx), dir_obj);
term obj = term_from_resource(dir_obj, &ctx->heap);
enif_release_resource(dir_obj); // decrement refcount after enif_alloc_resource
result = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(result, 0, OK_ATOM);
Expand Down
17 changes: 9 additions & 8 deletions src/libAtomVM/resources.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,17 @@ int enif_release_resource(void *resource)
return true;
}

// Suppress deprecation warning for the implementation
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
ERL_NIF_TERM enif_make_resource(ErlNifEnv *env, void *obj)
{
if (UNLIKELY(memory_erl_nif_env_ensure_free(env, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
AVM_ABORT();
}
return term_from_resource(obj, &env->heap);
}
#pragma GCC diagnostic pop

static void enif_select_event_message_dispose(Message *message, GlobalContext *global, bool from_task)
{
Expand Down Expand Up @@ -631,16 +635,13 @@ const ErlNifResourceTypeInit resource_binary_resource_type_init = {
.dtor = resource_binary_dtor,
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
ERL_NIF_TERM enif_make_resource_binary(ErlNifEnv *env, void *obj, const void *data, size_t size)
{
if (UNLIKELY(memory_erl_nif_env_ensure_free(env, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
if (UNLIKELY(memory_erl_nif_env_ensure_free(env, TERM_BOXED_REFC_BINARY_SIZE) != MEMORY_GC_OK)) {
AVM_ABORT();
}
struct ResourceBinary *resource_binary = enif_alloc_resource(env->global->resource_binary_resource_type, sizeof(struct ResourceBinary));
resource_binary->managing_resource = refc_binary_from_data(obj);
resource_binary->data = data;

term result = term_from_resource_binary_pointer(resource_binary, size, &env->heap);
refc_binary_decrement_refcount(refc_binary_from_data(resource_binary), env->global);
return result;
return term_from_resource_binary(obj, data, size, &env->heap, env->global);
}
#pragma GCC diagnostic pop
12 changes: 9 additions & 3 deletions src/libAtomVM/term.c
Original file line number Diff line number Diff line change
Expand Up @@ -1373,9 +1373,13 @@ term term_from_resource_type_and_serialize_ref(uint64_t resource_type_ptr, uint6
return term_from_ref_ticks(ref_ticks, heap);
}

term term_from_resource_binary_pointer(struct ResourceBinary *resource, size_t size, Heap *heap)
term term_from_resource_binary(void *obj, const void *data, size_t size, Heap *heap, GlobalContext *glb)
{
struct RefcBinary *refc = refc_binary_from_data(resource);
struct ResourceBinary *resource_binary = enif_alloc_resource(glb->resource_binary_resource_type, sizeof(struct ResourceBinary));
resource_binary->managing_resource = refc_binary_from_data(obj);
resource_binary->data = data;

struct RefcBinary *refc = refc_binary_from_data(resource_binary);
term *boxed_value = memory_heap_alloc(heap, TERM_BOXED_REFC_BINARY_SIZE);
boxed_value[0] = ((TERM_BOXED_REFC_BINARY_SIZE - 1) << 6) | TERM_BOXED_REFC_BINARY;
boxed_value[1] = (term) size;
Expand All @@ -1385,6 +1389,8 @@ term term_from_resource_binary_pointer(struct ResourceBinary *resource, size_t s
// Add the resource to the mso list
refc->ref_count++;
heap->root->mso_list = term_list_init_prepend(boxed_value + REFC_BINARY_CONS_OFFSET, ret, heap->root->mso_list);
refc_binary_increment_refcount(resource->managing_resource);
refc_binary_increment_refcount(resource_binary->managing_resource);

refc_binary_decrement_refcount(refc, glb);
return ret;
}
6 changes: 3 additions & 3 deletions src/libAtomVM/term.h
Original file line number Diff line number Diff line change
Expand Up @@ -3012,14 +3012,14 @@ term term_from_resource_type_and_serialize_ref(uint64_t resource_type_ptr, uint6
* @details Increment reference count of resource and create a refc binary for
* the pointer and size.
*
* @param resource the resource managing the binary
* @param obj the managing resource object
* @param data the pointer to the data
* @param size the size of the binary
* @param heap the heap to allocate memory in
* @param glb the global context
* @return a refc binary
* @return a binary term managed by obj
*/
term term_from_resource_binary_pointer(struct ResourceBinary *resource, size_t size, Heap *heap);
term term_from_resource_binary(void *obj, const void *data, size_t size, Heap *heap, GlobalContext *glb);

#ifdef __cplusplus
}
Expand Down
6 changes: 5 additions & 1 deletion src/platforms/emscripten/src/lib/platform_nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,11 @@ static EM_BOOL html5api_touch_callback(int eventType, const EmscriptenTouchEvent
enif_release_resource(resource); \
return term_from_emscripten_result(result, ctx); \
} \
term resource_term = enif_make_resource(erl_nif_env_from_context(ctx), resource); \
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) { \
enif_release_resource(resource); \
RAISE_ERROR(OUT_OF_MEMORY_ATOM); \
} \
term resource_term = term_from_resource(resource, &ctx->heap); \
enif_release_resource(resource); \
if (UNLIKELY(memory_ensure_free_with_roots(ctx, TUPLE_SIZE(3), 1, &resource_term, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { \
RAISE_ERROR(OUT_OF_MEMORY_ATOM); \
Expand Down
4 changes: 2 additions & 2 deletions src/platforms/esp32/components/avm_builtins/adc_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ static term nif_adc_init(Context *ctx, int argc, term argv[])
ESP_LOGE(TAG, "failed to allocate memory for resource: %s:%i.", __FILE__, __LINE__);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
ERL_NIF_TERM unit_obj = enif_make_resource(erl_nif_env_from_context(ctx), unit_rsrc);
ERL_NIF_TERM unit_obj = term_from_resource(unit_rsrc, &ctx->heap);
enif_release_resource(unit_rsrc); // decrement refcount after enif_alloc_resource

// {ok, {'$adc', Unit :: resource(), ref()}}
Expand Down Expand Up @@ -500,7 +500,7 @@ static term nif_adc_acquire(Context *ctx, int argc, term argv[])
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}

term chan_obj = enif_make_resource(erl_nif_env_from_context(ctx), chan_rsrc);
term chan_obj = term_from_resource(chan_rsrc, &ctx->heap);
enif_release_resource(chan_rsrc); // decrement refcount after enif_alloc_resource

// {ok, {'$adc', resource(), ref()}}
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/esp32/components/avm_builtins/dac_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static term nif_oneshot_new_channel_p(Context *ctx, int argc, term argv[])
enif_release_resource(chan_rsrc);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
ERL_NIF_TERM chan_obj = enif_make_resource(erl_nif_env_from_context(ctx), chan_rsrc);
ERL_NIF_TERM chan_obj = term_from_resource(chan_rsrc, &ctx->heap);

const dac_oneshot_config_t config = {
.chan_id = term_to_uint8(argv[0])
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/esp32/components/avm_builtins/i2c_resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ static term nif_i2c_open(Context *ctx, int argc, term argv[])
ESP_LOGW(TAG, "Failed to allocate memory: %s:%i.", __FILE__, __LINE__);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = enif_make_resource(erl_nif_env_from_context(ctx), rsrc_obj);
term obj = term_from_resource(rsrc_obj, &ctx->heap);
enif_release_resource(rsrc_obj);

//
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/esp32/components/avm_builtins/storage_nif.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ static term nif_esp_mount(Context *ctx, int argc, term argv[])
enif_release_resource(mount);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term mount_term = enif_make_resource(erl_nif_env_from_context(ctx), mount);
term mount_term = term_from_resource(mount, &ctx->heap);
return_term = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(return_term, 0, OK_ATOM);
term_put_tuple_element(return_term, 1, mount_term);
Expand Down
7 changes: 5 additions & 2 deletions src/platforms/esp32/components/avm_sys/platform_nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,11 @@ static term nif_esp_partition_mmap(Context *ctx, int argc, term argv[])
return ERROR_ATOM;
}

ErlNifEnv *env = erl_nif_env_from_context(ctx);
ERL_NIF_TERM binary = enif_make_resource_binary(env, handle, mmap_ptr, size);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFC_BINARY_SIZE) != MEMORY_GC_OK)) {
enif_release_resource(handle);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
ERL_NIF_TERM binary = term_from_resource_binary(handle, mmap_ptr, size, &ctx->heap, ctx->global);
enif_release_resource(handle);

if (UNLIKELY(memory_ensure_free_with_roots(ctx, TUPLE_SIZE(2), 1, &binary, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
Expand Down
6 changes: 5 additions & 1 deletion src/platforms/generic_unix/lib/jit_stream_mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ static term nif_jit_stream_mmap_new(Context *ctx, int argc, term argv[])
js->stream_offset = 0;
js->stream_size = size;

term obj = enif_make_resource(erl_nif_env_from_context(ctx), js);
if (UNLIKELY(memory_ensure_free(ctx, TERM_BOXED_REFERENCE_RESOURCE_SIZE) != MEMORY_GC_OK)) {
enif_release_resource(js);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term obj = term_from_resource(js, &ctx->heap);
enif_release_resource(js); // decrement refcount after enif_alloc_resource
return obj;
}
Expand Down
13 changes: 9 additions & 4 deletions tests/test-enif.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "erl_nif_priv.h"
#include "external_term.h"
#include "globalcontext.h"
#include "memory.h"
#include "scheduler.h"
#include "utils.h"

Expand Down Expand Up @@ -114,7 +115,8 @@ void test_resource(void)
uint32_t *resource = (uint32_t *) ptr;
*resource = 42;

ERL_NIF_TERM resource_term = enif_make_resource(env, ptr);
assert(memory_erl_nif_env_ensure_free(env, TERM_BOXED_REFERENCE_RESOURCE_SIZE) == MEMORY_GC_OK);
ERL_NIF_TERM resource_term = term_from_resource(ptr, &env->heap);
assert(term_is_reference(resource_term));
assert(term_is_resource_reference(resource_term));

Expand Down Expand Up @@ -475,7 +477,8 @@ void test_resource_binary(void)
uint32_t *resource = (uint32_t *) ptr;
*resource = 42;

ERL_NIF_TERM binary = enif_make_resource_binary(env, ptr, "hello", 5);
assert(memory_erl_nif_env_ensure_free(env, TERM_BOXED_REFC_BINARY_SIZE) == MEMORY_GC_OK);
ERL_NIF_TERM binary = term_from_resource_binary(ptr, "hello", 5, &env->heap, env->global);
assert(term_is_binary(binary));
assert(term_is_refc_binary(binary));
assert(term_binary_size(binary) == 5);
Expand Down Expand Up @@ -548,15 +551,17 @@ void test_resource_binaries(void)
uint32_t *resource = (uint32_t *) ptr;
*resource = 42;

ERL_NIF_TERM binary1 = enif_make_resource_binary(env1, ptr, "hello", 5);
assert(memory_erl_nif_env_ensure_free(env1, TERM_BOXED_REFC_BINARY_SIZE) == MEMORY_GC_OK);
ERL_NIF_TERM binary1 = term_from_resource_binary(ptr, "hello", 5, &env1->heap, env1->global);
assert(term_is_binary(binary1));
assert(term_is_refc_binary(binary1));
assert(term_binary_size(binary1) == 5);
assert(memcmp(term_binary_data(binary1), "hello", 5) == 0);

assert(cb_read_resource == 0);

ERL_NIF_TERM binary2 = enif_make_resource_binary(env2, ptr, "world", 5);
assert(memory_erl_nif_env_ensure_free(env2, TERM_BOXED_REFC_BINARY_SIZE) == MEMORY_GC_OK);
ERL_NIF_TERM binary2 = term_from_resource_binary(ptr, "world", 5, &env2->heap, env2->global);
assert(term_is_binary(binary2));
assert(term_is_refc_binary(binary2));
assert(term_binary_size(binary2) == 5);
Expand Down
Loading