From f894c8e23a6f0a13cecf3e53a262d7ea27045e20 Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Thu, 15 Feb 2024 19:24:33 +0100 Subject: [PATCH] gattlib_disconnect: Add mutex to avoid double free --- common/gattlib_internal_defs.h | 2 ++ dbus/gattlib.c | 19 +++++++++++++------ gattlib-py/gattlib/device.py | 15 +++++++++++---- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/common/gattlib_internal_defs.h b/common/gattlib_internal_defs.h index 6e4b447..6e898b0 100644 --- a/common/gattlib_internal_defs.h +++ b/common/gattlib_internal_defs.h @@ -42,6 +42,8 @@ struct gattlib_handler { struct _gatt_connection_t { void* context; + GMutex connection_mutex; + struct gattlib_handler on_connection; struct gattlib_handler on_connection_error; struct gattlib_handler notification; diff --git a/dbus/gattlib.c b/dbus/gattlib.c index 9e786ba..efe149e 100644 --- a/dbus/gattlib.c +++ b/dbus/gattlib.c @@ -281,6 +281,7 @@ gatt_connection_t *gattlib_connect_async(void *adapter, const char *dst, int gattlib_disconnect(gatt_connection_t* connection) { gattlib_context_t* conn_context; + int ret = GATTLIB_SUCCESS; GError *error = NULL; if (connection == NULL) { @@ -288,16 +289,15 @@ int gattlib_disconnect(gatt_connection_t* connection) { return GATTLIB_INVALID_PARAMETER; } + g_mutex_lock(&connection->connection_mutex); conn_context = connection->context; if (conn_context == NULL) { GATTLIB_LOG(GATTLIB_ERROR, "Cannot disconnect - connection context is not valid."); - return GATTLIB_NOT_SUPPORTED; + ret = GATTLIB_NOT_SUPPORTED; + goto EXIT; } - // Remove signal - g_signal_handler_disconnect(conn_context->device, conn_context->on_handle_device_property_change_id); - org_bluez_device1_call_disconnect_sync(conn_context->device, NULL, &error); if (error) { GATTLIB_LOG(GATTLIB_ERROR, "Failed to disconnect DBus Bluez Device: %s", error->message); @@ -308,7 +308,10 @@ int gattlib_disconnect(gatt_connection_t* connection) { gattlib_on_disconnected_device(connection); free(conn_context->device_object_path); - g_object_unref(conn_context->device); + if (conn_context->device != NULL) { + g_object_unref(conn_context->device); + conn_context->device = NULL; + } g_list_free_full(conn_context->dbus_objects, g_object_unref); g_main_loop_quit(conn_context->connection_loop); pthread_join(conn_context->event_thread, NULL); @@ -318,8 +321,12 @@ int gattlib_disconnect(gatt_connection_t* connection) { // Note: We do not free adapter as it might still be used by other devices free(connection->context); + connection->context = NULL; free(connection); - return GATTLIB_SUCCESS; + +EXIT: + g_mutex_unlock(&connection->connection_mutex); + return ret; } // Bluez was using org.bluez.Device1.GattServices until 5.37 to expose the list of available GATT Services diff --git a/gattlib-py/gattlib/device.py b/gattlib-py/gattlib/device.py index a6f23c5..2b2ad48 100644 --- a/gattlib-py/gattlib/device.py +++ b/gattlib-py/gattlib/device.py @@ -7,6 +7,7 @@ from __future__ import annotations import logging import uuid +import threading from typing import TYPE_CHECKING from gattlib import * @@ -39,6 +40,8 @@ class Device: self._addr = addr self._name = name self._connection = None + self._connection_lock = threading.Lock() + self.on_connection_callback = None self.on_connection_error_callback = None @@ -114,10 +117,14 @@ class Device: gattlib_python_callback_args(on_disconnection, user_data)) def disconnect(self): - if self._connection: - ret = gattlib_disconnect(self.connection) - handle_return(ret) - self._connection = None + self._connection_lock.acquire() + try: + if self._connection: + ret = gattlib_disconnect(self.connection) + handle_return(ret) + self._connection = None + finally: + self._connection_lock.release() def discover(self): #