Skip to content

Commit 2f3c830

Browse files
committed
Allow to run beams on CLI on generic_unix
Also fix a memory leak where modules were not properly destroyed when the global context is destroyed Signed-off-by: Paul Guyot <pguyot@kallisys.net>
1 parent a6d2baf commit 2f3c830

File tree

6 files changed

+42
-28
lines changed

6 files changed

+42
-28
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [0.6.6] - Unreleased
88

9+
### Added
10+
11+
- Added the ability to run beams from the CLI for Generic Unix platform (it was already possible with nodejs and emscripten).
12+
913
### Fixed
1014

1115
- Fixed specifications of nifs from `esp_adc` module
@@ -14,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1418
might lead to a crash in certain situations.
1519
- Fixed several bugs in `http_server` (#1366)
1620
- Fixed generic\_unix `socket_driver` to return `{gen_tcp, closed}` when socket is closed on Linux instead of `{gen_tcp, {recv, 104}}`
21+
- Fixed a memory leak where modules were not properly destroyed when the global context is destroyd
1722

1823
## [0.6.5] - 2024-10-15
1924

src/libAtomVM/globalcontext.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ COLD_FUNC void globalcontext_destroy(GlobalContext *glb)
194194
struct ListHead *item;
195195
struct ListHead *tmp;
196196

197+
int module_index = glb->loaded_modules_count;
198+
for (int i = 0; i < module_index; i++) {
199+
module_destroy(glb->modules_by_index[i]);
200+
}
201+
197202
struct ListHead *open_avm_packs = synclist_nolock(&glb->avmpack_data);
198203
MUTABLE_LIST_FOR_EACH (item, tmp, open_avm_packs) {
199204
struct AVMPackData *avmpack_data = GET_LIST_ENTRY(item, struct AVMPackData, avmpack_head);
@@ -622,6 +627,9 @@ Module *globalcontext_get_module(GlobalContext *global, AtomString module_name_a
622627
free(module_name);
623628

624629
if (UNLIKELY(!loaded_module || (globalcontext_insert_module(global, loaded_module) < 0))) {
630+
if (loaded_module) {
631+
module_destroy(loaded_module);
632+
}
625633
return NULL;
626634
}
627635

src/libAtomVM/globalcontext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ term globalcontext_existing_term_from_atom_string(GlobalContext *glb, AtomString
435435
/**
436436
* @brief Inserts a module to the modules table.
437437
*
438-
* @details Inserts an already loaded module to the modules table and assigns and index to it so it can be retrieved later by name or index.
438+
* @details Inserts an already loaded module to the modules table and assigns and index to it so it can be retrieved later by name or index. The module is then owned by the global context that will destroy it when globalcontext_destroy is invoked.
439439
* @param global the global context.
440440
* @param module the module that will be added to the modules table.
441441
* @returns the module index if successful, otherwise -1.

src/platforms/emscripten/src/main.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ int main(int argc, char **argv)
182182
global = NULL;
183183

184184
if (main_module) {
185-
module_destroy(main_module);
186185
main_module = NULL;
187186
}
188187

src/platforms/generic_unix/main.c

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ void print_help(const char *program_name)
4646
"\n"
4747
"Syntax:\n"
4848
"\n"
49-
" %s [-h] [-v] <path-to-avm-file>+\n"
49+
" %s [-h] [-v] <path-to-avm-or-beam-file>+\n"
5050
"\n"
5151
"Options:\n"
5252
"\n"
@@ -88,9 +88,7 @@ int main(int argc, char **argv)
8888

8989
GlobalContext *glb = globalcontext_new();
9090

91-
const void *startup_beam = NULL;
92-
uint32_t startup_beam_size;
93-
const char *startup_module_name;
91+
Module *startup_module = NULL;
9492

9593
for (int i = 1; i < argc; ++i) {
9694
const char *ext = strrchr(argv[i], '.');
@@ -102,50 +100,56 @@ int main(int argc, char **argv)
102100
}
103101
synclist_append(&glb->avmpack_data, &avmpack_data->avmpack_head);
104102

105-
if (IS_NULL_PTR(startup_beam)) {
103+
if (IS_NULL_PTR(startup_module)) {
104+
const void *startup_beam = NULL;
105+
const char *startup_module_name;
106+
uint32_t startup_beam_size;
106107
avmpack_find_section_by_flag(avmpack_data->data, 1, &startup_beam, &startup_beam_size, &startup_module_name);
107108

108109
if (startup_beam) {
109110
avmpack_data->in_use = true;
111+
startup_module = module_new_from_iff_binary(glb, startup_beam, startup_beam_size);
112+
if (IS_NULL_PTR(startup_module)) {
113+
fprintf(stderr, "Cannot load startup module: %s\n", startup_module_name);
114+
return EXIT_FAILURE;
115+
}
116+
globalcontext_insert_module(glb, startup_module);
117+
startup_module->module_platform_data = NULL;
110118
}
111119
}
112120

113-
} else if (i == 1 && ext && (strcmp(ext, ".beam") == 0)) {
121+
} else if (ext && (strcmp(ext, ".beam") == 0)) {
114122
MappedFile *mapped_file = mapped_file_open_beam(argv[i]);
115123
if (!iff_is_valid_beam(mapped_file->mapped)) {
116-
fprintf(stderr, "%s has invalid AVM Pack format.\n", argv[i]);
124+
fprintf(stderr, "%s has invalid beam format.\n", argv[i]);
117125
return EXIT_FAILURE;
118126
}
119-
startup_module_name = basename(argv[1]);
120-
startup_beam = mapped_file->mapped;
121-
startup_beam_size = mapped_file->size;
122-
123-
} else if (i == 1) {
124-
fprintf(stderr, "%s is not an AVM or a BEAM file.\n", argv[i]);
125-
return EXIT_FAILURE;
127+
Module *mod = module_new_from_iff_binary(glb, mapped_file->mapped, mapped_file->size);
128+
if (IS_NULL_PTR(mod)) {
129+
fprintf(stderr, "Cannot load module: %s\n", argv[i]);
130+
return EXIT_FAILURE;
131+
}
132+
globalcontext_insert_module(glb, mod);
133+
mod->module_platform_data = NULL;
134+
if (IS_NULL_PTR(startup_module) && module_search_exported_function(mod, ATOM_STR("\5", "start"), 0, glb) != 0) {
135+
startup_module = mod;
136+
}
126137

127138
} else {
128-
fprintf(stderr, "%s is not an AVM file.\n", argv[i]);
139+
fprintf(stderr, "%s is not an AVM or a BEAM file.\n", argv[i]);
129140
return EXIT_FAILURE;
130141
}
131142
}
132143

133-
if (IS_NULL_PTR(startup_beam)) {
144+
if (IS_NULL_PTR(startup_module)) {
134145
fprintf(stderr, "Unable to locate entrypoint.\n");
135146
return EXIT_FAILURE;
136147
}
137148

138-
Module *mod = module_new_from_iff_binary(glb, startup_beam, startup_beam_size);
139-
if (IS_NULL_PTR(mod)) {
140-
fprintf(stderr, "Cannot load startup module: %s\n", startup_module_name);
141-
return EXIT_FAILURE;
142-
}
143-
globalcontext_insert_module(glb, mod);
144-
mod->module_platform_data = NULL;
145149
Context *ctx = context_new(glb);
146150
ctx->leader = 1;
147151

148-
context_execute_loop(ctx, mod, "start", 0);
152+
context_execute_loop(ctx, startup_module, "start", 0);
149153

150154
term ret_value = ctx->x[0];
151155
fprintf(stderr, "Return value: ");
@@ -161,7 +165,6 @@ int main(int argc, char **argv)
161165

162166
context_destroy(ctx);
163167
globalcontext_destroy(glb);
164-
module_destroy(mod);
165168

166169
return status;
167170
}

tests/test.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,6 @@ static int test_atom(struct Test *test)
608608

609609
context_destroy(ctx);
610610
globalcontext_destroy(glb);
611-
module_destroy(mod);
612611
mapped_file_close(beam_file);
613612
return result;
614613
}

0 commit comments

Comments
 (0)