Skip to content

Commit 175f5ab

Browse files
committed
Bluetooth: Host: Fix use of local variable as atomic target
In bt_conn_unref(), a local variable is used as an atomic target: atomic_val_t old = atomic_dec(&conn->ref); /* Prevent from accessing connection object */ bool deallocated = (atomic_get(&old) == 1); conn = NULL; The above call to atomic_get() cannot prevent any data race or value staleness, and only causes confusion. The comment that seems associated can also be misleading. If pedantic, we can observe that in any case atomic_get() expects an atomic_t* argument (target), not an atomic_val_t* (value). This compiles and /works/ just fine since the Zephyr Atomic API defines both to be the same integer type. The equivalent C11 code, where _Atomic(T) and T are different types, wouldn't compile. Also add a comment to remind that automatic advertiser resumption is deprecated. Signed-off-by: Christophe Dufaza <[email protected]>
1 parent c4af18d commit 175f5ab

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

subsys/bluetooth/host/conn.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,33 +1492,46 @@ void bt_conn_unref(struct bt_conn *conn)
14921492

14931493
__ASSERT(conn, "Invalid connection reference");
14941494

1495-
/* Storing parameters of interest so we don't access the object
1496-
* after decrementing its ref-count
1495+
/* If we're removing the last reference, the connection object will be
1496+
* considered freed and possibly reused by the Bluetooth Host stack
1497+
* as soon as we decrement the counter.
1498+
* To prevent access to such a recycled object, we store the parameters
1499+
* of interest before decrementing the reference count,
1500+
* then unset the connection pointer.
14971501
*/
14981502
conn_type = conn->type;
14991503
conn_role = conn->role;
15001504
conn_handle = conn->handle;
1501-
1502-
old = atomic_dec(&conn->ref);
1503-
/* Prevent from accessing connection object */
1504-
deallocated = (atomic_get(&old) == 1);
15051505
IF_ENABLED(CONFIG_BT_CONN_TX,
1506-
(__ASSERT(!(deallocated && k_work_is_pending(&conn->tx_complete_work)),
1507-
"tx_complete_work is pending when conn is deallocated")));
1506+
(bool conn_tx_is_pending = k_work_is_pending(&conn->tx_complete_work);));
1507+
old = atomic_dec(&conn->ref);
15081508
conn = NULL;
15091509

15101510
LOG_DBG("handle %u ref %ld -> %ld", conn_handle, old, (old - 1));
15111511

15121512
__ASSERT(old > 0, "Conn reference counter is 0");
15131513

1514-
/* Slot has been freed and can be taken. No guarantees are made on requests
1515-
* to claim connection object as only the first claim will be served.
1514+
deallocated = (old == 1);
1515+
IF_ENABLED(CONFIG_BT_CONN_TX,
1516+
(__ASSERT(!(deallocated && conn_tx_is_pending),
1517+
"tx_complete_work is pending when conn is deallocated")));
1518+
1519+
/* Notify listeners that a slot has been freed and can be taken.
1520+
* No guarantees are made on requests to claim connection object
1521+
* as only the first claim will be served.
15161522
*/
15171523
if (deallocated) {
15181524
k_sem_give(&pending_recycled_events);
15191525
k_work_submit(&recycled_work);
15201526
}
15211527

1528+
/* Use the freed slot to automatically resume LE peripheral advertising.
1529+
*
1530+
* This behavior is deprecated:
1531+
* - 8cfad44: Bluetooth: Deprecate adv auto-resume
1532+
* - #72567: Bluetooth: Advertising resume functionality is broken
1533+
* - Migration guide to Zephyr v4.0.0, Automatic advertiser resumption is deprecated
1534+
*/
15221535
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn_type == BT_CONN_TYPE_LE &&
15231536
conn_role == BT_CONN_ROLE_PERIPHERAL && deallocated) {
15241537
bt_le_adv_resume();

0 commit comments

Comments
 (0)