Skip to content

Commit a4d4481

Browse files
committed
Bluetooth: Host: Fix use of local variable as atomic target
In bt_conn_unref(), the local, non shared, variable "old" is used as an atomic target: atomic_val_t old = atomic_dec(&conn->ref); conn = NULL; bool deallocated = (atomic_get(&old) == 1); The above call to atomic_get() does not prevent any data race or value obsolescence. The resulting additional memory barrier does not seem necessary either. If pedantic, one could also note that 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. While rewording comments,also emphasize that using freed slots to automatically resume advertising from bt_conn_unref() is a deprecated behavior. Signed-off-by: Christophe Dufaza <[email protected]>
1 parent 77bb19c commit a4d4481

File tree

1 file changed

+22
-13
lines changed

1 file changed

+22
-13
lines changed

subsys/bluetooth/host/conn.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,40 +1530,49 @@ static K_WORK_DEFINE(recycled_work, recycled_work_handler);
15301530
void bt_conn_unref(struct bt_conn *conn)
15311531
{
15321532
atomic_val_t old;
1533-
bool deallocated;
15341533
enum bt_conn_type conn_type;
15351534
uint8_t conn_role;
15361535
uint16_t conn_handle;
15371536

15381537
__ASSERT(conn, "Invalid connection reference");
15391538

1540-
/* Storing parameters of interest so we don't access the object
1541-
* after decrementing its ref-count
1539+
/* If we're removing the last reference, the connection object will be
1540+
* considered recycled and possibly reused by the Bluetooth Host stack
1541+
* as soon as we decrement the counter.
1542+
* To prevent access to a recycled connection object, we store
1543+
* the parameters of interest before updating the reference count,
1544+
* then unset the connection pointer.
15421545
*/
15431546
conn_type = conn->type;
15441547
conn_role = conn->role;
15451548
conn_handle = conn->handle;
15461549

15471550
old = atomic_dec(&conn->ref);
1548-
/* Prevent from accessing connection object */
15491551
conn = NULL;
1550-
deallocated = (atomic_get(&old) == 1);
15511552

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

15541555
__ASSERT(old > 0, "Conn reference counter is 0");
15551556

1556-
/* Slot has been freed and can be taken. No guarantees are made on requests
1557-
* to claim connection object as only the first claim will be served.
1558-
*/
1559-
if (deallocated) {
1557+
if (old - 1 == 0) {
1558+
/* We removed the last reference: notify listeners that a slot has been
1559+
* freed and can be taken. No guarantees are made on requests
1560+
* to claim the connection object, the first claim will be served.
1561+
*/
15601562
k_sem_give(&pending_recycled_events);
15611563
k_work_submit(&recycled_work);
1562-
}
15631564

1564-
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn_type == BT_CONN_TYPE_LE &&
1565-
conn_role == BT_CONN_ROLE_PERIPHERAL && deallocated) {
1566-
bt_le_adv_resume();
1565+
/* Use the freed slot to automatically resume LE peripheral advertising.
1566+
*
1567+
* This behavior is deprecated:
1568+
* - 8cfad44: Bluetooth: Deprecate adv auto-resume
1569+
* - #72567: Bluetooth: Advertising resume functionality is broken
1570+
* - Migration guide to Zephyr v4.0.0, Automatic advertiser resumption is deprecated
1571+
*/
1572+
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn_type == BT_CONN_TYPE_LE &&
1573+
conn_role == BT_CONN_ROLE_PERIPHERAL) {
1574+
bt_le_adv_resume();
1575+
}
15671576
}
15681577
}
15691578

0 commit comments

Comments
 (0)