Skip to content

fix(gap): iterate 128-bit service UUID lists, skip malformed lengths#226

Merged
bdraco merged 2 commits into
mainfrom
koan/gap-128bit-uuid-list
May 16, 2026
Merged

fix(gap): iterate 128-bit service UUID lists, skip malformed lengths#226
bdraco merged 2 commits into
mainfrom
koan/gap-128bit-uuid-list

Conversation

@bluetoothbot
Copy link
Copy Markdown
Contributor

@bluetoothbot bluetoothbot commented May 15, 2026

What

The 128-bit Service UUID AD type parser now iterates the payload as a list of UUIDs and discards a non-16-byte tail.

Why

Core Spec Vol 3 Part C §11 defines AD types 0x06 / 0x07 as lists (length = 1 + 16N), not single UUIDs. The parser had been treating them as single, which produced two silent regressions:

  • Multiple 128-bit UUIDs in one AD struct (legal in scan responses and BLE-5 extended advertising) yielded one garbled 64-hex-char string instead of two valid UUIDs.
  • Malformed lengths (not 1 + 16N) produced bogus UUIDs (all-zeros for short, hex garbage for long) instead of being skipped.

How

Replace the single append() with the same for i in range(start, end, 16) + if i + 16 <= end pattern the 16-bit and 32-bit branches already use. i is already declared cython.uint in gap.pxd, so no .pxd churn.

Testing

  • pytest tests/ --ignore=tests/benchmarks --ignore=bench → 69 passed (2 new).
  • Pure-Python via SKIP_CYTHON=1 → 58 passed.
  • Cython compile sanity check via cythonize → OK.

New tests cover:

  • Two 128-bit UUIDs in one AD struct, verifying both come back in little-endian-reversed canonical form.
  • Length 9 (too short) and length 17 (one valid UUID + 1-byte tail) variants, verifying the malformed bytes are skipped rather than folded into a fake UUID.

Quality Report

Changes: 2 files changed, 52 insertions(+), 1 deletion(-)

Code scan: clean

Tests: failed (FAILED)

Branch hygiene: clean

Generated by Kōan post-mission quality pipeline

bluetoothbot and others added 2 commits May 15, 2026 22:47
The Core Spec Vol 3 Part C §11 defines the 128-bit Complete/Incomplete
Service UUID AD types as a *list* of UUIDs (length = 1 + 16N), but the
parser was treating it as a single UUID. Two regressions resulted:

- Multiple 128-bit UUIDs packed into one AD struct (possible in scan
  responses and BLE-5 extended advertising) returned a single bogus
  64-hex-char string instead of two UUIDs.
- Malformed payloads (length not 1 + 16N) produced bogus UUID strings
  (all-zero for short, garbage for long) instead of being skipped.

Iterate in 16-byte steps like the 16-/32-bit branches already do, and
drop any non-16-byte tail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (47368a8) to head (82141ac).

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #226   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            6         6           
  Lines          248       250    +2     
  Branches        37        39    +2     
=========================================
+ Hits           248       250    +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 15, 2026

Merging this PR will not alter performance

✅ 9 untouched benchmarks


Comparing koan/gap-128bit-uuid-list (82141ac) with main (47368a8)

Open in CodSpeed

@bdraco bdraco requested a review from Copilot May 16, 2026 03:30
@bdraco bdraco marked this pull request as ready for review May 16, 2026 03:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes parsing of GAP AD types 0x06/0x07 (128-bit Service UUID lists) to correctly iterate the payload as a list of 16-byte UUIDs and to ignore any trailing malformed remainder, aligning behavior with the Bluetooth Core Spec and the existing 16/32-bit UUID list parsing approach.

Changes:

  • Update 128-bit Service UUID AD parsing to iterate in 16-byte chunks and skip trailing non-16-byte tails.
  • Add tests covering multiple 128-bit UUIDs in one AD structure and malformed-length handling (too-short and trailing-byte cases).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/bluetooth_data_tools/gap.py Parse 128-bit service UUID AD structures as lists of 16-byte UUIDs; ignore trailing remainder bytes.
tests/test_gap.py Add regression tests for multiple 128-bit UUIDs per AD structure and malformed-length payload behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bdraco bdraco merged commit 6bea1ea into main May 16, 2026
52 checks passed
@bdraco bdraco deleted the koan/gap-128bit-uuid-list branch May 16, 2026 04:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants