diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index f115542be..aeae5644b 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -39,7 +39,7 @@ concurrency: jobs: analyze: name: Analyze - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: actions: read contents: read @@ -61,7 +61,7 @@ jobs: uses: actions/checkout@v4 - name: "Initialize CodeQL" - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +./code-queries/term-to-non-term-func.ql,./code-queries/non-term-to-term-func.ql @@ -74,4 +74,4 @@ jobs: ninja - name: "Perform CodeQL Analysis" - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/esp32-build.yaml b/.github/workflows/esp32-build.yaml index e908ee804..aaae4d58b 100644 --- a/.github/workflows/esp32-build.yaml +++ b/.github/workflows/esp32-build.yaml @@ -29,7 +29,7 @@ concurrency: jobs: esp-idf: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: espressif/idf:${{ matrix.idf-version }} strategy: @@ -39,15 +39,16 @@ jobs: esp-idf-target: ["esp32", "esp32c3"] idf-version: - 'v5.0.7' - - 'v5.1.4' - - 'v5.2.2' - - 'v5.3.1' + - 'v5.1.5' + - 'v5.2.3' + - 'v5.3.2' + - 'v5.4' exclude: - esp-idf-target: "esp32c3" idf-version: 'v5.0.7' - esp-idf-target: "esp32c3" - idf-version: 'v5.1.4' + idf-version: 'v5.1.5' steps: - name: Checkout repo uses: actions/checkout@v4 diff --git a/.github/workflows/esp32-mkimage.yaml b/.github/workflows/esp32-mkimage.yaml index 8fd1c6d93..74e52698d 100644 --- a/.github/workflows/esp32-mkimage.yaml +++ b/.github/workflows/esp32-mkimage.yaml @@ -37,7 +37,7 @@ jobs: strategy: matrix: - idf-version: ["5.3.1"] + idf-version: ["5.3.2"] cc: ["clang-14"] cxx: ["clang++-14"] cflags: ["-O3"] diff --git a/.github/workflows/esp32-simtest.yaml b/.github/workflows/esp32-simtest.yaml index ea75c05c5..0fa7059fe 100644 --- a/.github/workflows/esp32-simtest.yaml +++ b/.github/workflows/esp32-simtest.yaml @@ -59,13 +59,26 @@ jobs: fail-fast: false # focus on device diversity. matrix: - esp-idf-target: ["esp32", "esp32s2", "esp32s3", "esp32c3", "esp32c6"] - idf-version: ${{ ((contains(github.event.head_commit.message, 'full_sim_test')||contains(github.event.pull_request.title, 'full_sim_test')) && fromJSON('["v5.1.5", "v5.2.3", "v5.3.2", "v5.4-beta1"]')) || fromJSON('["v5.3.2"]') }} - include: + esp-idf-target: + [ + "esp32", + "esp32s2", + "esp32s3", + "esp32c3", + "esp32c6", + "esp32h2", + "esp32p4", + ] + idf-version: ${{ ((contains(github.event.head_commit.message, 'full_sim_test')||contains(github.event.pull_request.title, 'full_sim_test')) && fromJSON('["v5.1.5", "v5.2.3", "v5.3.2", "v5.4"]')) || fromJSON('["v5.3.2"]') }} + exclude: - esp-idf-target: "esp32p4" - idf-version: "v5.3.2" + idf-version: "v5.1.5" + - esp-idf-target: "esp32p4" + idf-version: "v5.2.3" + - esp-idf-target: "esp32h2" + idf-version: "v5.1.5" - esp-idf-target: "esp32h2" - idf-version: "v5.3.2" + idf-version: "v5.2.3" steps: - name: Checkout repo diff --git a/.github/workflows/pico-build.yaml b/.github/workflows/pico-build.yaml index 879fe3568..01963ed55 100644 --- a/.github/workflows/pico-build.yaml +++ b/.github/workflows/pico-build.yaml @@ -33,7 +33,7 @@ concurrency: jobs: pico: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: board: ["pico", "pico_w", "pico2"] diff --git a/.github/workflows/reuse-lint.yaml b/.github/workflows/reuse-lint.yaml index ed63ea86a..cf5e72a31 100644 --- a/.github/workflows/reuse-lint.yaml +++ b/.github/workflows/reuse-lint.yaml @@ -12,7 +12,7 @@ concurrency: jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: REUSE Compliance Check diff --git a/.github/workflows/stm32-build.yaml b/.github/workflows/stm32-build.yaml index b33fcccb0..feacf4985 100644 --- a/.github/workflows/stm32-build.yaml +++ b/.github/workflows/stm32-build.yaml @@ -44,17 +44,6 @@ jobs: https://repo.hex.pm https://cdn.jsdelivr.net/hex - - name: Install arm-embedded toolchain - if: ${{ steps.builddeps-cache.outputs.cache-hit != 'true' }} - working-directory: /home/runner - run: | - set -euo pipefail - cd /home/runner - wget https://developer.arm.com/-/media/Files/downloads/gnu/11.3.rel1/binrel/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi.tar.xz \ - --output-document=$RUNNER_TEMP/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi.tar.xz - tar xJf $RUNNER_TEMP/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi.tar.xz - pwd && ls - - name: Checkout and build libopencm3 if: ${{ steps.builddeps-cache.outputs.cache-hit != 'true' }} working-directory: /home/runner @@ -71,7 +60,7 @@ jobs: run: sudo apt update - name: "Install deps" - run: sudo apt install -y cmake gperf + run: sudo apt install -y cmake gperf gcc-arm-none-eabi - name: Checkout repo uses: actions/checkout@v4 diff --git a/.github/workflows/wasm-build.yaml b/.github/workflows/wasm-build.yaml index 58fbf84f4..a9164698e 100644 --- a/.github/workflows/wasm-build.yaml +++ b/.github/workflows/wasm-build.yaml @@ -78,7 +78,7 @@ jobs: wasm_build_and_test_node: needs: compile_tests - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: emscripten/emsdk steps: - name: Checkout repo @@ -146,7 +146,7 @@ jobs: src/platforms/emscripten/build/src/AtomVM-node-${{ github.ref_name }}.wasm.sha256 wasm_build_web: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: emscripten/emsdk steps: - name: Checkout repo @@ -176,7 +176,7 @@ jobs: wasm_test_web: needs: [compile_tests, wasm_build_web] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repo uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e4b68ed5..e7c10dae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,9 @@ certain VM instructions are used. - Fixed an issue where a timeout would occur immediately in a race condition - Fixed SPI close command - Added missing lock on socket structure +- Fixed a race condition affecting multi-core MCUs where a timeout would not be properly cleared +- Fixed a double free when esp32 uart driver was closed, yielding an assert abort +- Fixed compilation with latest debian gcc-arm-none-eabi ## [0.6.5] - 2024-10-15 diff --git a/doc/release-notes.md.in b/doc/release-notes.md.in index f3f46540d..1de96f072 100644 --- a/doc/release-notes.md.in +++ b/doc/release-notes.md.in @@ -68,9 +68,10 @@ AtomVM currently supports the following versions of ESP-IDF: | IDF SDK supported versions | AtomVM support | |------------------------------|----------------| | ESP-IDF [v5.0](https://docs.espressif.com/projects/esp-idf/en/v5.0.7/esp32/get-started/index.html) | ✅ | -| ESP-IDF [v5.1](https://docs.espressif.com/projects/esp-idf/en/v5.1.4/esp32/get-started/index.html) | ✅ | -| ESP-IDF [v5.2](https://docs.espressif.com/projects/esp-idf/en/v5.2.2/esp32/get-started/index.html) | ✅ | -| ESP-IDF [v5.3](https://docs.espressif.com/projects/esp-idf/en/v5.3/esp32/get-started/index.html) | ✅ | +| ESP-IDF [v5.1](https://docs.espressif.com/projects/esp-idf/en/v5.1.5/esp32/get-started/index.html) | ✅ | +| ESP-IDF [v5.2](https://docs.espressif.com/projects/esp-idf/en/v5.2.3/esp32/get-started/index.html) | ✅ | +| ESP-IDF [v5.3](https://docs.espressif.com/projects/esp-idf/en/v5.3.2/esp32/get-started/index.html) | ✅ | +| ESP-IDF [v5.4](https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/get-started/index.html) | ✅ | Building the AtomVM virtual machine for ESP32 is optional. In most cases, you can simply download a release image from the AtomVM [release](https://github.com/atomvm/AtomVM/releases) repository. If you wish to work on development of the VM or use one on the additional drivers that are available in the [AtomVM repositories](https://github.com/atomvm) you will to build AtomVM from source. See the [Build Instructions](build-instructions.md) for information about how to build AtomVM from source code. We recommend you to use the latest subminor (patch) versions for source builds. You can check the current version used for testing in the [esp32-build.yaml](https://github.com/atomvm/AtomVM/actions/workflows/esp32-build.yaml) workflow. diff --git a/src/libAtomVM/context.c b/src/libAtomVM/context.c index df2f142c4..16dd955bc 100644 --- a/src/libAtomVM/context.c +++ b/src/libAtomVM/context.c @@ -178,9 +178,7 @@ void context_destroy(Context *ctx) // globalcontext_get_process_lock before accessing platform_data. // Here, the context can no longer be acquired with // globalcontext_get_process_lock, so it's safe to free the pointer. - if (ctx->platform_data) { - free(ctx->platform_data); - } + free(ctx->platform_data); ets_delete_owned_tables(&ctx->global->ets, ctx->process_id, ctx->global); diff --git a/src/libAtomVM/scheduler.c b/src/libAtomVM/scheduler.c index 21f1d7d75..ce97bbb16 100644 --- a/src/libAtomVM/scheduler.c +++ b/src/libAtomVM/scheduler.c @@ -414,11 +414,11 @@ void scheduler_cancel_timeout(Context *ctx) { GlobalContext *glb = ctx->global; - context_update_flags(ctx, ~(WaitingTimeout | WaitingTimeoutExpired), NoFlags); - struct TimerList *tw = &glb->timer_list; SMP_SPINLOCK_LOCK(&glb->timer_spinlock); timer_list_remove(tw, &ctx->timer_list_head); SMP_SPINLOCK_UNLOCK(&glb->timer_spinlock); + + context_update_flags(ctx, ~(WaitingTimeout | WaitingTimeoutExpired), NoFlags); } diff --git a/src/libAtomVM/term.h b/src/libAtomVM/term.h index e70c80330..023a43a6e 100644 --- a/src/libAtomVM/term.h +++ b/src/libAtomVM/term.h @@ -28,6 +28,9 @@ #ifndef _TERM_H_ #define _TERM_H_ +// gcc-arm-none-eabi 13.2.1 with newlib requires this first +#include + #include #include #include diff --git a/src/platforms/esp32/components/avm_builtins/uart_driver.c b/src/platforms/esp32/components/avm_builtins/uart_driver.c index 22f9ed398..8f141d77b 100644 --- a/src/platforms/esp32/components/avm_builtins/uart_driver.c +++ b/src/platforms/esp32/components/avm_builtins/uart_driver.c @@ -309,7 +309,7 @@ static void uart_driver_do_read(Context *ctx, GenMessage gen_message) int local_pid = term_to_local_process_id(pid); if (uart_data->reader_process_pid != term_invalid_term()) { - if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2) * 2 + REF_SIZE) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, TUPLE_SIZE(2) * 2 , 1, &ref, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { ESP_LOGE(TAG, "[uart_driver_do_read] Failed to allocate space for error tuple"); globalcontext_send_message(glb, local_pid, MEMORY_ATOM); return; @@ -326,7 +326,7 @@ static void uart_driver_do_read(Context *ctx, GenMessage gen_message) if (count > 0) { int bin_size = term_binary_heap_size(count); - if (UNLIKELY(memory_ensure_free(ctx, bin_size + TUPLE_SIZE(2) * 2 + REF_SIZE) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, bin_size + TUPLE_SIZE(2) * 2, 1, &ref, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { ESP_LOGE(TAG, "[uart_driver_do_read] Failed to allocate space for return value"); globalcontext_send_message(glb, local_pid, MEMORY_ATOM); } @@ -387,7 +387,7 @@ static void uart_driver_do_write(Context *ctx, GenMessage gen_message) free(buffer); int local_pid = term_to_local_process_id(pid); - if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2) + REF_SIZE) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, TUPLE_SIZE(2), 1, &ref, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { ESP_LOGE(TAG, "[uart_driver_do_write] Failed to allocate space for return value"); globalcontext_send_message(glb, local_pid, MEMORY_ATOM); } @@ -406,7 +406,7 @@ static void uart_driver_do_close(Context *ctx, GenMessage gen_message) sys_unregister_listener(glb, &uart_data->listener); - if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2) + REF_SIZE) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, TUPLE_SIZE(2), 1, &ref, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { ESP_LOGE(TAG, "[uart_driver_do_close] Failed to allocate space for return value"); globalcontext_send_message(glb, local_pid, MEMORY_ATOM); } @@ -419,6 +419,7 @@ static void uart_driver_do_close(Context *ctx, GenMessage gen_message) } free(uart_data); + ctx->platform_data = NULL; } static NativeHandlerResult uart_driver_consume_mailbox(Context *ctx) diff --git a/src/platforms/esp32/components/avm_sys/sys.c b/src/platforms/esp32/components/avm_sys/sys.c index f8226c3ee..d300138c8 100644 --- a/src/platforms/esp32/components/avm_sys/sys.c +++ b/src/platforms/esp32/components/avm_sys/sys.c @@ -586,12 +586,12 @@ static void *select_thread_loop(void *arg) { GlobalContext *glb = arg; struct ESP32PlatformData *platform = glb->platform_data; - struct pollfd *fds = malloc(0); + struct pollfd *fds = NULL; while (!platform->select_thread_exit) { int select_events_poll_count = platform->select_events_poll_count; int poll_count = 1; int fd_index; - if (select_events_poll_count < 0) { + if (fds == NULL || select_events_poll_count < 0) { // Means it is dirty and should be rebuilt. struct ListHead *select_events = synclist_wrlock(&glb->select_events); size_t select_events_new_count; @@ -601,7 +601,11 @@ static void *select_thread_loop(void *arg) select_events_new_count = select_events_poll_count; } - fds = realloc(fds, sizeof(struct pollfd) * (poll_count + select_events_new_count)); + if (fds) { + fds = realloc(fds, sizeof(struct pollfd) * (poll_count + select_events_new_count)); + } else { + fds = malloc(sizeof(struct pollfd) * (poll_count + select_events_new_count)); + } fds[0].fd = platform->signal_fd; fds[0].events = POLLIN;