`codecs.StreamReader.read()` silently drops an incomplete character at the end of the stream
維護者通常 1 天內回覆
評估
研究方向
Start with Lib/codecs.py around the StreamReader.read() implementation and the linked expected-failure test StreamReaderTruncationBug.test_read_reports_truncated_input from PR #160155. Compare its end-of-stream behavior with IncrementalDecoder.decode(b'', final=True) and check the reported UTF-8, UTF-16, UTF-32, and escape-codec cases. Done means truncated input raises or uses the selected error handler instead of being silently discarded.
由索引模型根據 Issue 內容生成。
描述
Bug description
StreamReader.read() decodes with the stateless codec function and keeps any undecoded trailing bytes for the next call. When the stream is exhausted there is no next call, so an incomplete final character is neither reported nor replaced; it just disappears:
>>> import codecs, io
>>> reader = codecs.getreader('utf-8')(io.BytesIO(b'ab\xe2'))
>>> reader.read()
'ab'
>>> reader.read()
''
Every other way of decoding the same bytes either raises or applies the error handler:
>>> b'ab\xe2'.decode('utf-8')
Traceback (most recent call last):
File "<python-input-3>", line 1, in <module>
b'ab\xe2'.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe2 in position 2: unexpected end of data
>>> io.TextIOWrapper(io.BytesIO(b'ab\xe2'), encoding='utf-8').read()
Traceback (most recent call last):
...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe2 in position 2: unexpected end of data
>>> codecs.getreader('utf-8')(io.BytesIO(b'ab\xe2'), 'replace').read()
'ab'
>>> b'ab\xe2'.decode('utf-8', 'replace')
'ab�'
So with errors='strict' a truncated file reads as if it were well-formed, and with 'replace' the replacement character that would mark the damage is missing. The same happens with utf-16, utf-32 and the escape codecs (unicode_escape with a trailing backslash); the CJK codecs are not affected, because their stateless decoders raise on an incomplete sequence themselves.
The cause is in read(): self.decode is the codec's stateless function with its default final=False (Lib/codecs.py line 512), and the loop exits on empty newdata without ever telling the decoder that the input is complete; self.bytebuffer keeps the fragment forever. Fixing it would mean a final decode pass once the underlying stream returns nothing, and raising (or applying the handler) if bytes remain, which is what IncrementalDecoder.decode(b'', final=True) does. The incremental decoders did not exist when StreamReader was written, which I assume is how this came about.
I realise codecs.open() is deprecated since 3.14 and StreamReader is on its way out with it, so feel free to say this is not worth touching; but it is silent data loss in the strict mode, which seemed worth having on record.
This is the same mechanism as #56717 (bpo-12508, 2011), which describes it for UTF-8 with errors='replace' and has had no activity since; I am filing it anyway because it applies to every codec with multi-byte characters and the strict-mode data loss is the part that matters, but feel free to fold this into that one.
Found by the Hypothesis tests in #160155, where it is pinned as StreamReaderTruncationBug.test_read_reports_truncated_input under expectedFailure.
CPython versions tested on
CPython main (6e1bd24e4d8)
Operating systems tested on
Linux
- 主要語言
- Python
- 星號
- 77.7k
- 分支
- 38.3k
- 平均合併
- 13 小時 30 分鐘
- 30 天內合併 PR
- 708
環境準備
在瀏覽器裡用你自己的 GitHub 帳號啟動這個專案的開發容器。
- 沒有 Dockerfile 或 Docker Compose 檔案
- 有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
python/cpython 的其他 Issue
-
tarfile: extractfile(member).read() of a sparse member is slow due to repeated bytes concatenation未關閉performance stdlib
難度 2/5 1-3 小時 新手友好度 75/100
維護者通常 1 天內回覆
-
tests topic-profiling type-bug
難度 2/5 1-3 小時 新手友好度 78/100
python/cpython#160334 · 1 則留言 ·
維護者通常 1 天內回覆
-
`iso2022_jp_3` encodes U+9B1D but decodes the result as U+9B1C可能已有人在做 @kinqsradio 於 1 天前認領。 未關閉extension-modules type-bug
難度 2/5 1-3 小時 新手友好度 84/100
維護者通常 1 天內回覆
-
interpreter-core type-feature
難度 1/5 1 小時以內 新手友好度 78/100
python/cpython#160109 · 1 則留言 ·
維護者通常 1 天內回覆
-
extension-modules type-bug
難度 2/5 1-3 小時 新手友好度 72/100
python/cpython#160001 · 3 則留言 ·
維護者通常 1 天內回覆
相似的 Issue
-
fix(ui): serve bundled fonts from the gateway可能已有人在做 @dkritarth 今天認領。 未關閉agent: in-progress agent: ready P3 type: bug
難度 2/5 1-3 小時 新手友好度 72/100
dkritarth/scopewatch#336 · 1 則留言 ·
維護者通常 1 天內回覆
-
bob
難度 1/5 1-3 小時 新手友好度 72/100
khuisman/mcp-gee-sweet#1267 ·
維護者通常 1 天內回覆
-
bug confirmed issue
難度 2/5 1-3 小時 新手友好度 68/100
open-webui/open-webui#33285 · 1 則留言 ·
維護者通常 1 天內回覆
-
tv-list
難度 2/5 1-3 小時 新手友好度 66/100
Gathin23/cleanyourtv#2337 ·
維護者通常 1 天內回覆
-
bug P2
難度 2/5 1-3 小時 新手友好度 84/100
維護者通常 1 天內回覆