Add beginWriteOperation() guards to all blocking GATT methods

writeCharacteristic(), read(), and enableNotifications() resolve
characteristic pointers under _conn_mutex then call blocking GATT
ops after releasing it — same pattern as write(). Without the
active-operation guard, processPendingDisconnects() could delete
the client (and its child characteristics) during the GATT call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
torlando-tech
2026-03-04 23:54:01 -05:00
parent 71bc4ae82b
commit fffd8ec79e
+14 -3
View File
@@ -1780,7 +1780,10 @@ bool NimBLEPlatform::writeCharacteristic(uint16_t conn_handle, uint16_t char_han
if (!chr) return false;
return chr->writeValue(data.data(), data.size(), response);
beginWriteOperation();
bool result = chr->writeValue(data.data(), data.size(), response);
endWriteOperation();
return result;
}
bool NimBLEPlatform::read(uint16_t conn_handle, uint16_t char_handle,
@@ -1833,7 +1836,9 @@ bool NimBLEPlatform::read(uint16_t conn_handle, uint16_t char_handle,
return false;
}
beginWriteOperation();
NimBLEAttValue value = chr->readValue();
endWriteOperation();
if (callback) {
Bytes result(value.data(), value.size());
callback(OperationResult::SUCCESS, result);
@@ -1903,9 +1908,15 @@ bool NimBLEPlatform::enableNotifications(uint16_t conn_handle, bool enable) {
}
};
return txChar->subscribe(true, notifyCb);
beginWriteOperation();
bool result = txChar->subscribe(true, notifyCb);
endWriteOperation();
return result;
} else {
return txChar->unsubscribe();
beginWriteOperation();
bool result = txChar->unsubscribe();
endWriteOperation();
return result;
}
}