55
66from __future__ import annotations
77
8- # Cap mirrors the #2118 mojibake size; keeps exception text readable in logs .
8+ # Cap sized for the #2118 mojibake without flooding exception text.
99_PREVIEW_MAX_BYTES = 64
1010
1111
1212def _bounded_hex_preview (data : bytes , max_bytes : int = _PREVIEW_MAX_BYTES ) -> str :
13- # NUL terminates C strings; bytes past it are not the returned value.
14- # Marker is explicit so a reader does not misread truncation as empty.
13+ # Bytes after the first NUL are not part of the returned C string. The
14+ # marker is explicit so truncation cannot be misread as an empty value .
1515 nul = data .find (b"\x00 " )
1616 nul_stopped = nul != - 1
1717 visible_end = len (data ) if not nul_stopped else nul
@@ -30,13 +30,12 @@ def _bounded_hex_preview(data: bytes, max_bytes: int = _PREVIEW_MAX_BYTES) -> st
3030def decode_c_str (data : bytes , api_name : str ) -> str :
3131 """Decode ``data`` as UTF-8, or raise ``UnicodeDecodeError`` with ``api_name`` and a bounded hex preview in ``reason``.
3232
33- Internal API. ``api_name`` is trusted caller input and is embedded verbatim.
33+ Internal API. ``api_name`` is trusted caller input and embedded verbatim.
3434 """
3535 try :
3636 return data .decode ("utf-8" )
3737 except UnicodeDecodeError as e :
38- # Same exception type, not a subclass: existing `except UnicodeDecodeError`
39- # keeps working. Original chained via `from e`.
38+ # Same exception type, not a subclass, so existing handlers still catch.
4039 preview = _bounded_hex_preview (data )
4140 reason = f"{ e .reason } (returned by { api_name } ; bytes={ preview } )"
4241 raise UnicodeDecodeError (e .encoding , e .object , e .start , e .end , reason ) from e
0 commit comments