[Linux] Fix memory leaks in the BLE module (#28067)
* Do not duplicate string when passing to const argument
* Convert NULL to nullptr
* Do not duplicate string when adding to mpConnMap
* Free buffer used for reading characteristic data
* Clear stack-allocated dict variants
* Fix memory leak when creating unix FD list
* Change new to g_new to be consistent with the rest of the code
* Replace stack-alloc variant dict with heap-alloc
In our case, it's easier to handle memory free for heap-allocated variant dicts.
* Free memory returned by g_variant_dict_lookup_value
diff --git a/src/platform/Linux/bluez/Helper.cpp b/src/platform/Linux/bluez/Helper.cpp
index 6a1966c..d071f3b 100644
--- a/src/platform/Linux/bluez/Helper.cpp
+++ b/src/platform/Linux/bluez/Helper.cpp
@@ -335,15 +335,15 @@
uint8_t * buf;
size_t len;
bool isSuccess = false;
- BluezConnection * conn = NULL;
+ BluezConnection * conn = nullptr;
BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
- VerifyOrExit(endpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+ VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
- VerifyOrExit(aValue != NULL, ChipLogError(DeviceLayer, "aValue is NULL in %s", __func__));
+ VerifyOrExit(aValue != nullptr, ChipLogError(DeviceLayer, "aValue is NULL in %s", __func__));
conn = GetBluezConnectionViaDevice(endpoint);
- VerifyOrExit(conn != NULL,
+ VerifyOrExit(conn != nullptr,
g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No CHIP Bluez connection"));
bluez_gatt_characteristic1_set_value(aChar, g_variant_ref(aValue));
@@ -372,9 +372,8 @@
static gboolean BluezCharacteristicWriteFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint)
{
GVariant * newVal;
- gchar * buf;
+ uint8_t * buf = nullptr;
ssize_t len;
- int fd;
bool isSuccess = false;
BluezConnection * conn = static_cast<BluezConnection *>(apEndpoint);
@@ -387,33 +386,29 @@
ChipLogDetail(DeviceLayer, "c1 %s mtu, %d", __func__, conn->mMtu);
- buf = static_cast<gchar *>(g_malloc(conn->mMtu));
- fd = g_io_channel_unix_get_fd(aChannel);
-
- len = read(fd, buf, conn->mMtu);
-
+ buf = g_new(uint8_t, conn->mMtu);
+ len = read(g_io_channel_unix_get_fd(aChannel), buf, conn->mMtu);
VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%zd)", __func__, len));
// Casting len to size_t is safe, since we ensured that it's not negative.
newVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buf, static_cast<size_t>(len), sizeof(uint8_t));
bluez_gatt_characteristic1_set_value(conn->mpC1, newVal);
- BLEManagerImpl::HandleRXCharWrite(conn, reinterpret_cast<uint8_t *>(buf), static_cast<size_t>(len));
+ BLEManagerImpl::HandleRXCharWrite(conn, buf, static_cast<size_t>(len));
isSuccess = true;
exit:
+ g_free(buf);
return isSuccess ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
}
static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMethodInvocation * invocation, int fd, guint16 mtu)
{
GUnixFDList * fd_list = g_unix_fd_list_new();
- int index;
-
- index = g_unix_fd_list_append(fd_list, fd, nullptr);
-
+ int index = g_unix_fd_list_append(fd_list, fd, nullptr);
g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, g_variant_new("(@hq)", g_variant_new_handle(index), mtu),
fd_list);
+ g_object_unref(fd_list);
}
static gboolean bluezCharacteristicDestroyFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint)
@@ -430,9 +425,10 @@
#if CHIP_ERROR_LOGGING
char * errStr;
#endif // CHIP_ERROR_LOGGING
- GVariantDict options;
- bool isSuccess = false;
BluezConnection * conn = nullptr;
+ GVariantDict * options = nullptr;
+ GVariant * option_mtu = nullptr;
+ bool isSuccess = false;
BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
@@ -453,18 +449,12 @@
goto exit;
}
- g_variant_dict_init(&options, aOptions);
- if (g_variant_dict_contains(&options, "mtu") == TRUE)
- {
- GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
- conn->mMtu = g_variant_get_uint16(v);
- }
- else
- {
- ChipLogError(DeviceLayer, "FAIL: no MTU in options in %s", __func__);
- g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed");
- goto exit;
- }
+ options = g_variant_dict_new(aOptions);
+ option_mtu = g_variant_dict_lookup_value(options, "mtu", G_VARIANT_TYPE_UINT16);
+ VerifyOrExit(
+ option_mtu != nullptr, ChipLogError(DeviceLayer, "FAIL: No MTU in options in %s", __func__);
+ g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed"));
+ conn->mMtu = g_variant_get_uint16(option_mtu);
channel = g_io_channel_unix_new(fds[0]);
g_io_channel_set_encoding(channel, nullptr, nullptr);
@@ -484,6 +474,14 @@
isSuccess = true;
exit:
+ if (options != nullptr)
+ {
+ g_variant_dict_unref(options);
+ }
+ if (option_mtu != nullptr)
+ {
+ g_variant_unref(option_mtu);
+ }
return isSuccess ? TRUE : FALSE;
}
@@ -505,28 +503,31 @@
#if CHIP_ERROR_LOGGING
char * errStr;
#endif // CHIP_ERROR_LOGGING
- GVariantDict options;
BluezConnection * conn = nullptr;
+ GVariantDict * options = nullptr;
+ GVariant * option_mtu = nullptr;
bool isSuccess = false;
BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+ if (bluez_gatt_characteristic1_get_notifying(aChar))
+ {
+ g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying");
+ goto exit;
+ }
+
conn = GetBluezConnectionViaDevice(endpoint);
VerifyOrExit(conn != nullptr,
g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
- g_variant_dict_init(&options, aOptions);
- if ((g_variant_dict_contains(&options, "mtu") == TRUE))
- {
- GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
- conn->mMtu = g_variant_get_uint16(v);
- }
+ options = g_variant_dict_new(aOptions);
+ option_mtu = g_variant_dict_lookup_value(options, "mtu", G_VARIANT_TYPE_UINT16);
+ VerifyOrExit(
+ option_mtu != nullptr, ChipLogError(DeviceLayer, "FAIL: No MTU in options in %s", __func__);
+ g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed"));
+ conn->mMtu = g_variant_get_uint16(option_mtu);
- if (bluez_gatt_characteristic1_get_notifying(aChar))
- {
- g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying");
- }
if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
{
#if CHIP_ERROR_LOGGING
@@ -559,6 +560,14 @@
isSuccess = true;
exit:
+ if (options != nullptr)
+ {
+ g_variant_dict_unref(options);
+ }
+ if (option_mtu != nullptr)
+ {
+ g_variant_unref(option_mtu);
+ }
return isSuccess ? TRUE : FALSE;
}
@@ -801,8 +810,8 @@
static BluezGattCharacteristic1 * BluezCharacteristicCreate(BluezGattService1 * aService, const char * aCharName,
const char * aUUID, GDBusObjectManagerServer * aRoot)
{
- char * servicePath = g_strdup(g_dbus_object_get_object_path(g_dbus_interface_get_object(G_DBUS_INTERFACE(aService))));
- char * charPath = g_strdup_printf("%s/%s", servicePath, aCharName);
+ const char * servicePath = g_dbus_object_get_object_path(g_dbus_interface_get_object(G_DBUS_INTERFACE(aService)));
+ char * charPath = g_strdup_printf("%s/%s", servicePath, aCharName);
BluezObjectSkeleton * object;
BluezGattCharacteristic1 * characteristic;
@@ -817,7 +826,6 @@
g_dbus_object_manager_server_export(aRoot, G_DBUS_OBJECT_SKELETON(object));
g_free(charPath);
- g_free(servicePath);
g_object_unref(object);
return characteristic;
@@ -868,10 +876,10 @@
return CHIP_NO_ERROR;
}
-/// Update the table of open BLE connections whevener a new device is spotted or its attributes have changed.
+/// Update the table of open BLE connections whenever a new device is spotted or its attributes have changed.
static void UpdateConnectionTable(BluezDevice1 * apDevice, BluezEndpoint & aEndpoint)
{
- const gchar * objectPath = g_dbus_proxy_get_object_path(G_DBUS_PROXY(apDevice));
+ const char * objectPath = g_dbus_proxy_get_object_path(G_DBUS_PROXY(apDevice));
BluezConnection * connection = static_cast<BluezConnection *>(g_hash_table_lookup(aEndpoint.mpConnMap, objectPath));
if (connection != nullptr && !bluez_device1_get_connected(apDevice))
@@ -901,7 +909,7 @@
aEndpoint.mpPeerDevicePath = g_strdup(objectPath);
g_hash_table_insert(aEndpoint.mpConnMap, aEndpoint.mpPeerDevicePath, connection);
- ChipLogDetail(DeviceLayer, "New BLE connection %p, device %s, path %s", connection, connection->mpPeerAddress,
+ ChipLogDetail(DeviceLayer, "New BLE connection: conn %p, device %s, path %s", connection, connection->mpPeerAddress,
aEndpoint.mpPeerDevicePath);
BLEManagerImpl::HandleNewConnection(connection);
@@ -932,7 +940,7 @@
}
// We need to handle device connection both this function and BluezSignalInterfacePropertiesChanged
- // When a device is connected for first time, this function will be triggerred.
+ // When a device is connected for first time, this function will be triggered.
// The future connections for the same device will trigger ``Connect'' property change.
// TODO: Factor common code in the two function.
BluezConnection * conn;
@@ -950,8 +958,10 @@
conn->mpEndpoint = apEndpoint;
BluezConnectionInit(conn);
apEndpoint->mpPeerDevicePath = g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
- ChipLogDetail(DeviceLayer, "Device %s (Path: %s) Connected", conn->mpPeerAddress, apEndpoint->mpPeerDevicePath);
- g_hash_table_insert(apEndpoint->mpConnMap, g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))), conn);
+ g_hash_table_insert(apEndpoint->mpConnMap, apEndpoint->mpPeerDevicePath, conn);
+
+ ChipLogDetail(DeviceLayer, "BLE device connected: conn %p, device %s, path %s", conn, conn->mpPeerAddress,
+ apEndpoint->mpPeerDevicePath);
exit:
return;
@@ -1072,52 +1082,51 @@
static BluezConnection * BluezCharacteristicGetBluezConnection(BluezGattCharacteristic1 * aChar, GVariant * aOptions,
BluezEndpoint * apEndpoint)
{
- BluezConnection * retval = NULL;
- const gchar * path = NULL;
- GVariantDict options;
- GVariant * v;
+ BluezConnection * retval = nullptr;
+ GVariantDict * options = nullptr;
+ GVariant * option_device = nullptr;
- VerifyOrExit(apEndpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+ VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
VerifyOrExit(apEndpoint->mIsCentral, );
/* TODO Unfortunately StartNotify/StopNotify doesn't provide info about
* peer device in call params so we need look this up ourselves.
*/
- if (aOptions == NULL)
+ if (aOptions == nullptr)
{
GList * objects;
GList * l;
GList * ll;
objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
- for (l = objects; l != NULL; l = l->next)
+ for (l = objects; l != nullptr; l = l->next)
{
BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(l->data));
- if (device != NULL)
+ if (device != nullptr)
{
if (BluezIsDeviceOnAdapter(device, apEndpoint->mpAdapter))
{
- for (ll = objects; ll != NULL; ll = ll->next)
+ for (ll = objects; ll != nullptr; ll = ll->next)
{
BluezGattService1 * service = bluez_object_get_gatt_service1(BLUEZ_OBJECT(ll->data));
- if (service != NULL)
+ if (service != nullptr)
{
if (BluezIsServiceOnDevice(service, device))
{
if (BluezIsCharOnService(aChar, service))
{
- retval = (BluezConnection *) g_hash_table_lookup(
- apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
+ retval = static_cast<BluezConnection *>(g_hash_table_lookup(
+ apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
}
}
g_object_unref(service);
- if (retval != NULL)
+ if (retval != nullptr)
break;
}
}
}
g_object_unref(device);
- if (retval != NULL)
+ if (retval != nullptr)
break;
}
}
@@ -1126,18 +1135,23 @@
}
else
{
- g_variant_dict_init(&options, aOptions);
+ options = g_variant_dict_new(aOptions);
+ option_device = g_variant_dict_lookup_value(options, "device", G_VARIANT_TYPE_OBJECT_PATH);
+ VerifyOrExit(option_device != nullptr, ChipLogError(DeviceLayer, "FAIL: No device in options in %s", __func__););
- v = g_variant_dict_lookup_value(&options, "device", G_VARIANT_TYPE_OBJECT_PATH);
-
- VerifyOrExit(v != NULL, ChipLogError(DeviceLayer, "FAIL: No device option in dictionary (%s)", __func__));
-
- path = g_variant_get_string(v, NULL);
-
- retval = (BluezConnection *) g_hash_table_lookup(apEndpoint->mpConnMap, path);
+ retval = static_cast<BluezConnection *>(
+ g_hash_table_lookup(apEndpoint->mpConnMap, g_variant_get_string(option_device, nullptr)));
}
exit:
+ if (options != nullptr)
+ {
+ g_variant_dict_unref(options);
+ }
+ if (option_device != nullptr)
+ {
+ g_variant_unref(option_device);
+ }
return retval;
}
#endif // CHIP_BLUEZ_CENTRAL_SUPPORT
@@ -1260,24 +1274,22 @@
endpoint->mpService = BluezServiceCreate(apClosure);
// C1 characteristic
- endpoint->mpC1 =
- BluezCharacteristicCreate(endpoint->mpService, g_strdup("c1"), g_strdup(CHIP_PLAT_BLE_UUID_C1_STRING), endpoint->mpRoot);
+ endpoint->mpC1 = BluezCharacteristicCreate(endpoint->mpService, "c1", CHIP_PLAT_BLE_UUID_C1_STRING, endpoint->mpRoot);
bluez_gatt_characteristic1_set_flags(endpoint->mpC1, c1_flags);
g_signal_connect(endpoint->mpC1, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
- g_signal_connect(endpoint->mpC1, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
+ g_signal_connect(endpoint->mpC1, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), nullptr);
g_signal_connect(endpoint->mpC1, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWrite), apClosure);
- g_signal_connect(endpoint->mpC1, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotifyError), NULL);
- g_signal_connect(endpoint->mpC1, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotifyError), NULL);
- g_signal_connect(endpoint->mpC1, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotifyError), NULL);
- g_signal_connect(endpoint->mpC1, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirmError), NULL);
+ g_signal_connect(endpoint->mpC1, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotifyError), nullptr);
+ g_signal_connect(endpoint->mpC1, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotifyError), nullptr);
+ g_signal_connect(endpoint->mpC1, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotifyError), nullptr);
+ g_signal_connect(endpoint->mpC1, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirmError), nullptr);
- endpoint->mpC2 =
- BluezCharacteristicCreate(endpoint->mpService, g_strdup("c2"), g_strdup(CHIP_PLAT_BLE_UUID_C2_STRING), endpoint->mpRoot);
+ endpoint->mpC2 = BluezCharacteristicCreate(endpoint->mpService, "c2", CHIP_PLAT_BLE_UUID_C2_STRING, endpoint->mpRoot);
bluez_gatt_characteristic1_set_flags(endpoint->mpC2, c2_flags);
g_signal_connect(endpoint->mpC2, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
- g_signal_connect(endpoint->mpC2, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
- g_signal_connect(endpoint->mpC2, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
+ g_signal_connect(endpoint->mpC2, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), nullptr);
+ g_signal_connect(endpoint->mpC2, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), nullptr);
g_signal_connect(endpoint->mpC2, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
g_signal_connect(endpoint->mpC2, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
g_signal_connect(endpoint->mpC2, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
@@ -1289,12 +1301,11 @@
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is TRUE");
// Additional data characteristics
- endpoint->mpC3 =
- BluezCharacteristicCreate(endpoint->mpService, g_strdup("c3"), g_strdup(CHIP_PLAT_BLE_UUID_C3_STRING), endpoint->mpRoot);
+ endpoint->mpC3 = BluezCharacteristicCreate(endpoint->mpService, "c3", CHIP_PLAT_BLE_UUID_C3_STRING, endpoint->mpRoot);
bluez_gatt_characteristic1_set_flags(endpoint->mpC3, c3_flags);
g_signal_connect(endpoint->mpC3, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
- g_signal_connect(endpoint->mpC3, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
- g_signal_connect(endpoint->mpC3, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
+ g_signal_connect(endpoint->mpC3, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), nullptr);
+ g_signal_connect(endpoint->mpC3, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), nullptr);
g_signal_connect(endpoint->mpC3, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
g_signal_connect(endpoint->mpC3, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
g_signal_connect(endpoint->mpC3, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);