Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/3] Cancel pending HoG reports before detach
@ 2026-09-22  1:15 Nicholas Hammond
  2026-09-22  1:15 ` [PATCH BlueZ 1/3] input/hog: Cancel pending report requests on detach Nicholas Hammond
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Nicholas Hammond @ 2026-09-22  1:15 UTC (permalink / raw)
  To: linux-bluetooth

From: Nick Hammond <blender7@gmail.com>

This series fixes outstanding HID report callbacks surviving HoG detach.

The investigation started with a bluetoothd crash on Ubuntu BlueZ
5.72-0ubuntu5.5 while reconnecting an MX Keys S keyboard after switching
hosts. The saved stack passes through report_reply/get_report_cb,
read_blob_helper and attrib_callback_result. The original core and device
identifiers are intentionally not included.

On current master (17e624d1c), getrep_att and setrep_att still bypass the
gatt_op queue cancelled by bt_hog_detach. If another owner retains the
GAttrib connection, a late response can invoke a callback after its HoG
object/report is freed. A surviving HoG object can also receive a stale
reply after detach.

A socketpair test on that revision reproduces the read, long-read and
write use-after-free under AddressSanitizer. For example, the long-read
case reports:

  ERROR: AddressSanitizer: heap-use-after-free
    get_report_cb       profiles/input/hog-lib.c:929
    read_blob_helper    attrib/gatt.c:791
    attrib_callback_result attrib/gattrib.c:235
    handle_rsp          src/shared/att.c:913

This is a lifetime regression test with a shared live GAttrib reference,
not an over-the-air reproducer or a claim of unauthenticated reachability.
It does not establish that every historical keyboard outage had this
cause.

Patch 1 cancels the separately tracked report requests before dropping
attrib. Patches 2 and 3 add and register five hardware-independent tests.
The test includes hog-lib.c to access private report state, avoiding new
production APIs and unrelated discovery traffic.

Validation on current master plus this series:
- AddressSanitizer with detect_leaks=1: all five new tests pass.
- Existing test-hog (6), test-gattrib (6), test-gatt (193): all pass.
- checkpatch --no-tree --no-signoff: no errors or warnings.
- A backport to Ubuntu 5.72 is installed on the affected host; keyboard
  and mouse reconnected after restarting the daemon. Long-term stability
  is not yet established.

To reproduce the failures, apply only patches 2 and 3 to the base revision
and build with --enable-asan. Run unit/test-hog-lifetime -p followed by
/hog/detach/read, /hog/detach/blob or /hog/detach/write. Each detects a
use-after-free without patch 1. /hog/reconnect catches the stale reply;
/hog/normal passes before and after the fix.

AI assistance disclosure: Codex:gpt-6 analyzed the saved crash, prepared
the fix and tests, and ran the validation commands. This contribution
includes Assisted-by tags. No claim of an independent human code review
is made.

Thanks,
Nick Hammond

Nick Hammond (3):
  input/hog: Cancel pending report requests on detach
  unit: Test pending HoG reports across detach
  build: Register the HoG report lifetime tests

 Makefile.am              |  14 ++++
 profiles/input/hog-lib.c |  11 +++
 unit/test-hog-lifetime.c | 152 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 177 insertions(+)
 create mode 100644 unit/test-hog-lifetime.c


base-commit: 17e624d1cd9a4d94f90e0ca008548456c3455492
-- 
2.43.0

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 1/3] input/hog: Cancel pending report requests on detach
  2026-09-22  1:15 [PATCH BlueZ 0/3] Cancel pending HoG reports before detach Nicholas Hammond
@ 2026-09-22  1:15 ` Nicholas Hammond
  2026-09-22  6:36   ` Cancel pending HoG reports before detach bluez.test.bot
  2026-10-07 12:06   ` bluez.test.bot
  2026-09-22  1:15 ` [PATCH BlueZ 2/3] unit: Test pending HoG reports across detach Nicholas Hammond
  2026-09-22  1:15 ` [PATCH BlueZ 3/3] build: Register the HoG report lifetime tests Nicholas Hammond
  2 siblings, 2 replies; 7+ messages in thread
From: Nicholas Hammond @ 2026-09-22  1:15 UTC (permalink / raw)
  To: linux-bluetooth

From: Nick Hammond <blender7@gmail.com>

GET_REPORT and SET_REPORT requests are tracked by getrep_att and
setrep_att rather than gatt_op. Cancelling gatt_op during detach leaves
these callbacks registered on the shared GAttrib connection.

A reply delivered after the HoG object is freed can therefore access a
freed report in get_report_cb or a freed hog in set_report_cb. A long
GET_REPORT read can also retain its callback through a READ_BLOB
continuation. If the HoG object survives detach, the callback can instead
send a stale UHID reply.

Cancel both outstanding requests before releasing attrib and clear their
IDs so a later attachment starts without stale request state.

This was investigated following a bluetoothd crash on Ubuntu BlueZ 5.72
during keyboard reconnection. A socketpair regression reproduces the
use-after-free on current master with AddressSanitizer as well.

Assisted-by: Codex:gpt-6 AddressSanitizer
---
 profiles/input/hog-lib.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/profiles/input/hog-lib.c b/profiles/input/hog-lib.c
index 054356371..6c75c607f 100644
--- a/profiles/input/hog-lib.c
+++ b/profiles/input/hog-lib.c
@@ -1896,6 +1896,17 @@ void bt_hog_detach(struct bt_hog *hog, bool force)
 	if (hog->dis)
 		bt_dis_detach(hog->dis);

+	/* Report requests are tracked separately from gatt_op. */
+	if (hog->getrep_att) {
+		g_attrib_cancel(hog->attrib, hog->getrep_att);
+		hog->getrep_att = 0;
+	}
+
+	if (hog->setrep_att) {
+		g_attrib_cancel(hog->attrib, hog->setrep_att);
+		hog->setrep_att = 0;
+	}
+
 	queue_remove_all(hog->gatt_op, cancel_gatt_req, hog, destroy_gatt_req);
 	g_attrib_unref(hog->attrib);
 	hog->attrib = NULL;
-- 
2.43.0



On Mon, 21 Sep 2026 18:15:15 -0700, Nicholas Hammond
<nicholas.hammond0@gmail.com> wrote:
> From: Nick Hammond <blender7@gmail.com>
>
> This series fixes outstanding HID report callbacks surviving HoG detach.
>
> The investigation started with a bluetoothd crash on Ubuntu BlueZ
> 5.72-0ubuntu5.5 while reconnecting an MX Keys S keyboard after switching
> hosts. The saved stack passes through report_reply/get_report_cb,
> read_blob_helper and attrib_callback_result. The original core and device
> identifiers are intentionally not included.
>
> On current master (17e624d1c), getrep_att and setrep_att still bypass the
> gatt_op queue cancelled by bt_hog_detach. If another owner retains the
> GAttrib connection, a late response can invoke a callback after its HoG
> object/report is freed. A surviving HoG object can also receive a stale
> reply after detach.
>
> A socketpair test on that revision reproduces the read, long-read and
> write use-after-free under AddressSanitizer. For example, the long-read
> case reports:
>
>   ERROR: AddressSanitizer: heap-use-after-free
>     get_report_cb       profiles/input/hog-lib.c:929
>     read_blob_helper    attrib/gatt.c:791
>     attrib_callback_result attrib/gattrib.c:235
>     handle_rsp          src/shared/att.c:913
>
> This is a lifetime regression test with a shared live GAttrib reference,
> not an over-the-air reproducer or a claim of unauthenticated reachability.
> It does not establish that every historical keyboard outage had this
> cause.
>
> Patch 1 cancels the separately tracked report requests before dropping
> attrib. Patches 2 and 3 add and register five hardware-independent tests.
> The test includes hog-lib.c to access private report state, avoiding new
> production APIs and unrelated discovery traffic.
>
> Validation on current master plus this series:
> - AddressSanitizer with detect_leaks=1: all five new tests pass.
> - Existing test-hog (6), test-gattrib (6), test-gatt (193): all pass.
> - checkpatch --no-tree --no-signoff: no errors or warnings.
> - A backport to Ubuntu 5.72 is installed on the affected host; keyboard
>   and mouse reconnected after restarting the daemon. Long-term stability
>   is not yet established.
>
> To reproduce the failures, apply only patches 2 and 3 to the base revision
> and build with --enable-asan. Run unit/test-hog-lifetime -p followed by
> /hog/detach/read, /hog/detach/blob or /hog/detach/write. Each detects a
> use-after-free without patch 1. /hog/reconnect catches the stale reply;
> /hog/normal passes before and after the fix.
>
> AI assistance disclosure: Codex:gpt-6 analyzed the saved crash, prepared
> the fix and tests, and ran the validation commands. This contribution
> includes Assisted-by tags. No claim of an independent human code review
> is made.
>
> Thanks,
> Nick Hammond
>
> Nick Hammond (3):
>   input/hog: Cancel pending report requests on detach
>   unit: Test pending HoG reports across detach
>   build: Register the HoG report lifetime tests
>
>  Makefile.am              |  14 ++++
>  profiles/input/hog-lib.c |  11 +++
>  unit/test-hog-lifetime.c | 152 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 177 insertions(+)
>  create mode 100644 unit/test-hog-lifetime.c
>
>
> base-commit: 17e624d1cd9a4d94f90e0ca008548456c3455492
> --
> 2.43.0

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 2/3] unit: Test pending HoG reports across detach
  2026-09-22  1:15 [PATCH BlueZ 0/3] Cancel pending HoG reports before detach Nicholas Hammond
  2026-09-22  1:15 ` [PATCH BlueZ 1/3] input/hog: Cancel pending report requests on detach Nicholas Hammond
@ 2026-09-22  1:15 ` Nicholas Hammond
  2026-09-22 14:25   ` Luiz Augusto von Dentz
  2026-09-22  1:15 ` [PATCH BlueZ 3/3] build: Register the HoG report lifetime tests Nicholas Hammond
  2 siblings, 1 reply; 7+ messages in thread
From: Nicholas Hammond @ 2026-09-22  1:15 UTC (permalink / raw)
  To: linux-bluetooth

From: Nick Hammond <blender7@gmail.com>

Exercise the real HoG, GAttrib and ATT implementations with socketpairs
for ATT and UHID, without requiring a controller or /dev/uhid.

Cover pending reads, READ_BLOB continuations and writes whose responses
arrive after detach and object destruction. Also check normal completion
and reuse of a surviving object after detach. Keep another GAttrib
reference alive to model the connection shared with other profiles.

Include hog-lib.c to construct a single report and invoke its request
handlers without unrelated service discovery or new production APIs.
The follow-up build change registers this test with make check.

Without the preceding fix, the three teardown cases fail under
AddressSanitizer and the reuse case receives a stale reply. All five
cases pass with the fix and leak detection enabled.

Assisted-by: Codex:gpt-6 AddressSanitizer
---
 unit/test-hog-lifetime.c | 152 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 152 insertions(+)
 create mode 100644 unit/test-hog-lifetime.c

diff --git a/unit/test-hog-lifetime.c b/unit/test-hog-lifetime.c
new file mode 100644
index 000000000..53a563c40
--- /dev/null
+++ b/unit/test-hog-lifetime.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Regression for outstanding HID report requests surviving detach.
+ * Uses socketpairs and the real HoG/GAttrib/ATT implementation; no hardware.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "profiles/input/hog-lib.c"
+
+static void pump(void)
+{
+	while (g_main_context_iteration(NULL, FALSE))
+		;
+}
+
+static void test_report(gconstpointer data)
+{
+	const char *name = data;
+	bool blob = !strcmp(name, "blob");
+	bool write_test = !strcmp(name, "write");
+	bool normal = !strcmp(name, "normal");
+	bool reconnect = !strcmp(name, "reconnect");
+	int attfd[2], uhidfd[2];
+	GIOChannel *io;
+	GAttrib *attrib;
+	struct bt_hog *hog;
+	struct report *report;
+	struct uhid_event ev = { 0 }, reply;
+	uint8_t pdu[64];
+	uint8_t response[2] = {
+		write_test ? 0x13 : blob ? 0x0d : 0x0b, 0x55
+	};
+	size_t size = write_test ? 1 : 2;
+	ssize_t n;
+
+	g_assert_cmpint(socketpair(AF_UNIX,
+			SOCK_SEQPACKET | SOCK_NONBLOCK, 0, attfd), ==, 0);
+	g_assert_cmpint(socketpair(AF_UNIX,
+			SOCK_SEQPACKET | SOCK_NONBLOCK, 0, uhidfd), ==, 0);
+	io = g_io_channel_unix_new(attfd[0]);
+	g_io_channel_set_close_on_unref(io, TRUE);
+	attrib = g_attrib_new(io, 23, false);
+	g_io_channel_unref(io);
+	hog = bt_hog_new(uhidfd[0], "lifetime-test", 2, 1, 1, 0, NULL);
+	g_assert(hog && attrib);
+	hog->attrib = g_attrib_ref(attrib);
+	report = g_new0(struct report, 1);
+	report->hog = hog;
+	report->type = HOG_REPORT_TYPE_FEATURE;
+	report->value_handle = 0x31;
+	hog->reports = g_slist_append(hog->reports, report);
+
+	if (write_test) {
+		ev.type = UHID_SET_REPORT;
+		ev.u.set_report.id = 123;
+		ev.u.set_report.rtype = UHID_FEATURE_REPORT;
+		ev.u.set_report.size = 1;
+		ev.u.set_report.data[0] = 0x55;
+		set_report(&ev, hog);
+		g_assert(hog->setrep_att != 0);
+	} else {
+		ev.type = UHID_GET_REPORT;
+		ev.u.get_report.id = 123;
+		ev.u.get_report.rtype = UHID_FEATURE_REPORT;
+		get_report(&ev, hog);
+		g_assert(hog->getrep_att != 0);
+	}
+
+	pump();
+	n = read(attfd[1], pdu, sizeof(pdu));
+	g_assert(n >= 3 && pdu[0] == (write_test ? 0x12 : 0x0a));
+
+	if (blob) {
+		uint8_t first[23] = { 0x0b };
+
+		g_assert_cmpint(write(attfd[1], first, sizeof(first)),
+						==, sizeof(first));
+		pump();
+		n = read(attfd[1], pdu, sizeof(pdu));
+		g_assert(n == 5 && pdu[0] == 0x0c);
+	}
+
+	if (!normal) {
+		bt_hog_detach(hog, true);
+
+		if (!reconnect) {
+			bt_hog_unref(hog);
+			hog = NULL;
+		}
+	}
+
+	g_assert(write(attfd[1], response, size) == size);
+	pump();
+	n = read(uhidfd[1], &reply, sizeof(reply));
+
+	if (normal) {
+		g_assert(n == sizeof(reply));
+		g_assert(reply.type == UHID_GET_REPORT_REPLY);
+		g_assert(reply.u.get_report_reply.id == 123);
+		g_assert(reply.u.get_report_reply.err == 0);
+		g_assert(reply.u.get_report_reply.data[0] == 0x55);
+	} else {
+		g_assert(n == -1 && errno == EAGAIN);
+	}
+
+	if (reconnect) {
+		/* Reuse the detached object for another report request. */
+		g_assert(hog->getrep_att == 0 && hog->setrep_att == 0);
+		hog->attrib = g_attrib_ref(attrib);
+		ev.u.get_report.id = 124;
+		get_report(&ev, hog);
+		pump();
+		n = read(attfd[1], pdu, sizeof(pdu));
+		g_assert(n == 3 && pdu[0] == 0x0a);
+		g_assert(write(attfd[1], response, 2) == 2);
+		pump();
+		g_assert_cmpint(read(uhidfd[1], &reply, sizeof(reply)),
+						==, sizeof(reply));
+		g_assert(reply.u.get_report_reply.id == 124);
+		g_assert(reply.u.get_report_reply.err == 0);
+	}
+
+	if (hog)
+		bt_hog_unref(hog);
+
+	g_attrib_unref(attrib);
+	close(attfd[1]);
+	close(uhidfd[0]);
+	close(uhidfd[1]);
+	pump();
+}
+
+int main(int argc, char *argv[])
+{
+	g_test_init(&argc, &argv, NULL);
+
+	g_test_add_data_func("/hog/detach/read", "read", test_report);
+	g_test_add_data_func("/hog/detach/blob", "blob", test_report);
+	g_test_add_data_func("/hog/detach/write", "write", test_report);
+	g_test_add_data_func("/hog/normal", "normal", test_report);
+	g_test_add_data_func("/hog/reconnect", "reconnect", test_report);
+
+	return g_test_run();
+}
-- 
2.43.0



On Mon, 21 Sep 2026 18:15:15 -0700, Nicholas Hammond
<nicholas.hammond0@gmail.com> wrote:
> From: Nick Hammond <blender7@gmail.com>
>
> This series fixes outstanding HID report callbacks surviving HoG detach.
>
> The investigation started with a bluetoothd crash on Ubuntu BlueZ
> 5.72-0ubuntu5.5 while reconnecting an MX Keys S keyboard after switching
> hosts. The saved stack passes through report_reply/get_report_cb,
> read_blob_helper and attrib_callback_result. The original core and device
> identifiers are intentionally not included.
>
> On current master (17e624d1c), getrep_att and setrep_att still bypass the
> gatt_op queue cancelled by bt_hog_detach. If another owner retains the
> GAttrib connection, a late response can invoke a callback after its HoG
> object/report is freed. A surviving HoG object can also receive a stale
> reply after detach.
>
> A socketpair test on that revision reproduces the read, long-read and
> write use-after-free under AddressSanitizer. For example, the long-read
> case reports:
>
>   ERROR: AddressSanitizer: heap-use-after-free
>     get_report_cb       profiles/input/hog-lib.c:929
>     read_blob_helper    attrib/gatt.c:791
>     attrib_callback_result attrib/gattrib.c:235
>     handle_rsp          src/shared/att.c:913
>
> This is a lifetime regression test with a shared live GAttrib reference,
> not an over-the-air reproducer or a claim of unauthenticated reachability.
> It does not establish that every historical keyboard outage had this
> cause.
>
> Patch 1 cancels the separately tracked report requests before dropping
> attrib. Patches 2 and 3 add and register five hardware-independent tests.
> The test includes hog-lib.c to access private report state, avoiding new
> production APIs and unrelated discovery traffic.
>
> Validation on current master plus this series:
> - AddressSanitizer with detect_leaks=1: all five new tests pass.
> - Existing test-hog (6), test-gattrib (6), test-gatt (193): all pass.
> - checkpatch --no-tree --no-signoff: no errors or warnings.
> - A backport to Ubuntu 5.72 is installed on the affected host; keyboard
>   and mouse reconnected after restarting the daemon. Long-term stability
>   is not yet established.
>
> To reproduce the failures, apply only patches 2 and 3 to the base revision
> and build with --enable-asan. Run unit/test-hog-lifetime -p followed by
> /hog/detach/read, /hog/detach/blob or /hog/detach/write. Each detects a
> use-after-free without patch 1. /hog/reconnect catches the stale reply;
> /hog/normal passes before and after the fix.
>
> AI assistance disclosure: Codex:gpt-6 analyzed the saved crash, prepared
> the fix and tests, and ran the validation commands. This contribution
> includes Assisted-by tags. No claim of an independent human code review
> is made.
>
> Thanks,
> Nick Hammond
>
> Nick Hammond (3):
>   input/hog: Cancel pending report requests on detach
>   unit: Test pending HoG reports across detach
>   build: Register the HoG report lifetime tests
>
>  Makefile.am              |  14 ++++
>  profiles/input/hog-lib.c |  11 +++
>  unit/test-hog-lifetime.c | 152 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 177 insertions(+)
>  create mode 100644 unit/test-hog-lifetime.c
>
>
> base-commit: 17e624d1cd9a4d94f90e0ca008548456c3455492
> --
> 2.43.0

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 3/3] build: Register the HoG report lifetime tests
  2026-09-22  1:15 [PATCH BlueZ 0/3] Cancel pending HoG reports before detach Nicholas Hammond
  2026-09-22  1:15 ` [PATCH BlueZ 1/3] input/hog: Cancel pending report requests on detach Nicholas Hammond
  2026-09-22  1:15 ` [PATCH BlueZ 2/3] unit: Test pending HoG reports across detach Nicholas Hammond
@ 2026-09-22  1:15 ` Nicholas Hammond
  2 siblings, 0 replies; 7+ messages in thread
From: Nicholas Hammond @ 2026-09-22  1:15 UTC (permalink / raw)
  To: linux-bluetooth

From: Nick Hammond <blender7@gmail.com>

Build and run test-hog-lifetime with the existing unit test suite. Link
its support sources without a second copy of hog-lib.c, which the test
includes to exercise the private report callbacks.

Assisted-by: Codex:gpt-6 AddressSanitizer
---
 Makefile.am | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 1d46b9b93..87a3b4f64 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -779,6 +779,20 @@ unit_test_hog_SOURCES = unit/test-hog.c \
 unit_test_hog_LDADD = src/libshared-glib.la \
 				lib/libbluetooth-internal.la $(GLIB_LIBS)

+unit_tests += unit/test-hog-lifetime
+
+unit_test_hog_lifetime_SOURCES = unit/test-hog-lifetime.c \
+			$(btio_sources) \
+			profiles/input/hog-lib.h \
+			profiles/scanparam/scpp.h profiles/scanparam/scpp.c \
+			profiles/battery/bas.h profiles/battery/bas.c \
+			profiles/deviceinfo/dis.h profiles/deviceinfo/dis.c \
+			src/log.h src/log.c \
+			attrib/att.h attrib/att.c \
+			attrib/gatt.h attrib/gatt.c \
+			attrib/gattrib.h attrib/gattrib.c
+unit_test_hog_lifetime_LDADD = $(unit_test_hog_LDADD)
+
 unit_tests += unit/test-gattrib

 unit_test_gattrib_SOURCES = unit/test-gattrib.c attrib/gattrib.c \
-- 
2.43.0



On Mon, 21 Sep 2026 18:15:15 -0700, Nicholas Hammond
<nicholas.hammond0@gmail.com> wrote:
> From: Nick Hammond <blender7@gmail.com>
>
> This series fixes outstanding HID report callbacks surviving HoG detach.
>
> The investigation started with a bluetoothd crash on Ubuntu BlueZ
> 5.72-0ubuntu5.5 while reconnecting an MX Keys S keyboard after switching
> hosts. The saved stack passes through report_reply/get_report_cb,
> read_blob_helper and attrib_callback_result. The original core and device
> identifiers are intentionally not included.
>
> On current master (17e624d1c), getrep_att and setrep_att still bypass the
> gatt_op queue cancelled by bt_hog_detach. If another owner retains the
> GAttrib connection, a late response can invoke a callback after its HoG
> object/report is freed. A surviving HoG object can also receive a stale
> reply after detach.
>
> A socketpair test on that revision reproduces the read, long-read and
> write use-after-free under AddressSanitizer. For example, the long-read
> case reports:
>
>   ERROR: AddressSanitizer: heap-use-after-free
>     get_report_cb       profiles/input/hog-lib.c:929
>     read_blob_helper    attrib/gatt.c:791
>     attrib_callback_result attrib/gattrib.c:235
>     handle_rsp          src/shared/att.c:913
>
> This is a lifetime regression test with a shared live GAttrib reference,
> not an over-the-air reproducer or a claim of unauthenticated reachability.
> It does not establish that every historical keyboard outage had this
> cause.
>
> Patch 1 cancels the separately tracked report requests before dropping
> attrib. Patches 2 and 3 add and register five hardware-independent tests.
> The test includes hog-lib.c to access private report state, avoiding new
> production APIs and unrelated discovery traffic.
>
> Validation on current master plus this series:
> - AddressSanitizer with detect_leaks=1: all five new tests pass.
> - Existing test-hog (6), test-gattrib (6), test-gatt (193): all pass.
> - checkpatch --no-tree --no-signoff: no errors or warnings.
> - A backport to Ubuntu 5.72 is installed on the affected host; keyboard
>   and mouse reconnected after restarting the daemon. Long-term stability
>   is not yet established.
>
> To reproduce the failures, apply only patches 2 and 3 to the base revision
> and build with --enable-asan. Run unit/test-hog-lifetime -p followed by
> /hog/detach/read, /hog/detach/blob or /hog/detach/write. Each detects a
> use-after-free without patch 1. /hog/reconnect catches the stale reply;
> /hog/normal passes before and after the fix.
>
> AI assistance disclosure: Codex:gpt-6 analyzed the saved crash, prepared
> the fix and tests, and ran the validation commands. This contribution
> includes Assisted-by tags. No claim of an independent human code review
> is made.
>
> Thanks,
> Nick Hammond
>
> Nick Hammond (3):
>   input/hog: Cancel pending report requests on detach
>   unit: Test pending HoG reports across detach
>   build: Register the HoG report lifetime tests
>
>  Makefile.am              |  14 ++++
>  profiles/input/hog-lib.c |  11 +++
>  unit/test-hog-lifetime.c | 152 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 177 insertions(+)
>  create mode 100644 unit/test-hog-lifetime.c
>
>
> base-commit: 17e624d1cd9a4d94f90e0ca008548456c3455492
> --
> 2.43.0

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* RE: Cancel pending HoG reports before detach
  2026-09-22  1:15 ` [PATCH BlueZ 1/3] input/hog: Cancel pending report requests on detach Nicholas Hammond
@ 2026-09-22  6:36   ` bluez.test.bot
  2026-10-07 12:06   ` bluez.test.bot
  1 sibling, 0 replies; 7+ messages in thread
From: bluez.test.bot @ 2026-09-22  6:36 UTC (permalink / raw)
  To: linux-bluetooth, nicholas.hammond0

[-- Attachment #1: Type: text/plain, Size: 48117 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1170874/

---Test result---

Test Summary:
CheckPatch                    PASS      1.15 seconds
GitLint                       PASS      0.78 seconds
BuildEll                      PASS      16.24 seconds
BluezMake                     FAIL      164.57 seconds
MakeCheck                     FAIL      129.63 seconds
MakeDistcheck                 PASS      114.17 seconds
CheckValgrind                 FAIL      46.79 seconds
CheckSmatch                   FAIL      88.66 seconds
bluezmakeextell               FAIL      32.47 seconds
TestFunctional                ERROR     163.96 seconds
IncrementalBuild              FAIL      283.62 seconds
ScanBuild                     FAIL      142.10 seconds

Details
##############################
Test: BluezMake - FAIL
Desc: Build BlueZ
Output:

tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:13218:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
13218 | int main(int argc, char *argv[])
      |     ^~~~
In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:34,
                 from /usr/include/glib-2.0/glib/galloca.h:34,
                 from /usr/include/glib-2.0/glib.h:32,
                 from unit/test-hog-lifetime.c:14:
unit/test-hog-lifetime.c: In function ‘test_report’:
unit/test-hog-lifetime.c:100:50: error: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Werror=sign-compare]
  100 |         g_assert(write(attfd[1], response, size) == size);
      |                                                  ^~
/usr/include/glib-2.0/glib/gmacros.h:1279:8: note: in definition of macro ‘_G_BOOLEAN_EXPR_IMPL’
 1279 |    if (expr)                                    \
      |        ^~~~
/usr/include/glib-2.0/glib/gmacros.h:1284:43: note: in expansion of macro ‘_G_BOOLEAN_EXPR’
 1284 | #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
      |                                           ^~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtestutils.h:276:49: note: in expansion of macro ‘G_LIKELY’
  276 |                                              if G_LIKELY (expr) ; else \
      |                                                 ^~~~~~~~
unit/test-hog-lifetime.c:100:9: note: in expansion of macro ‘g_assert’
  100 |         g_assert(write(attfd[1], response, size) == size);
      |         ^~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7297: unit/test-hog-lifetime.o] Error 1
make[1]: *** Waiting for unfinished jobs....
unit/test-avdtp.c: In function ‘main’:
unit/test-avdtp.c:766:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
  766 | int main(int argc, char *argv[])
      |     ^~~~
unit/test-avrcp.c: In function ‘main’:
unit/test-avrcp.c:1382:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
 1382 | int main(int argc, char *argv[])
      |     ^~~~
make: *** [Makefile:4348: all] Error 2
##############################
Test: MakeCheck - FAIL
Desc: Run Bluez Make Check
Output:

In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:34,
                 from /usr/include/glib-2.0/glib/galloca.h:34,
                 from /usr/include/glib-2.0/glib.h:32,
                 from unit/test-hog-lifetime.c:14:
unit/test-hog-lifetime.c: In function ‘test_report’:
unit/test-hog-lifetime.c:100:50: error: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Werror=sign-compare]
  100 |         g_assert(write(attfd[1], response, size) == size);
      |                                                  ^~
/usr/include/glib-2.0/glib/gmacros.h:1279:8: note: in definition of macro ‘_G_BOOLEAN_EXPR_IMPL’
 1279 |    if (expr)                                    \
      |        ^~~~
/usr/include/glib-2.0/glib/gmacros.h:1284:43: note: in expansion of macro ‘_G_BOOLEAN_EXPR’
 1284 | #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
      |                                           ^~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtestutils.h:276:49: note: in expansion of macro ‘G_LIKELY’
  276 |                                              if G_LIKELY (expr) ; else \
      |                                                 ^~~~~~~~
unit/test-hog-lifetime.c:100:9: note: in expansion of macro ‘g_assert’
  100 |         g_assert(write(attfd[1], response, size) == size);
      |         ^~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7297: unit/test-hog-lifetime.o] Error 1
make: *** [Makefile:11236: check] Error 2
##############################
Test: CheckValgrind - FAIL
Desc: Run Bluez Make Check with Valgrind
Output:

In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:34,
                 from /usr/include/glib-2.0/glib/galloca.h:34,
                 from /usr/include/glib-2.0/glib.h:32,
                 from unit/test-hog-lifetime.c:14:
unit/test-hog-lifetime.c: In function ‘test_report’:
unit/test-hog-lifetime.c:100:50: error: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Werror=sign-compare]
  100 |         g_assert(write(attfd[1], response, size) == size);
      |                                                  ^~
/usr/include/glib-2.0/glib/gmacros.h:1279:8: note: in definition of macro ‘_G_BOOLEAN_EXPR_IMPL’
 1279 |    if (expr)                                    \
      |        ^~~~
/usr/include/glib-2.0/glib/gmacros.h:1284:43: note: in expansion of macro ‘_G_BOOLEAN_EXPR’
 1284 | #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
      |                                           ^~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtestutils.h:276:49: note: in expansion of macro ‘G_LIKELY’
  276 |                                              if G_LIKELY (expr) ; else \
      |                                                 ^~~~~~~~
unit/test-hog-lifetime.c:100:9: note: in expansion of macro ‘g_assert’
  100 |         g_assert(write(attfd[1], response, size) == size);
      |         ^~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7297: unit/test-hog-lifetime.o] Error 1
make[1]: *** Waiting for unfinished jobs....
tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:13218:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
13218 | int main(int argc, char *argv[])
      |     ^~~~
make: *** [Makefile:11236: check] Error 2
##############################
Test: CheckSmatch - FAIL
Desc: Run smatch tool with source
Output:

src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272:23: warning: Variable length array is used.
src/shared/gatt-helpers.c:764:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:842:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1335:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1366:23: warning: Variable length array is used.
src/shared/bap.c:318:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/x86_64-linux-gnu//sys/ioctl.h, /usr/include/x86_64-linux-gnu//sys/epoll.h, src/shared/mainloop.h):
/usr/include/x86_64-linux-gnu//sys/ttydefaults.h:55:9: warning: preprocessor token CTRL redefined
src/shared/shell.c: note: in included file (through /usr/include/readline/keymaps.h, /usr/include/readline/readline.h):
/usr/include/readline/chardefs.h:51:9: this was the original definition
src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272:23: warning: Variable length array is used.
src/shared/gatt-helpers.c:764:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:842:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1335:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1366:23: warning: Variable length array is used.
src/shared/bap.c:318:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/x86_64-linux-gnu//sys/ioctl.h, /usr/include/x86_64-linux-gnu//sys/epoll.h, src/shared/mainloop.h):
/usr/include/x86_64-linux-gnu//sys/ttydefaults.h:55:9: warning: preprocessor token CTRL redefined
src/shared/shell.c: note: in included file (through /usr/include/readline/keymaps.h, /usr/include/readline/readline.h):
/usr/include/readline/chardefs.h:51:9: this was the original definition
tools/mesh-cfgtest.c:1453:17: warning: unknown escape sequence: '\%'
tools/sco-tester.c: note: in included file:
./lib/bluetooth/bluetooth.h:232:15: warning: array of flexible structures
./lib/bluetooth/bluetooth.h:237:31: warning: array of flexible structures
tools/bneptest.c:634:39: warning: unknown escape sequence: '\%'
tools/seq2bseq.c:57:26: warning: Variable length array is used.
client/btpclient/gatt.c: note: in included file:
./src/shared/btp.h:338:41: warning: array of flexible structures
./src/shared/btp.h:343:55: warning: array of flexible structures
./src/shared/btp.h:366:47: warning: array of flexible structures
./src/shared/btp.h:395:42: warning: array of flexible structures
src/advertising.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/agent.c: note: in included file:
src/shared/queue.h:19:20: error: redefinition of struct queue_entry
src/adv_monitor.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
unit/avctp.c:505:34: warning: Variable length array is used.
unit/avctp.c:556:34: warning: Variable length array is used.
unit/test-avrcp.c:374:26: warning: Variable length array is used.
unit/test-avrcp.c:399:26: warning: Variable length array is used.
unit/test-avrcp.c:415:24: warning: Variable length array is used.
unit/avrcp-lib.c:1085:34: warning: Variable length array is used.
unit/avrcp-lib.c:1583:34: warning: Variable length array is used.
unit/avrcp-lib.c:1612:34: warning: Variable length array is used.
unit/avrcp-lib.c:1638:34: warning: Variable length array is used.
In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:34,
                 from /usr/include/glib-2.0/glib/galloca.h:34,
                 from /usr/include/glib-2.0/glib.h:32,
                 from unit/test-hog-lifetime.c:14:
unit/test-hog-lifetime.c: In function ‘test_report’:
unit/test-hog-lifetime.c:100:50: error: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Werror=sign-compare]
  100 |         g_assert(write(attfd[1], response, size) == size);
      |                                                  ^~
/usr/include/glib-2.0/glib/gmacros.h:1279:8: note: in definition of macro ‘_G_BOOLEAN_EXPR_IMPL’
 1279 |    if (expr)                                    \
      |        ^~~~
/usr/include/glib-2.0/glib/gmacros.h:1284:43: note: in expansion of macro ‘_G_BOOLEAN_EXPR’
 1284 | #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
      |                                           ^~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtestutils.h:276:49: note: in expansion of macro ‘G_LIKELY’
  276 |                                              if G_LIKELY (expr) ; else \
      |                                                 ^~~~~~~~
unit/test-hog-lifetime.c:100:9: note: in expansion of macro ‘g_assert’
  100 |         g_assert(write(attfd[1], response, size) == size);
      |         ^~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7297: unit/test-hog-lifetime.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4348: all] Error 2
##############################
Test: bluezmakeextell - FAIL
Desc: Build Bluez with External ELL
Output:

In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:34,
                 from /usr/include/glib-2.0/glib/galloca.h:34,
                 from /usr/include/glib-2.0/glib.h:32,
                 from unit/test-hog-lifetime.c:14:
unit/test-hog-lifetime.c: In function ‘test_report’:
unit/test-hog-lifetime.c:100:50: error: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Werror=sign-compare]
  100 |         g_assert(write(attfd[1], response, size) == size);
      |                                                  ^~
/usr/include/glib-2.0/glib/gmacros.h:1279:8: note: in definition of macro ‘_G_BOOLEAN_EXPR_IMPL’
 1279 |    if (expr)                                    \
      |        ^~~~
/usr/include/glib-2.0/glib/gmacros.h:1284:43: note: in expansion of macro ‘_G_BOOLEAN_EXPR’
 1284 | #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
      |                                           ^~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtestutils.h:276:49: note: in expansion of macro ‘G_LIKELY’
  276 |                                              if G_LIKELY (expr) ; else \
      |                                                 ^~~~~~~~
unit/test-hog-lifetime.c:100:9: note: in expansion of macro ‘g_assert’
  100 |         g_assert(write(attfd[1], response, size) == size);
      |         ^~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7297: unit/test-hog-lifetime.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4348: all] Error 2
##############################
Test: TestFunctional - ERROR
Desc: Run test-functional
Output:
Failed to build BlueZ:
Failed to build BlueZ
##############################
Test: IncrementalBuild - FAIL
Desc: Incremental build with the patches in the series
Output:

In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:34,
                 from /usr/include/glib-2.0/glib/galloca.h:34,
                 from /usr/include/glib-2.0/glib.h:32,
                 from unit/test-hog-lifetime.c:14:
unit/test-hog-lifetime.c: In function ‘test_report’:
unit/test-hog-lifetime.c:100:50: error: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Werror=sign-compare]
  100 |         g_assert(write(attfd[1], response, size) == size);
      |                                                  ^~
/usr/include/glib-2.0/glib/gmacros.h:1279:8: note: in definition of macro ‘_G_BOOLEAN_EXPR_IMPL’
 1279 |    if (expr)                                    \
      |        ^~~~
/usr/include/glib-2.0/glib/gmacros.h:1284:43: note: in expansion of macro ‘_G_BOOLEAN_EXPR’
 1284 | #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
      |                                           ^~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtestutils.h:276:49: note: in expansion of macro ‘G_LIKELY’
  276 |                                              if G_LIKELY (expr) ; else \
      |                                                 ^~~~~~~~
unit/test-hog-lifetime.c:100:9: note: in expansion of macro ‘g_assert’
  100 |         g_assert(write(attfd[1], response, size) == size);
      |         ^~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7297: unit/test-hog-lifetime.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4348: all] Error 2
[BlueZ,3/3] build: Register the HoG report lifetime tests

In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:34,
                 from /usr/include/glib-2.0/glib/galloca.h:34,
                 from /usr/include/glib-2.0/glib.h:32,
                 from unit/test-hog-lifetime.c:14:
unit/test-hog-lifetime.c: In function ‘test_report’:
unit/test-hog-lifetime.c:100:50: error: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Werror=sign-compare]
  100 |         g_assert(write(attfd[1], response, size) == size);
      |                                                  ^~
/usr/include/glib-2.0/glib/gmacros.h:1279:8: note: in definition of macro ‘_G_BOOLEAN_EXPR_IMPL’
 1279 |    if (expr)                                    \
      |        ^~~~
/usr/include/glib-2.0/glib/gmacros.h:1284:43: note: in expansion of macro ‘_G_BOOLEAN_EXPR’
 1284 | #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
      |                                           ^~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtestutils.h:276:49: note: in expansion of macro ‘G_LIKELY’
  276 |                                              if G_LIKELY (expr) ; else \
      |                                                 ^~~~~~~~
unit/test-hog-lifetime.c:100:9: note: in expansion of macro ‘g_assert’
  100 |         g_assert(write(attfd[1], response, size) == size);
      |         ^~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7297: unit/test-hog-lifetime.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4348: all] Error 2
##############################
Test: ScanBuild - FAIL
Desc: Run Scan Build
Output:

src/shared/gatt-client.c:447:21: warning: Use of memory after it is freed [unix.Malloc]
  447 |         gatt_db_unregister(op->client->db, op->db_id);
      |                            ^~~~~~~~~~
src/shared/gatt-client.c:692:2: warning: Use of memory after it is freed [unix.Malloc]
  692 |         discovery_op_complete(op, false, att_ecode);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1098:2: warning: Use of memory after it is freed [unix.Malloc]
 1098 |         discovery_op_complete(op, success, att_ecode);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1292:2: warning: Use of memory after it is freed [unix.Malloc]
 1292 |         discovery_op_complete(op, success, att_ecode);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1357:2: warning: Use of memory after it is freed [unix.Malloc]
 1357 |         discovery_op_complete(op, success, att_ecode);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1632:6: warning: Use of memory after it is freed [unix.Malloc]
 1632 |         if (read_db_hash(op)) {
      |             ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1637:2: warning: Use of memory after it is freed [unix.Malloc]
 1637 |         discover_all(op);
      |         ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1693:56: warning: Use of memory after it is freed [unix.Malloc]
 1693 |         notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
      |                                           ~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2146:6: warning: Use of memory after it is freed [unix.Malloc]
 2146 |         if (read_db_hash(op)) {
      |             ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2154:8: warning: Use of memory after it is freed [unix.Malloc]
 2154 |                                                         discovery_op_ref(op),
      |                                                         ^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3332:2: warning: Use of memory after it is freed [unix.Malloc]
 3332 |         complete_write_long_op(req, success, 0, false);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3354:2: warning: Use of memory after it is freed [unix.Malloc]
 3354 |         request_unref(req);
      |         ^~~~~~~~~~~~~~~~~~
12 warnings generated.
src/shared/rap.c:3322:30: warning: Assigned value is uninitialized [core.uninitialized.Assign]
 3322 |                         out->tone_pct[k].i_sample = tone_pct_i[k];
      |                                                   ^ ~~~~~~~~~~~~~
src/shared/rap.c:4269:13: warning: Use of memory after it is freed [unix.Malloc]
 4269 |         attached = queue_find(sessions, NULL, rap);
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/shared/bap.c:1543:8: warning: Use of memory after it is freed [unix.Malloc]
 1543 |         bap = bt_bap_ref_safe(bap);
      |               ^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2359:20: warning: Use of memory after it is freed [unix.Malloc]
 2359 |         return queue_find(stream->bap->streams, NULL, stream);
      |                           ^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/shared/gatt-client.c:447:21: warning: Use of memory after it is freed [unix.Malloc]
  447 |         gatt_db_unregister(op->client->db, op->db_id);
      |                            ^~~~~~~~~~
src/shared/gatt-client.c:692:2: warning: Use of memory after it is freed [unix.Malloc]
  692 |         discovery_op_complete(op, false, att_ecode);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1098:2: warning: Use of memory after it is freed [unix.Malloc]
 1098 |         discovery_op_complete(op, success, att_ecode);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1292:2: warning: Use of memory after it is freed [unix.Malloc]
 1292 |         discovery_op_complete(op, success, att_ecode);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1357:2: warning: Use of memory after it is freed [unix.Malloc]
 1357 |         discovery_op_complete(op, success, att_ecode);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1632:6: warning: Use of memory after it is freed [unix.Malloc]
 1632 |         if (read_db_hash(op)) {
      |             ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1637:2: warning: Use of memory after it is freed [unix.Malloc]
 1637 |         discover_all(op);
      |         ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1693:56: warning: Use of memory after it is freed [unix.Malloc]
 1693 |         notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
      |                                           ~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2146:6: warning: Use of memory after it is freed [unix.Malloc]
 2146 |         if (read_db_hash(op)) {
      |             ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2154:8: warning: Use of memory after it is freed [unix.Malloc]
 2154 |                                                         discovery_op_ref(op),
      |                                                         ^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3332:2: warning: Use of memory after it is freed [unix.Malloc]
 3332 |         complete_write_long_op(req, success, 0, false);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3354:2: warning: Use of memory after it is freed [unix.Malloc]
 3354 |         request_unref(req);
      |         ^~~~~~~~~~~~~~~~~~
12 warnings generated.
src/shared/rap.c:3322:30: warning: Assigned value is uninitialized [core.uninitialized.Assign]
 3322 |                         out->tone_pct[k].i_sample = tone_pct_i[k];
      |                                                   ^ ~~~~~~~~~~~~~
src/shared/rap.c:4269:13: warning: Use of memory after it is freed [unix.Malloc]
 4269 |         attached = queue_find(sessions, NULL, rap);
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
tools/hciattach_ath3k.c:530:9: warning: File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior [unix.Stream]
  530 |                         if (!fgets(byte, 3, stream))
      |                              ^~~~~~~~~~~~~~~~~~~~~~
tools/hciattach_ath3k.c:530:9: warning: Read function called when stream is in EOF state. Function has no effect [unix.Stream]
  530 |                         if (!fgets(byte, 3, stream))
      |                              ^~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
tools/hciattach.c:817:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' [deadcode.DeadStores]
  817 |         if ((n = read_hci_event(fd, resp, 10)) < 0) {
      |              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:865:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' [deadcode.DeadStores]
  865 |         if ((n = read_hci_event(fd, resp, 4)) < 0) {
      |              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:887:8: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' [deadcode.DeadStores]
  887 |                 if ((n = read_hci_event(fd, resp, 10)) < 0) {
      |                      ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:909:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' [deadcode.DeadStores]
  909 |         if ((n = read_hci_event(fd, resp, 4)) < 0) {
      |              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:930:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' [deadcode.DeadStores]
  930 |         if ((n = read_hci_event(fd, resp, 4)) < 0) {
      |              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:974:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' [deadcode.DeadStores]
  974 |         if ((n = read_hci_event(fd, resp, 6)) < 0) {
      |              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 warnings generated.
src/oui.c:50:2: warning: Value stored to 'hwdb' is never read [deadcode.DeadStores]
   50 |         hwdb = udev_hwdb_unref(hwdb);
      |         ^      ~~~~~~~~~~~~~~~~~~~~~
src/oui.c:53:2: warning: Value stored to 'udev' is never read [deadcode.DeadStores]
   53 |         udev = udev_unref(udev);
      |         ^      ~~~~~~~~~~~~~~~~
2 warnings generated.
src/shared/bap.c:1543:8: warning: Use of memory after it is freed [unix.Malloc]
 1543 |         bap = bt_bap_ref_safe(bap);
      |               ^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2359:20: warning: Use of memory after it is freed [unix.Malloc]
 2359 |         return queue_find(stream->bap->streams, NULL, stream);
      |                           ^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
tools/rfcomm.c:234:3: warning: Value stored to 'i' is never read [deadcode.DeadStores]
  234 |                 i = execvp(cmdargv[0], cmdargv);
      |                 ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:234:7: warning: Null pointer passed to 1st parameter expecting 'nonnull' [core.NonNullParamChecker]
  234 |                 i = execvp(cmdargv[0], cmdargv);
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:354:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd' [deadcode.DeadStores]
  354 |                 if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
      |                      ^    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:473:6: warning: The 1st argument to 'getsockname' is -1 but should be >= 0 [unix.StdCLibraryFunctions]
  473 |         if (getsockname(nsk, (struct sockaddr *)&laddr, &alen) < 0) {
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:497:14: warning: Assigned value is uninitialized [core.uninitialized.Assign]
  497 |         req.channel = raddr.rc_channel;
      |                     ^ ~~~~~~~~~~~~~~~~
tools/rfcomm.c:515:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd' [deadcode.DeadStores]
  515 |                 if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
      |                      ^    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 warnings generated.
tools/ciptool.c:351:7: warning: 5th function call argument is an uninitialized value [core.CallAndMessage]
  351 |         sk = do_connect(ctl, dev_id, &src, &dst, psm, (1 << CMTP_LOOPBACK));
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
tools/sdptool.c:941:26: warning: Result of 'malloc' is converted to a pointer of type 'uint32_t', which is incompatible with sizeof operand type 'int' [unix.MallocSizeof]
  941 |                         uint32_t *value_int = malloc(sizeof(int));
      |                         ~~~~~~~~~~            ^~~~~~ ~~~~~~~~~~~
tools/sdptool.c:980:4: warning: 1st function call argument is an uninitialized value [core.CallAndMessage]
  980 |                         free(allocArray[i]);
      |                         ^~~~~~~~~~~~~~~~~~~
tools/sdptool.c:3777:2: warning: Potential leak of memory pointed to by 'si.name' [unix.Malloc]
 3777 |         return add_service(0, &si);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
tools/sdptool.c:4112:4: warning: Potential leak of memory pointed to by 'context.svc' [unix.Malloc]
 4112 |                         return -1;
      |                         ^~~~~~~~~
4 warnings generated.
src/sdp-xml.c:129:10: warning: Assigned value is uninitialized [core.uninitialized.Assign]
  129 |                 buf[1] = data[i + 1];
      |                        ^ ~~~~~~~~~~~
src/sdp-xml.c:309:11: warning: Assigned value is uninitialized [core.uninitialized.Assign]
  309 |                         buf[1] = data[i + 1];
      |                                ^ ~~~~~~~~~~~
src/sdp-xml.c:347:11: warning: Assigned value is uninitialized [core.uninitialized.Assign]
  347 |                         buf[1] = data[i + 1];
      |                                ^ ~~~~~~~~~~~
3 warnings generated.
tools/rfcomm-tester.c:410:6: warning: The 1st argument to 'bind' is -1 but should be >= 0 [unix.StdCLibraryFunctions]
  410 |         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm-tester.c:428:8: warning: The 1st argument to 'connect' is -1 but should be >= 0 [unix.StdCLibraryFunctions]
  428 |         err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
tools/avtest.c:243:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  243 |                                 len = write(sk, buf, 3);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:253:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  253 |                                 len = write(sk, buf, 4);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:262:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  262 |                                 len = write(sk, buf, 3);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:276:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  276 |                                 len = write(sk, buf,
      |                                 ^     ~~~~~~~~~~~~~~
  277 |                                                 3 + sizeof(media_transport));
      |                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:283:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  283 |                                 len = write(sk, buf,
      |                                 ^     ~~~~~~~~~~~~~~
  284 |                                                 1 + media_transport_size);
      |                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:290:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  290 |                                 len = write(sk, buf,
      |                                 ^     ~~~~~~~~~~~~~~
  291 |                                                 1 + media_transport_size);
      |                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:297:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  297 |                                 len = write(sk, buf,
      |                                 ^     ~~~~~~~~~~~~~~
  298 |                                                 2 + media_transport_size);
      |                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:309:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  309 |                                 len = write(sk, buf, 4);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:313:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  313 |                                 len = write(sk, buf, 2);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:322:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  322 |                                 len = write(sk, buf, 3);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:326:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  326 |                                 len = write(sk, buf, 2);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:335:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  335 |                                 len = write(sk, buf, 3);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:342:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  342 |                                 len = write(sk, buf, 2);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:364:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  364 |                                 len = write(sk, buf, 4);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:368:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  368 |                                 len = write(sk, buf, 2);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:377:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  377 |                                 len = write(sk, buf, 3);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:381:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  381 |                                 len = write(sk, buf, 2);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:394:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  394 |                                 len = write(sk, buf, 4);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:398:5: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  398 |                                 len = write(sk, buf, 2);
      |                                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:405:4: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  405 |                         len = write(sk, buf, 2);
      |                         ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:415:4: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  415 |                         len = write(sk, buf, 2);
      |                         ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:580:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  580 |                 len = write(sk, buf, 2);
      |                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:588:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  588 |                 len = write(sk, buf, invalid ? 2 : 3);
      |                 ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:602:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  602 |                 len = write(sk, buf, 4 + media_transport_size);
      |                 ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:615:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  615 |                 len = write(sk, buf, 3);
      |                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:625:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  625 |                 len = write(sk, buf, 3);
      |                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:637:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  637 |                 len = write(sk, buf, 3);
      |                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:652:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  652 |                 len = write(sk, buf, 3);
      |                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:664:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  664 |                 len = write(sk, buf, 3);
      |                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:673:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  673 |                 len = write(sk, buf, 3);
      |                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:680:3: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  680 |                 len = write(sk, buf, 2);
      |                 ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:716:2: warning: Value stored to 'len' is never read [deadcode.DeadStores]
  716 |         len = write(sk, buf, AVCTP_HEADER_LENGTH + sizeof(play_pressed));
      |         ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 warnings generated.
tools/create-image.c:76:3: warning: Value stored to 'fd' is never read [deadcode.DeadStores]
   76 |                 fd = -1;
      |                 ^    ~~
tools/create-image.c:84:3: warning: Value stored to 'fd' is never read [deadcode.DeadStores]
   84 |                 fd = -1;
      |                 ^    ~~
tools/create-image.c:92:3: warning: Value stored to 'fd' is never read [deadcode.DeadStores]
   92 |                 fd = -1;
      |                 ^    ~~
tools/create-image.c:105:2: warning: Value stored to 'fd' is never read [deadcode.DeadStores]
  105 |         fd = -1;
      |         ^    ~~
tools/create-image.c:108:2: warning: Null pointer passed to 1st parameter expecting 'nonnull' [core.NonNullParamChecker]
  108 |         fprintf(fp, HDR_FMT, HDR_MAGIC, ino, mode, 0, 0, 1, 0,
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  109 |                 (uintmax_t) st.st_size, 0, 0, 0, 0, namelen + 1, 0, name);
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/create-image.c:188:2: warning: Null pointer passed to 1st parameter expecting 'nonnull' [core.NonNullParamChecker]
  188 |         fclose(fp);
      |         ^~~~~~~~~~
6 warnings generated.
tools/btgatt-client.c:1822:2: warning: Value stored to 'argv' is never read [deadcode.DeadStores]
 1822 |         argv += optind;
      |         ^       ~~~~~~
1 warning generated.
tools/btgatt-server.c:1204:2: warning: Value stored to 'argv' is never read [deadcode.DeadStores]
 1204 |         argv -= optind;
      |         ^       ~~~~~~
1 warning generated.
tools/check-selftest.c:42:3: warning: Value stored to 'ptr' is never read [deadcode.DeadStores]
   42 |                 ptr = fgets(result, sizeof(result), fp);
      |                 ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
tools/gatt-service.c:294:2: warning: 2nd function call argument is an uninitialized value [core.CallAndMessage]
  294 |         chr_write(chr, value, len);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
In file included from tools/obex-server-tool.c:17:
In file included from /usr/include/fcntl.h:342:
/usr/include/x86_64-linux-gnu/bits/fcntl2.h:76:10: warning: Null pointer passed to 1st parameter expecting 'nonnull' [core.NonNullParamChecker]
   76 |   return __open_alias (__path, __oflag, __mode);
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
client/btpclient/btpclientctl.c:402:3: warning: Value stored to 'bit' is never read [deadcode.DeadStores]
  402 |                 bit = 0;
      |                 ^     ~
client/btpclient/btpclientctl.c:1655:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull' [core.NonNullParamChecker]
 1655 |         memcpy(cp->data, ad_data, ad_len);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/sdp-client.c:353:14: warning: Access to field 'cb' results in a dereference of a null pointer [core.NullDereference]
  353 |         (*ctxt)->cb = cb;
      |         ~~~~~~~~~~~~^~~~
1 warning generated.
src/sdpd-request.c:209:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint16_t' [unix.MallocSizeof]
  209 |                                 pElem = malloc(sizeof(uint16_t));
      |                                         ^~~~~~ ~~~~~~~~~~~~~~~~
src/sdpd-request.c:237:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint32_t' [unix.MallocSizeof]
  237 |                                 pElem = malloc(sizeof(uint32_t));
      |                                         ^~~~~~ ~~~~~~~~~~~~~~~~
2 warnings generated.
src/gatt-client.c:1569:2: warning: Use of memory after it is freed [unix.Malloc]
 1569 |         notify_client_unref(client);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/sdp-xml.c:129:10: warning: Assigned value is uninitialized [core.uninitialized.Assign]
  129 |                 buf[1] = data[i + 1];
      |                        ^ ~~~~~~~~~~~
src/sdp-xml.c:309:11: warning: Assigned value is uninitialized [core.uninitialized.Assign]
  309 |                         buf[1] = data[i + 1];
      |                                ^ ~~~~~~~~~~~
src/sdp-xml.c:347:11: warning: Assigned value is uninitialized [core.uninitialized.Assign]
  347 |                         buf[1] = data[i + 1];
      |                                ^ ~~~~~~~~~~~
3 warnings generated.
unit/avdtp.c:756:25: warning: Use of memory after it is freed [unix.Malloc]
  756 |                 session->prio_queue = g_slist_remove(session->prio_queue, req);
      |                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
unit/avdtp.c:763:24: warning: Use of memory after it is freed [unix.Malloc]
  763 |                 session->req_queue = g_slist_remove(session->req_queue, req);
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
unit/avrcp-lib.c:1968:3: warning: 1st function call argument is an uninitialized value [core.CallAndMessage]
 1968 |                 g_free(text[i]);
      |                 ^~~~~~~~~~~~~~~
unit/avrcp-lib.c:3510:4: warning: Address of stack memory associated with local variable 'val' is still referred to by the caller variable 'iov' upon returning to the caller.  This will be a dangling reference [core.StackAddressEscape]
 3503 |         struct media_item val[AVRCP_MEDIA_ATTRIBUTE_LAST];
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 3504 | 
 3505 |         for (i = 0; i < number; i++) {
 3506 |                 uint16_t len = 0;
 3507 | 
 3508 |                 if (attrs[i] > AVRCP_MEDIA_ATTRIBUTE_LAST ||
 3509 |                                 attrs[i] == AVRCP_MEDIA_ATTRIBUTE_ILLEGAL)
 3510 |                         return false;
      |                         ^~~~~~~~~~~~
unit/avrcp-lib.c:3526:2: warning: Address of stack memory associated with local variable 'val' is still referred to by the caller variable 'iov' upon returning to the caller.  This will be a dangling reference [core.StackAddressEscape]
 3503 |         return true;
      |         ^~~~~~~~~~~
3 warnings generated.
unit/test-util.c:33:8: warning: Potential leak of memory pointed to by 'p1' [unix.Malloc]
   33 |         p2[0] = 1;
      |         ~~~~~~^~~
unit/test-util.c:36:3: warning: Potential leak of memory pointed to by 'p2' [unix.Malloc]
   36 |                 _cleanup_free_ uint8_t *data = NULL;
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:134:24: note: expanded from macro '_cleanup_free_'
  134 | #define _cleanup_free_ _cleanup_(freep)
      |                        ^
./src/shared/util.h:132:22: note: expanded from macro '_cleanup_'
  132 | #define _cleanup_(f) __attribute__((cleanup(f)))
      |                      ^
unit/test-util.c:42:3: warning: Potential leak of memory pointed to by 'data' [unix.Malloc]
   42 |                 assert(is_null_too == NULL);
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/assert.h:170:11: note: expanded from macro 'assert'
  170 |   ((void) sizeof ((expr) ? 1 : 0), __extension__ ({                     \
      |           ^~~~~~~~~~~~~~~~~~~~~~~
3 warnings generated.
In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:34,
                 from /usr/include/glib-2.0/glib/galloca.h:34,
                 from /usr/include/glib-2.0/glib.h:32,
                 from unit/test-hog-lifetime.c:14:
unit/test-hog-lifetime.c: In function ‘test_report’:
unit/test-hog-lifetime.c:100:50: error: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Werror=sign-compare]
  100 |         g_assert(write(attfd[1], response, size) == size);
      |                                                  ^~
/usr/include/glib-2.0/glib/gmacros.h:1279:8: note: in definition of macro ‘_G_BOOLEAN_EXPR_IMPL’
 1279 |    if (expr)                                    \
      |        ^~~~
/usr/include/glib-2.0/glib/gmacros.h:1284:43: note: in expansion of macro ‘_G_BOOLEAN_EXPR’
 1284 | #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
      |                                           ^~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtestutils.h:276:49: note: in expansion of macro ‘G_LIKELY’
  276 |                                              if G_LIKELY (expr) ; else \
      |                                                 ^~~~~~~~
unit/test-hog-lifetime.c:100:9: note: in expansion of macro ‘g_assert’
  100 |         g_assert(write(attfd[1], response, size) == size);
      |         ^~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7297: unit/test-hog-lifetime.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4348: all] Error 2


https://github.com/bluez/bluez/pull/2563

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH BlueZ 2/3] unit: Test pending HoG reports across detach
  2026-09-22  1:15 ` [PATCH BlueZ 2/3] unit: Test pending HoG reports across detach Nicholas Hammond
@ 2026-09-22 14:25   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-22 14:25 UTC (permalink / raw)
  To: Nicholas Hammond; +Cc: linux-bluetooth

Hi Nicholas,

On Mon, Sep 21, 2026 at 9:16 PM Nicholas Hammond
<nicholas.hammond0@gmail.com> wrote:
>
> From: Nick Hammond <blender7@gmail.com>
>
> Exercise the real HoG, GAttrib and ATT implementations with socketpairs
> for ATT and UHID, without requiring a controller or /dev/uhid.

While the fix on 1/3 looks good, adding unit testing for this may not
be worth it, we should really replace the HoG implementation to use
the likes of bt_gatt_client instead of deprecated GAttrib.

> Cover pending reads, READ_BLOB continuations and writes whose responses
> arrive after detach and object destruction. Also check normal completion
> and reuse of a surviving object after detach. Keep another GAttrib
> reference alive to model the connection shared with other profiles.
>
> Include hog-lib.c to construct a single report and invoke its request
> handlers without unrelated service discovery or new production APIs.
> The follow-up build change registers this test with make check.
>
> Without the preceding fix, the three teardown cases fail under
> AddressSanitizer and the reuse case receives a stale reply. All five
> cases pass with the fix and leak detection enabled.
>
> Assisted-by: Codex:gpt-6 AddressSanitizer
> ---
>  unit/test-hog-lifetime.c | 152 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 152 insertions(+)
>  create mode 100644 unit/test-hog-lifetime.c
>
> diff --git a/unit/test-hog-lifetime.c b/unit/test-hog-lifetime.c
> new file mode 100644
> index 000000000..53a563c40
> --- /dev/null
> +++ b/unit/test-hog-lifetime.c
> @@ -0,0 +1,152 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Regression for outstanding HID report requests surviving detach.
> + * Uses socketpairs and the real HoG/GAttrib/ATT implementation; no hardware.
> + */
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <errno.h>
> +#include <unistd.h>
> +#include <sys/socket.h>
> +
> +#include <glib.h>
> +
> +#include "profiles/input/hog-lib.c"
> +
> +static void pump(void)
> +{
> +       while (g_main_context_iteration(NULL, FALSE))
> +               ;
> +}
> +
> +static void test_report(gconstpointer data)
> +{
> +       const char *name = data;
> +       bool blob = !strcmp(name, "blob");
> +       bool write_test = !strcmp(name, "write");
> +       bool normal = !strcmp(name, "normal");
> +       bool reconnect = !strcmp(name, "reconnect");
> +       int attfd[2], uhidfd[2];
> +       GIOChannel *io;
> +       GAttrib *attrib;
> +       struct bt_hog *hog;
> +       struct report *report;
> +       struct uhid_event ev = { 0 }, reply;
> +       uint8_t pdu[64];
> +       uint8_t response[2] = {
> +               write_test ? 0x13 : blob ? 0x0d : 0x0b, 0x55
> +       };
> +       size_t size = write_test ? 1 : 2;
> +       ssize_t n;
> +
> +       g_assert_cmpint(socketpair(AF_UNIX,
> +                       SOCK_SEQPACKET | SOCK_NONBLOCK, 0, attfd), ==, 0);
> +       g_assert_cmpint(socketpair(AF_UNIX,
> +                       SOCK_SEQPACKET | SOCK_NONBLOCK, 0, uhidfd), ==, 0);
> +       io = g_io_channel_unix_new(attfd[0]);
> +       g_io_channel_set_close_on_unref(io, TRUE);
> +       attrib = g_attrib_new(io, 23, false);
> +       g_io_channel_unref(io);
> +       hog = bt_hog_new(uhidfd[0], "lifetime-test", 2, 1, 1, 0, NULL);
> +       g_assert(hog && attrib);
> +       hog->attrib = g_attrib_ref(attrib);
> +       report = g_new0(struct report, 1);
> +       report->hog = hog;
> +       report->type = HOG_REPORT_TYPE_FEATURE;
> +       report->value_handle = 0x31;
> +       hog->reports = g_slist_append(hog->reports, report);
> +
> +       if (write_test) {
> +               ev.type = UHID_SET_REPORT;
> +               ev.u.set_report.id = 123;
> +               ev.u.set_report.rtype = UHID_FEATURE_REPORT;
> +               ev.u.set_report.size = 1;
> +               ev.u.set_report.data[0] = 0x55;
> +               set_report(&ev, hog);
> +               g_assert(hog->setrep_att != 0);
> +       } else {
> +               ev.type = UHID_GET_REPORT;
> +               ev.u.get_report.id = 123;
> +               ev.u.get_report.rtype = UHID_FEATURE_REPORT;
> +               get_report(&ev, hog);
> +               g_assert(hog->getrep_att != 0);
> +       }
> +
> +       pump();
> +       n = read(attfd[1], pdu, sizeof(pdu));
> +       g_assert(n >= 3 && pdu[0] == (write_test ? 0x12 : 0x0a));
> +
> +       if (blob) {
> +               uint8_t first[23] = { 0x0b };
> +
> +               g_assert_cmpint(write(attfd[1], first, sizeof(first)),
> +                                               ==, sizeof(first));
> +               pump();
> +               n = read(attfd[1], pdu, sizeof(pdu));
> +               g_assert(n == 5 && pdu[0] == 0x0c);
> +       }
> +
> +       if (!normal) {
> +               bt_hog_detach(hog, true);
> +
> +               if (!reconnect) {
> +                       bt_hog_unref(hog);
> +                       hog = NULL;
> +               }
> +       }
> +
> +       g_assert(write(attfd[1], response, size) == size);
> +       pump();
> +       n = read(uhidfd[1], &reply, sizeof(reply));
> +
> +       if (normal) {
> +               g_assert(n == sizeof(reply));
> +               g_assert(reply.type == UHID_GET_REPORT_REPLY);
> +               g_assert(reply.u.get_report_reply.id == 123);
> +               g_assert(reply.u.get_report_reply.err == 0);
> +               g_assert(reply.u.get_report_reply.data[0] == 0x55);
> +       } else {
> +               g_assert(n == -1 && errno == EAGAIN);
> +       }
> +
> +       if (reconnect) {
> +               /* Reuse the detached object for another report request. */
> +               g_assert(hog->getrep_att == 0 && hog->setrep_att == 0);
> +               hog->attrib = g_attrib_ref(attrib);
> +               ev.u.get_report.id = 124;
> +               get_report(&ev, hog);
> +               pump();
> +               n = read(attfd[1], pdu, sizeof(pdu));
> +               g_assert(n == 3 && pdu[0] == 0x0a);
> +               g_assert(write(attfd[1], response, 2) == 2);
> +               pump();
> +               g_assert_cmpint(read(uhidfd[1], &reply, sizeof(reply)),
> +                                               ==, sizeof(reply));
> +               g_assert(reply.u.get_report_reply.id == 124);
> +               g_assert(reply.u.get_report_reply.err == 0);
> +       }
> +
> +       if (hog)
> +               bt_hog_unref(hog);
> +
> +       g_attrib_unref(attrib);
> +       close(attfd[1]);
> +       close(uhidfd[0]);
> +       close(uhidfd[1]);
> +       pump();
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       g_test_init(&argc, &argv, NULL);
> +
> +       g_test_add_data_func("/hog/detach/read", "read", test_report);
> +       g_test_add_data_func("/hog/detach/blob", "blob", test_report);
> +       g_test_add_data_func("/hog/detach/write", "write", test_report);
> +       g_test_add_data_func("/hog/normal", "normal", test_report);
> +       g_test_add_data_func("/hog/reconnect", "reconnect", test_report);
> +
> +       return g_test_run();
> +}
> --
> 2.43.0
>
>
>
> On Mon, 21 Sep 2026 18:15:15 -0700, Nicholas Hammond
> <nicholas.hammond0@gmail.com> wrote:
> > From: Nick Hammond <blender7@gmail.com>
> >
> > This series fixes outstanding HID report callbacks surviving HoG detach.
> >
> > The investigation started with a bluetoothd crash on Ubuntu BlueZ
> > 5.72-0ubuntu5.5 while reconnecting an MX Keys S keyboard after switching
> > hosts. The saved stack passes through report_reply/get_report_cb,
> > read_blob_helper and attrib_callback_result. The original core and device
> > identifiers are intentionally not included.
> >
> > On current master (17e624d1c), getrep_att and setrep_att still bypass the
> > gatt_op queue cancelled by bt_hog_detach. If another owner retains the
> > GAttrib connection, a late response can invoke a callback after its HoG
> > object/report is freed. A surviving HoG object can also receive a stale
> > reply after detach.
> >
> > A socketpair test on that revision reproduces the read, long-read and
> > write use-after-free under AddressSanitizer. For example, the long-read
> > case reports:
> >
> >   ERROR: AddressSanitizer: heap-use-after-free
> >     get_report_cb       profiles/input/hog-lib.c:929
> >     read_blob_helper    attrib/gatt.c:791
> >     attrib_callback_result attrib/gattrib.c:235
> >     handle_rsp          src/shared/att.c:913
> >
> > This is a lifetime regression test with a shared live GAttrib reference,
> > not an over-the-air reproducer or a claim of unauthenticated reachability.
> > It does not establish that every historical keyboard outage had this
> > cause.
> >
> > Patch 1 cancels the separately tracked report requests before dropping
> > attrib. Patches 2 and 3 add and register five hardware-independent tests.
> > The test includes hog-lib.c to access private report state, avoiding new
> > production APIs and unrelated discovery traffic.
> >
> > Validation on current master plus this series:
> > - AddressSanitizer with detect_leaks=1: all five new tests pass.
> > - Existing test-hog (6), test-gattrib (6), test-gatt (193): all pass.
> > - checkpatch --no-tree --no-signoff: no errors or warnings.
> > - A backport to Ubuntu 5.72 is installed on the affected host; keyboard
> >   and mouse reconnected after restarting the daemon. Long-term stability
> >   is not yet established.
> >
> > To reproduce the failures, apply only patches 2 and 3 to the base revision
> > and build with --enable-asan. Run unit/test-hog-lifetime -p followed by
> > /hog/detach/read, /hog/detach/blob or /hog/detach/write. Each detects a
> > use-after-free without patch 1. /hog/reconnect catches the stale reply;
> > /hog/normal passes before and after the fix.
> >
> > AI assistance disclosure: Codex:gpt-6 analyzed the saved crash, prepared
> > the fix and tests, and ran the validation commands. This contribution
> > includes Assisted-by tags. No claim of an independent human code review
> > is made.
> >
> > Thanks,
> > Nick Hammond
> >
> > Nick Hammond (3):
> >   input/hog: Cancel pending report requests on detach
> >   unit: Test pending HoG reports across detach
> >   build: Register the HoG report lifetime tests
> >
> >  Makefile.am              |  14 ++++
> >  profiles/input/hog-lib.c |  11 +++
> >  unit/test-hog-lifetime.c | 152 +++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 177 insertions(+)
> >  create mode 100644 unit/test-hog-lifetime.c
> >
> >
> > base-commit: 17e624d1cd9a4d94f90e0ca008548456c3455492
> > --
> > 2.43.0
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: Cancel pending HoG reports before detach
  2026-09-22  1:15 ` [PATCH BlueZ 1/3] input/hog: Cancel pending report requests on detach Nicholas Hammond
  2026-09-22  6:36   ` Cancel pending HoG reports before detach bluez.test.bot
@ 2026-10-07 12:06   ` bluez.test.bot
  1 sibling, 0 replies; 7+ messages in thread
From: bluez.test.bot @ 2026-10-07 12:06 UTC (permalink / raw)
  To: linux-bluetooth, nicholas.hammond0

[-- Attachment #1: Type: text/plain, Size: 680 bytes --]

This is an automated email and please do not reply to this email.

Dear Submitter,

This series was picked up by the CI more than 2 weeks ago and the pull
request created for it is still open, which means the series was never
applied to the tree.

   Series:       Cancel pending HoG reports before detach
   Pull Request: https://github.com/bluez/bluez/pull/2563
   Created:      2026-09-22 06:15:05+00:00

The pull request has been closed and no further action is taken on this
series.

If the change should still be considered, it must be resent to the Linux
Bluetooth mailing list (linux-bluetooth@vger.kernel.org) so that it is
picked up again.

---
Regards,
Linux Bluetooth

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-10-07 12:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-22  1:15 [PATCH BlueZ 0/3] Cancel pending HoG reports before detach Nicholas Hammond
2026-09-22  1:15 ` [PATCH BlueZ 1/3] input/hog: Cancel pending report requests on detach Nicholas Hammond
2026-09-22  6:36   ` Cancel pending HoG reports before detach bluez.test.bot
2026-10-07 12:06   ` bluez.test.bot
2026-09-22  1:15 ` [PATCH BlueZ 2/3] unit: Test pending HoG reports across detach Nicholas Hammond
2026-09-22 14:25   ` Luiz Augusto von Dentz
2026-09-22  1:15 ` [PATCH BlueZ 3/3] build: Register the HoG report lifetime tests Nicholas Hammond

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox