Confusing decoding of standalone break marker; `allow_indefinite=False` still accepts it
- Vorherrschende Sprache
- Rust
- Sterne
- 305
- Forks
- 79
- Ø Merge
- 21 Std. 59 Min.
- Gemergte PRs (30 T.)
- 2
Beschreibung
### Things to check first
- [x] I have searched the existing issues and didn't find my bug already reported there
- [x] I have checked that my bug is still present in the latest release
### cbor2 version
6.0.1
### Python version
3.11.15
### What happened?
I am confused about how `cbor2.loads` handles the break marker (`0xff`) when appearing standalone.
Per [RFC 8949 Section 3.2.1](https://datatracker.ietf.org/doc/html/rfc8949#name-the-break-stop-code):
>The "break" stop code is encoded with major type 7 and additional information value 31 (0b111_11111). It is not itself a data item: it is just a syntactic feature to close an indefinite-length item.
If the "break" stop code appears where a data item is expected, other than directly inside an indefinite-length string, array, or map -- for example, directly inside a definite-length array or map -- the enclosing item is not well-formed.
Previous versions of cbor2 were returning a `break_marker` object, appearing in the public API, but the changelog for 6.0.1 indicates it "removed" from the API as "unnecessary." Now, `cbor2.loads(b"\xff")` returns an object, but the documentation does not say anything about what to do with this object. Only by trial-and-error have I figured out that all calls to `cbor2.loads(b"\xff")` return the same object.
This holds wherever `0xff` occurs: a definite-length array where one of the elements is `0xff` is accepted, and the array element is decoded to the same unlabeled break marker object.
Moreover, since 6.0 now introduces an `allow_indefinite` option to disable indefinite-length decoding, I would have expected `cbor2.loads(b"\xff", allow_indefinite=False)` to reject and raise `cbor2.CBORDecodeError`, but no such exception is raised, and the unlabeled break marker object is returned instead.
Are all of these behaviors intended? If so, it would be nice to please document them. Thanks!
### How can we reproduce the bug?
Running the following Python code will exit with code 1, whereas I would have expected 0.
```python
import sys
import cbor2
from importlib.metadata import version as _pkg_version
CASES = [
# (label, hex, expected_description, kwargs)
("lone break", "ff", "single 0xff", {}),
("lone break, allow_indefinite=False", "ff", "single 0xff", {"allow_indefinite": False}),
("definite array [1, BREAK, 2]", "8301ff02", "def-array of 3 items, middle is 0xff", {}),
("definite array [BREAK]", "81ff", "def-array of 1 item: 0xff", {}),
("definite map {1: BREAK}", "a101ff", "def-map, value is 0xff", {}),
("definite map {BREAK: 1}", "a1ff01", "def-map, key is 0xff", {}),
("nested [[BREAK], 1]", "8281ff01", "def-array containing a def-array of 0xff", {}),
("tag(100000) wrapping BREAK", "da000186a0ff", "generic tag whose tagged value is 0xff", {}),
]
def run(label, hex_bytes, kwargs):
data = bytes.fromhex(hex_bytes)
try:
result = cbor2.loads(data, **kwargs)
except cbor2.CBORDecodeError as e:
print(f"[OK] {label:<42} -> CBORDecodeError: {e}")
return True
print(f"[BUG] {label:<42} -> {result!r}")
return False
print(f"cbor2 version: {_pkg_version('cbor2')}")
print(f"python: {sys.version.split()[0]}")
print()
ok = True
for label, hexb, _desc, kwargs in CASES:
ok &= run(label, hexb, kwargs)
# The sentinel cannot be identified through the public API.
LONE = b"\xff"
print()
print(f"singleton across calls? {cbor2.loads(LONE) is cbor2.loads(LONE)}")
print(f"public 'break_marker' exported? {'break_marker' in dir(cbor2)}")
sys.exit(0 if ok else 1)
```
Current output (address may be different, but is the same across all 8 tests):
```
cbor2 version: 6.0.1
python: 3.11.15
[BUG] lone break ->
[BUG] lone break, allow_indefinite=False ->
[BUG] definite array [1, BREAK, 2] -> [1, , 2]
[BUG] definite array [BREAK] -> []
[BUG] definite map {1: BREAK} -> {1: }
[BUG] definite map {BREAK: 1} -> {: 1}
[BUG] nested [[BREAK], 1] -> [[], 1]
[BUG] tag(100000) wrapping BREAK -> CBORTag(100000, )
singleton across calls? True
public 'break_marker' exported? False
```
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Bewertung
Dieses Issue wurde noch nicht bewertet.