Skip to content

Commit 0ca2ce8

Browse files
fix: reject negative n in read_bytes and peek_bytes
read_bytes(-n) silently decremented _pos, corrupting the buffer and allowing re-reads of already-consumed data. peek_bytes(-n) returned empty bytes without error. Both now raise ValueError for negative n. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ee37dd3 commit 0ca2ce8

2 files changed

Lines changed: 27 additions & 0 deletions

File tree

src/dqlitewire/buffer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,10 @@ def read_bytes(self, n: int) -> bytes | None:
403403
404404
Returns None if not enough data available.
405405
Raises ``ProtocolError`` if the buffer is poisoned.
406+
Raises ``ValueError`` if *n* is negative.
406407
"""
408+
if n < 0:
409+
raise ValueError(f"n must be non-negative, got {n}")
407410
self._check_poisoned()
408411
available = len(self._data) - self._pos
409412
if available < n:
@@ -430,7 +433,10 @@ def peek_bytes(self, n: int) -> bytes | None:
430433
validate the bytes before deciding whether to consume them.
431434
432435
Raises ``ProtocolError`` if the buffer is poisoned.
436+
Raises ``ValueError`` if *n* is negative.
433437
"""
438+
if n < 0:
439+
raise ValueError(f"n must be non-negative, got {n}")
434440
self._check_poisoned()
435441
available = len(self._data) - self._pos
436442
if available < n:

tests/test_buffer.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,27 @@ def test_read_bytes_not_enough(self) -> None:
118118
assert data is None
119119
assert buf.available() == 2
120120

121+
def test_read_bytes_negative_n_raises(self) -> None:
122+
"""read_bytes with negative n must raise, not corrupt _pos."""
123+
import pytest
124+
125+
buf = ReadBuffer()
126+
buf.feed(b"hello world")
127+
with pytest.raises(ValueError, match="non-negative"):
128+
buf.read_bytes(-1)
129+
# Buffer state must be unchanged
130+
assert buf.available() == 11
131+
132+
def test_peek_bytes_negative_n_raises(self) -> None:
133+
"""peek_bytes with negative n must raise, not return empty bytes."""
134+
import pytest
135+
136+
buf = ReadBuffer()
137+
buf.feed(b"hello world")
138+
with pytest.raises(ValueError, match="non-negative"):
139+
buf.peek_bytes(-1)
140+
assert buf.available() == 11
141+
121142
def test_has_message_incomplete(self) -> None:
122143
buf = ReadBuffer()
123144
# Feed only header

0 commit comments

Comments
 (0)