semihosting: fix memory leak and double free

Resolve two problems that occurred when working with semihosting service
through multiple connection cycles (connect-disconnect-reconnect):

1) Double free:
    When the same service handles multiple connections sequentially,
    the same memory gets freed repeatedly, because function
    'semihosting_service_connection_closed_handler()' incorrectly frees
    service->priv->name on every connection closure.

2) Memory leak:
    Function 'free_services()' misses service->priv->name cleanup for
    semihosting redirection. Memory remains allocated after service
    destruction.

The solution introduces a new 'dtor()' field in the service structure
that is called exactly once during free_service() execution.

To reproduce the issue, you can do the following:
    1. openocd -f target.cfg -c init -c 'arm semihosting enable' -c
    'arm semihosting_redirect tcp 4445'

    # in another terminal
    2. nc localhost 4445
    3. Ctr+C
    4. nc localhost 4445
    5. Ctr+C

Change-Id: I0dc8021cc3e21c5af619c71a1821a1afe9bffe78
Signed-off-by: Kulyatskaya Alexandra <a.kulyatskaya@syntacore.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/9196
Tested-by: jenkins
Reviewed-by: Evgeniy Naydanov <eugnay@gmail.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
Kulyatskaya Alexandra
2025-10-06 23:19:56 +03:00
committed by Antonio Borneo
parent 55e9160509
commit 5ff384be08
3 changed files with 17 additions and 19 deletions

View File

@@ -1800,13 +1800,12 @@ static int semihosting_service_input_handler(struct connection *connection)
return ERROR_OK;
}
static int semihosting_service_connection_closed_handler(struct connection *connection)
static void semihosting_service_dtor_handler(struct service *service)
{
struct semihosting_tcp_service *service = connection->service->priv;
if (service)
free(service->name);
struct semihosting_tcp_service *service_priv = service->priv;
if (service_priv)
free(service_priv->name);
return ERROR_OK;
}
static void semihosting_tcp_close_cnx(struct semihosting *semihosting)
@@ -1825,7 +1824,8 @@ static const struct service_driver semihosting_service_driver = {
.new_connection_during_keep_alive_handler = NULL,
.new_connection_handler = semihosting_service_new_connection_handler,
.input_handler = semihosting_service_input_handler,
.connection_closed_handler = semihosting_service_connection_closed_handler,
.service_dtor_handler = semihosting_service_dtor_handler,
.connection_closed_handler = NULL,
.keep_client_alive_handler = NULL,
};