|
6 | 6 | from functools import lru_cache, partial |
7 | 7 | from typing import TYPE_CHECKING |
8 | 8 |
|
| 9 | +import cython |
| 10 | + |
9 | 11 | BLE_UUID = "0000-1000-8000-00805f9b34fb" |
10 | 12 | _LOGGER = logging.getLogger(__name__) |
11 | 13 |
|
@@ -265,15 +267,16 @@ def _uncached_parse_advertisement_bytes( |
265 | 267 | # per-iteration bounds branch; any 1-3 byte tail is dropped. |
266 | 268 | safe_end = start + ((end - start) & ~3) |
267 | 269 | for i in range(start, safe_end, 4): |
268 | | - # Assemble via uint local: in Cython the shift-by-24 of an |
269 | | - # unsigned char promotes to signed int and would yield a |
270 | | - # negative value when bit 31 is set; assigning to a |
271 | | - # cython.uint local recovers the unsigned 32-bit value. |
| 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`. |
272 | 275 | uuid32_int = ( |
273 | | - gap_data[i] |
274 | | - | (gap_data[i + 1] << 8) |
275 | | - | (gap_data[i + 2] << 16) |
276 | | - | (gap_data[i + 3] << 24) |
| 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) |
277 | 280 | ) |
278 | 281 | service_uuids.append(_cached_uint32_int_as_uuid(uuid32_int)) |
279 | 282 | elif gap_type_num in { |
@@ -306,11 +309,13 @@ def _uncached_parse_advertisement_bytes( |
306 | 309 | continue |
307 | 310 | if service_data is _EMPTY_SERVICE_DATA: |
308 | 311 | 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). |
309 | 314 | uuid32_int = ( |
310 | | - gap_data[start] |
311 | | - | (gap_data[start + 1] << 8) |
312 | | - | (gap_data[start + 2] << 16) |
313 | | - | (gap_data[start + 3] << 24) |
| 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) |
314 | 319 | ) |
315 | 320 | service_data[_cached_uint32_int_as_uuid(uuid32_int)] = gap_data[ |
316 | 321 | splice_pos:end |
|
0 commit comments