diff --git a/components/console/commands.c b/components/console/commands.c index a07e743e12..b3bb082c6d 100644 --- a/components/console/commands.c +++ b/components/console/commands.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -376,7 +376,18 @@ esp_err_t esp_console_register_help_command(void) .argtable = &help_args }; return esp_console_cmd_register(&command); + return ESP_OK; } + +esp_err_t esp_console_deregister_help_command(void) +{ + free(help_args.help_cmd); + free(help_args.verbose_level); + free(help_args.end); + + return esp_console_cmd_deregister("help"); +} + esp_err_t esp_console_set_help_verbose_level(esp_console_help_verbose_level_e verbose_level) { /* legal verbose level sanity check */ diff --git a/components/console/esp_console.h b/components/console/esp_console.h index 2cebe9b9bf..7e7a18ddb1 100644 --- a/components/console/esp_console.h +++ b/components/console/esp_console.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -331,6 +331,15 @@ const char *esp_console_get_hint(const char *buf, int *color, int *bold); */ esp_err_t esp_console_register_help_command(void); +/** + * @brief Deregister a 'help' command + * + * @return esp_err_t + * - ESP_OK on success + * - other on failure + */ +esp_err_t esp_console_deregister_help_command(void); + /** * @brief Set the verbose level for 'help' command * diff --git a/components/console/esp_console_common.c b/components/console/esp_console_common.c index 8bbe84ef19..adb7c054da 100644 --- a/components/console/esp_console_common.c +++ b/components/console/esp_console_common.c @@ -129,6 +129,22 @@ _exit: return ret; } +void esp_console_common_deinit(esp_console_repl_com_t *repl_com) +{ + /* Unregister the heap function to avoid memory leak, since it is created + * every time a console init is called. */ + esp_err_t ret = esp_console_deregister_help_command(); + assert(ret == ESP_OK); + + /* unregister eventfd to avoid memory leaks, since it is created every time a + * console init is called */ + (void)esp_vfs_eventfd_unregister(); + + /* free the history to avoid memory leak, since it is created + * every time a console init is called. */ + linenoiseHistoryFree(); +} + esp_err_t esp_console_start_repl(esp_console_repl_t *repl) { esp_err_t ret = ESP_OK; diff --git a/components/console/esp_console_repl_chip.c b/components/console/esp_console_repl_chip.c index 743db4d500..3ec5dbd3de 100644 --- a/components/console/esp_console_repl_chip.c +++ b/components/console/esp_console_repl_chip.c @@ -315,6 +315,8 @@ static esp_err_t esp_console_repl_uart_delete(esp_console_repl_t *repl) vSemaphoreDelete(repl_com->state_mux); repl_com->state_mux = NULL; + esp_console_common_deinit(&uart_repl->repl_com); + esp_console_deinit(); uart_vfs_dev_use_nonblocking(uart_repl->uart_channel); uart_driver_delete(uart_repl->uart_channel); @@ -356,6 +358,8 @@ static esp_err_t esp_console_repl_usb_cdc_delete(esp_console_repl_t *repl) vSemaphoreDelete(repl_com->state_mux); repl_com->state_mux = NULL; + esp_console_common_deinit(&cdc_repl->repl_com); + esp_console_deinit(); free(cdc_repl); _exit: @@ -395,6 +399,8 @@ static esp_err_t esp_console_repl_usb_serial_jtag_delete(esp_console_repl_t *rep vSemaphoreDelete(repl_com->state_mux); repl_com->state_mux = NULL; + esp_console_common_deinit(&usb_serial_jtag_repl->repl_com); + esp_console_deinit(); usb_serial_jtag_vfs_use_nonblocking(); usb_serial_jtag_driver_uninstall(); diff --git a/components/console/linenoise/linenoise.c b/components/console/linenoise/linenoise.c index 0725da3048..7b8d378ec2 100644 --- a/components/console/linenoise/linenoise.c +++ b/components/console/linenoise/linenoise.c @@ -1265,6 +1265,7 @@ void linenoiseHistoryFree(void) { free(history); } history = NULL; + history_len = 0; } /* This is the API call to add a new entry in the linenoise history. diff --git a/components/console/private_include/console_private.h b/components/console/private_include/console_private.h index f95bcfb82b..606c0c81d7 100644 --- a/components/console/private_include/console_private.h +++ b/components/console/private_include/console_private.h @@ -47,6 +47,7 @@ typedef struct { void esp_console_repl_task(void *args); esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com); +void esp_console_common_deinit(esp_console_repl_com_t *repl_com); esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com); esp_err_t esp_console_setup_history(const char *history_path, uint32_t max_history_len, diff --git a/components/console/test_apps/console/main/test_app_main.c b/components/console/test_apps/console/main/test_app_main.c index 258953bd47..2336f50da5 100644 --- a/components/console/test_apps/console/main/test_app_main.c +++ b/components/console/test_apps/console/main/test_app_main.c @@ -10,7 +10,12 @@ #include // Some resources are lazy allocated (newlib locks) in the console code, the threshold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (150) +#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT (150) +static int leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +void set_leak_threshold(int threshold) +{ + leak_threshold = threshold; +} void setUp(void) { @@ -19,7 +24,8 @@ void setUp(void) void tearDown(void) { - unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD); + unity_utils_evaluate_leaks_direct(leak_threshold); + leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; } void app_main(void) diff --git a/components/console/test_apps/console/main/test_console.c b/components/console/test_apps/console/main/test_console.c index 034b3b7362..3111fc9760 100644 --- a/components/console/test_apps/console/main/test_console.c +++ b/components/console/test_apps/console/main/test_console.c @@ -154,8 +154,11 @@ TEST_CASE("esp console repl test", "[console][ignore]") vTaskDelay(pdMS_TO_TICKS(2000)); } +extern void set_leak_threshold(int threshold); TEST_CASE("esp console repl deinit", "[console][ignore]") { + set_leak_threshold(400); + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); @@ -165,14 +168,17 @@ TEST_CASE("esp console repl deinit", "[console][ignore]") /* wait to make sure the task reaches linenoiseEdit function * and gets stuck in the select */ - vTaskDelay(pdMS_TO_TICKS(500)); + vTaskDelay(pdMS_TO_TICKS(10)); /* call the delete function, this returns only when the repl task terminated */ const esp_err_t res = s_repl->del(s_repl); + /* wait to make sure the task reaches linenoiseEdit function + * and gets stuck in the select */ + vTaskDelay(pdMS_TO_TICKS(10)); + /* if this point is reached, the repl environment has been deleted successfully */ TEST_ASSERT(res == ESP_OK); - printf("-------------- %p\n", s_repl); } static const esp_console_cmd_t cmd_a = {