Skip to content

Commit dfb3d7a

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 3da3959 commit dfb3d7a

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

subsys/bluetooth/host/conn.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,33 +1492,44 @@ 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-
15021505
old = atomic_dec(&conn->ref);
1503-
/* Prevent from accessing connection object */
1504-
deallocated = (atomic_get(&old) == 1);
1505-
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")));
15081506
conn = NULL;
15091507

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

15121510
__ASSERT(old > 0, "Conn reference counter is 0");
15131511

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.
1512+
deallocated = (old == 1);
1513+
IF_ENABLED(CONFIG_BT_CONN_TX,
1514+
(__ASSERT(!(deallocated && k_work_is_pending(&conn->tx_complete_work)),
1515+
"tx_complete_work is pending when conn is deallocated")));
1516+
1517+
/* Notify listeners that a slot has been freed and can be taken.
1518+
* No guarantees are made on requests to claim connection object
1519+
* as only the first claim will be served.
15161520
*/
15171521
if (deallocated) {
15181522
k_sem_give(&pending_recycled_events);
15191523
k_work_submit(&recycled_work);
15201524
}
15211525

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

0 commit comments

Comments
 (0)