Skip to content

Commit 6dcf102

Browse files
committed
fix: resolve CI failures on Bluetooth-Devices#253 (attempt 1)
1 parent 4517c45 commit 6dcf102

2 files changed

Lines changed: 29 additions & 17 deletions

File tree

src/bluetooth_data_tools/gap.pxd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ cpdef parse_advertisement_data(object data)
5656
safe_end=cython.uint,
5757
i=cython.uint,
5858
tx_power_byte="unsigned char",
59+
uuid32_b0=cython.uint,
60+
uuid32_b1=cython.uint,
61+
uuid32_b2=cython.uint,
62+
uuid32_b3=cython.uint,
5963
uuid32_int=cython.uint,
6064
)
6165
cpdef _uncached_parse_advertisement_bytes(bytes gap_bytes)

src/bluetooth_data_tools/gap.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
from functools import lru_cache, partial
77
from typing import TYPE_CHECKING
88

9-
import cython
10-
119
BLE_UUID = "0000-1000-8000-00805f9b34fb"
1210
_LOGGER = logging.getLogger(__name__)
1311

@@ -267,16 +265,21 @@ def _uncached_parse_advertisement_bytes(
267265
# per-iteration bounds branch; any 1-3 byte tail is dropped.
268266
safe_end = start + ((end - start) & ~3)
269267
for i in range(start, safe_end, 4):
270-
# Cast each byte to unsigned int before shifting: in C an
271-
# `unsigned char` operand of `<<` is promoted to (signed)
272-
# `int`, so `gap_data[i + 3] << 24` would be undefined
273-
# behavior when bit 31 is set. Casting keeps the operation
274-
# well-defined on `unsigned int`.
268+
# Stage each byte through an unsigned-int local (declared in
269+
# gap.pxd) before shifting: in C an `unsigned char` operand
270+
# of `<<` is promoted to (signed) `int`, so
271+
# `gap_data[i + 3] << 24` would be undefined behavior when
272+
# bit 31 is set. Assigning to the typed local first keeps
273+
# the shift well-defined on `unsigned int`.
274+
uuid32_b0 = gap_data[i]
275+
uuid32_b1 = gap_data[i + 1]
276+
uuid32_b2 = gap_data[i + 2]
277+
uuid32_b3 = gap_data[i + 3]
275278
uuid32_int = (
276-
cython.cast(cython.uint, gap_data[i])
277-
| (cython.cast(cython.uint, gap_data[i + 1]) << 8)
278-
| (cython.cast(cython.uint, gap_data[i + 2]) << 16)
279-
| (cython.cast(cython.uint, gap_data[i + 3]) << 24)
279+
uuid32_b0
280+
| (uuid32_b1 << 8)
281+
| (uuid32_b2 << 16)
282+
| (uuid32_b3 << 24)
280283
)
281284
service_uuids.append(_cached_uint32_int_as_uuid(uuid32_int))
282285
elif gap_type_num in {
@@ -309,13 +312,18 @@ def _uncached_parse_advertisement_bytes(
309312
continue
310313
if service_data is _EMPTY_SERVICE_DATA:
311314
service_data = {}
312-
# Cast each byte to unsigned int before shifting to keep the
313-
# << 24 well-defined (see TYPE_32BIT_SERVICE_UUID_* branch above).
315+
# Stage each byte through an unsigned-int local before shifting
316+
# to keep the << 24 well-defined (see TYPE_32BIT_SERVICE_UUID_*
317+
# branch above).
318+
uuid32_b0 = gap_data[start]
319+
uuid32_b1 = gap_data[start + 1]
320+
uuid32_b2 = gap_data[start + 2]
321+
uuid32_b3 = gap_data[start + 3]
314322
uuid32_int = (
315-
cython.cast(cython.uint, gap_data[start])
316-
| (cython.cast(cython.uint, gap_data[start + 1]) << 8)
317-
| (cython.cast(cython.uint, gap_data[start + 2]) << 16)
318-
| (cython.cast(cython.uint, gap_data[start + 3]) << 24)
323+
uuid32_b0
324+
| (uuid32_b1 << 8)
325+
| (uuid32_b2 << 16)
326+
| (uuid32_b3 << 24)
319327
)
320328
service_data[_cached_uint32_int_as_uuid(uuid32_int)] = gap_data[
321329
splice_pos:end

0 commit comments

Comments
 (0)