Skip to content

Commit

Permalink
Merge pull request #697 from bettio/improve-add_avm_pack_file-return-…
Browse files Browse the repository at this point in the history
…type

Make atomvm:add_avm_pack_file/2 return a meaningful error

This change is required for #657.

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
  • Loading branch information
bettio committed Jul 23, 2023
2 parents ea8fa33 + 876ad70 commit 900b601
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 36 deletions.
39 changes: 36 additions & 3 deletions src/libAtomVM/nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3439,6 +3439,38 @@ static term nif_atomvm_add_avm_pack_binary(Context *ctx, int argc, term argv[])
return OK_ATOM;
}

static term open_avm_error_tuple(Context *ctx, enum OpenAVMResult result)
{
term reason = UNDEFINED_ATOM;
switch (result) {
case AVM_OPEN_FAILED_ALLOC:
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
break;
case AVM_OPEN_INVALID:
reason = globalcontext_make_atom(ctx->global, ATOM_STR("\xB", "invalid_avm"));
break;
case AVM_OPEN_CANNOT_OPEN:
reason = globalcontext_make_atom(ctx->global, ATOM_STR("\xB", "cannot_open"));
break;
case AVM_OPEN_CANNOT_READ:
reason = globalcontext_make_atom(ctx->global, ATOM_STR("\xB", "cannot_read"));
break;
case AVM_OPEN_NOT_SUPPORTED:
reason = globalcontext_make_atom(ctx->global, ATOM_STR("\xD", "not_supported"));
break;
case AVM_OPEN_OK:
__builtin_unreachable();
}
if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2)) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term error_tuple = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(error_tuple, 0, ERROR_ATOM);
term_put_tuple_element(error_tuple, 1, reason);

return error_tuple;
}

// AtomVM extension
static term nif_atomvm_add_avm_pack_file(Context *ctx, int argc, term argv[])
{
Expand All @@ -3457,10 +3489,11 @@ static term nif_atomvm_add_avm_pack_file(Context *ctx, int argc, term argv[])
RAISE_ERROR(BADARG_ATOM);
}

struct AVMPackData *avmpack_data = sys_open_avm_from_file(ctx->global, abs);
if (IS_NULL_PTR(avmpack_data)) {
struct AVMPackData *avmpack_data;
enum OpenAVMResult result = sys_open_avm_from_file(ctx->global, abs, &avmpack_data);
if (UNLIKELY(result != AVM_OPEN_OK)) {
free(abs);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
return open_avm_error_tuple(ctx, result);
}

term name = interop_kv_get_value_default(opts, ATOM_STR("\x4", "name"), UNDEFINED_ATOM, ctx->global);
Expand Down
15 changes: 14 additions & 1 deletion src/libAtomVM/sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,24 @@ extern "C" {
#include <stdint.h>
#include <time.h>

struct AVMPackData;

enum
{
SYS_POLL_EVENTS_DO_NOT_WAIT = 0,
SYS_POLL_EVENTS_WAIT_FOREVER = -1
};

enum OpenAVMResult
{
AVM_OPEN_OK = 0,
AVM_OPEN_FAILED_ALLOC = 1,
AVM_OPEN_INVALID = 2,
AVM_OPEN_CANNOT_OPEN = 3,
AVM_OPEN_CANNOT_READ = 4,
AVM_OPEN_NOT_SUPPORTED = 5
};

/**
* @brief Event listener
*
Expand Down Expand Up @@ -182,7 +194,8 @@ void sys_signal(GlobalContext *glb);

#endif

struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *path);
enum OpenAVMResult sys_open_avm_from_file(
GlobalContext *global, const char *path, struct AVMPackData **data);

/**
* @brief gets wall clock time
Expand Down
10 changes: 6 additions & 4 deletions src/platforms/emscripten/src/lib/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,8 @@ static void *load_or_fetch_file(const char *path, emscripten_fetch_t **fetch, si
return (void *) (*fetch)->data;
}

struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *path)
enum OpenAVMResult sys_open_avm_from_file(
GlobalContext *global, const char *path, struct AVMPackData **avm_data)
{
TRACE("sys_open_avm_from_file: Going to open: %s\n", path);

Expand All @@ -421,7 +422,7 @@ struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *pa
emscripten_fetch_t *fetch = NULL;
void *data = load_or_fetch_file(path, &fetch, NULL);
if (IS_NULL_PTR(data)) {
return NULL;
return AVM_OPEN_CANNOT_OPEN;
}

struct ConstAVMPack *const_avm = malloc(sizeof(struct ConstAVMPack));
Expand All @@ -431,12 +432,13 @@ struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *pa
} else {
free(data);
}
return NULL;
return AVM_OPEN_FAILED_ALLOC;
}
avmpack_data_init(&const_avm->base, &const_avm_pack_info);
const_avm->base.data = (const uint8_t *) data;

return &const_avm->base;
*avm_data = &const_avm->base;
return AVM_OPEN_OK;
}

Module *sys_load_module_from_file(GlobalContext *global, const char *path)
Expand Down
4 changes: 2 additions & 2 deletions src/platforms/emscripten/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ static int load_module(const char *path)
{
const char *ext = strrchr(path, '.');
if (ext && strcmp(ext, ".avm") == 0) {
struct AVMPackData *avmpack_data = sys_open_avm_from_file(global, path);
if (IS_NULL_PTR(avmpack_data)) {
struct AVMPackData *avmpack_data;
if (sys_open_avm_from_file(global, path, &avmpack_data) != AVM_OPEN_OK) {
fprintf(stderr, "Failed opening %s.\n", path);
return EXIT_FAILURE;
}
Expand Down
24 changes: 12 additions & 12 deletions src/platforms/esp32/components/avm_sys/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ static void esp32_part_avm_pack_destructor(struct AVMPackData *obj, GlobalContex
free(obj);
}

struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *path)
enum OpenAVMResult sys_open_avm_from_file(GlobalContext *global, const char *path, struct AVMPackData **data)
{
TRACE("sys_open_avm_from_file: Going to open: %s\n", path);

Expand All @@ -271,16 +271,15 @@ struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *pa
const char *part_name = path + parts_by_name_len;
const void *part_data = esp32_sys_mmap_partition(part_name, &part_handle, &size);
if (IS_NULL_PTR(part_data)) {
return NULL;
return AVM_OPEN_CANNOT_OPEN;
}
if (UNLIKELY(!avmpack_is_valid(part_data, size))) {
return NULL;
return AVM_OPEN_INVALID;
}

struct ESP32PartAVMPack *part_avm = malloc(sizeof(struct ESP32PartAVMPack));
if (IS_NULL_PTR(part_avm)) {
// use esp_partition_munmap
return NULL;
return AVM_OPEN_FAILED_ALLOC;
}
avmpack_data_init(&part_avm->base, &esp32_part_avm_pack_info);
part_avm->base.data = part_data;
Expand All @@ -290,46 +289,47 @@ struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *pa
} else {
struct stat file_stats;
if (UNLIKELY(stat(path, &file_stats) < 0)) {
return NULL;
return AVM_OPEN_CANNOT_OPEN;
}
// check int max
int size = file_stats.st_size;

void *file_data = malloc(size);
if (IS_NULL_PTR(file_data)) {
return NULL;
return AVM_OPEN_FAILED_ALLOC;
}

FILE *avm_file = fopen(path, "r");
if (UNLIKELY(!avm_file)) {
free(file_data);
return NULL;
return AVM_OPEN_CANNOT_OPEN;
}

int bytes_read = fread(file_data, 1, size, avm_file);
fclose(avm_file);

if (UNLIKELY(bytes_read != size)) {
free(file_data);
return NULL;
return AVM_OPEN_CANNOT_READ;
}

if (UNLIKELY(!avmpack_is_valid(file_data, size))) {
free(file_data);
return NULL;
return AVM_OPEN_INVALID;
}

struct InMemoryAVMPack *in_memory_avm = malloc(sizeof(struct InMemoryAVMPack));
if (IS_NULL_PTR(avmpack_data)) {
free(file_data);
return NULL;
return AVM_OPEN_FAILED_ALLOC;
}
avmpack_data_init(&in_memory_avm->base, &in_memory_avm_pack_info);
in_memory_avm->base.data = file_data;
avmpack_data = &in_memory_avm->base;
}

return avmpack_data;
*data = avmpack_data;
return AVM_OPEN_OK;
}

Module *sys_load_module_from_file(GlobalContext *global, const char *path)
Expand Down
14 changes: 7 additions & 7 deletions src/platforms/generic_unix/lib/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,32 +365,32 @@ uint64_t sys_monotonic_millis()
return (ts.tv_nsec / 1000000UL) + (ts.tv_sec * 1000UL);
}

struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *path)
enum OpenAVMResult sys_open_avm_from_file(
GlobalContext *global, const char *path, struct AVMPackData **data)
{
TRACE("sys_open_avm_from_file: Going to open: %s\n", path);

UNUSED(global);

MappedFile *mapped = mapped_file_open_beam(path);
if (IS_NULL_PTR(mapped)) {
return NULL;
return AVM_OPEN_CANNOT_OPEN;
}
if (UNLIKELY(!avmpack_is_valid(mapped->mapped, mapped->size))) {
fprintf(stderr, "%s is not a valid AVM Pack file.\n", path);
return NULL;
return AVM_OPEN_INVALID;
}

struct MappedFileAVMPack *avmpack_data = malloc(sizeof(struct MappedFileAVMPack));
if (IS_NULL_PTR(avmpack_data)) {
fprintf(stderr, "Memory error: Cannot allocate AVMPackData.\n");
mapped_file_close(mapped);
return NULL;
return AVM_OPEN_FAILED_ALLOC;
}
avmpack_data_init(&avmpack_data->base, &mapped_file_avm_pack_info);
avmpack_data->base.data = mapped->mapped;
avmpack_data->mapped = mapped;

return &avmpack_data->base;
*data = &avmpack_data->base;
return AVM_OPEN_OK;
}

static void mapped_file_avm_pack_destructor(struct AVMPackData *obj, GlobalContext *global)
Expand Down
4 changes: 2 additions & 2 deletions src/platforms/generic_unix/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ int main(int argc, char **argv)
for (int i = 1; i < argc; ++i) {
const char *ext = strrchr(argv[i], '.');
if (ext && strcmp(ext, ".avm") == 0) {
struct AVMPackData *avmpack_data = sys_open_avm_from_file(glb, argv[i]);
if (IS_NULL_PTR(avmpack_data)) {
struct AVMPackData *avmpack_data;
if (UNLIKELY(sys_open_avm_from_file(glb, argv[i], &avmpack_data) != AVM_OPEN_OK)) {
fprintf(stderr, "Failed opening %s.\n", argv[i]);
return EXIT_FAILURE;
}
Expand Down
7 changes: 4 additions & 3 deletions src/platforms/rp2040/src/lib/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,14 @@ uint64_t sys_monotonic_millis()
return usec / 1000;
}

struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *path)
enum OpenAVMResult sys_open_avm_from_file(
GlobalContext *global, const char *path, struct AVMPackData **data)
{
UNUSED(global);
UNUSED(path);

// No file support on pico.
return NULL;
// TODO
return AVM_OPEN_NOT_SUPPORTED;
}

Module *sys_load_module_from_file(GlobalContext *global, const char *path)
Expand Down
5 changes: 3 additions & 2 deletions src/platforms/stm32/src/lib/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,13 @@ uint64_t sys_monotonic_millis()
return system_millis;
}

struct AVMPackData *sys_open_avm_from_file(GlobalContext *global, const char *path)
enum OpenAVMResult sys_open_avm_from_file(
GlobalContext *global, const char *path, struct AVMPackData **data)
{
TRACE("sys_open_avm_from_file: Going to open: %s\n", path);

// TODO
return NULL;
return AVM_OPEN_NOT_SUPPORTED;
}

Module *sys_load_module_from_file(GlobalContext *global, const char *path)
Expand Down

0 comments on commit 900b601

Please sign in to comment.