Skip to content

Commit 918e0dd

Browse files
committed
pyexpat, sys: state why the two name unwraps are the strict encode
`parser_create3` and `sys_audit` both take their name argument through `str_utf8_w`, which refuses a lone surrogate, where `space.text_w` upstream does not. Neither site said why. For pyexpat the reason is a reader: both stored names come back out through `w_str_get_value`, which panics on a lone surrogate -- `declared_or_forced_encoding` for the encoding, `namespace_separator` for the separator. The refusal at the door is what keeps those reads from aborting the process. The `namespace_separator` arm carried no comment at all; the encoding arm's pointed at the separator arm rather than at the reader. For `sys.audit` nothing stores the event, so the encode exists only for the error it raises; the doc comment now says so. Comment-only. Assisted-by: Claude
1 parent d83185d commit 918e0dd

2 files changed

Lines changed: 13 additions & 3 deletions

File tree

pyre/pyre-interpreter/src/module/pyexpat/mod.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,14 +1764,20 @@ fn parser_create3(
17641764
if unsafe { !is_str(encoding) } {
17651765
return Err(parser_create_not_str("encoding", encoding));
17661766
}
1767-
// The name reaches the expat setup as a `&str`, the same view the
1768-
// sibling `namespace_separator` arm takes below: a value with no UTF-8
1769-
// spelling is refused here rather than at that read.
1767+
// Both stored names are read back through `w_str_get_value`, which
1768+
// panics on a lone surrogate — `declared_or_forced_encoding` for this
1769+
// one, `namespace_separator` for the other. A name with no UTF-8
1770+
// spelling is refused here so that read cannot abort the process;
1771+
// `space.text_w` has no such reader behind it and so does not need the
1772+
// refusal.
17701773
crate::baseobjspace::str_utf8_w(encoding)?;
17711774
crate::baseobjspace::setdictvalue_native(parser, "_pyre_forced_encoding", encoding);
17721775
}
17731776
if unsafe { is_none(namespace_separator) } {
17741777
} else if unsafe { is_str(namespace_separator) } {
1778+
// `namespace_separator` reads this back through `w_str_get_value`, so
1779+
// the refusal the encoding arm makes applies here too; the length check
1780+
// below then runs on a value that has a `&str` view.
17751781
let value = crate::baseobjspace::str_utf8_w(namespace_separator)?;
17761782
if value.chars().count() > 1 {
17771783
return Err(crate::PyError::value_error(

pyre/pyre-interpreter/src/module/sys/vm.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,6 +2460,10 @@ pub fn register_module(ns: pyre_object::PyObjectRef) {
24602460
/// event name has to be a `str` with a UTF-8 spelling, and the parameters are
24612461
/// positional-only, so every stdlib `sys.audit(...)` call reports a bad event
24622462
/// name at the call rather than carrying it to whichever hook reads it.
2463+
///
2464+
/// The unwrap is `str_utf8_w` and not a surrogate-tolerant read even though
2465+
/// nothing stores the event: the encode is there for the error it raises, so an
2466+
/// event name holding a lone surrogate is a `UnicodeEncodeError` at the call.
24632467
fn sys_audit(args: &[PyObjectRef]) -> crate::PyResult {
24642468
let (positional, kwargs) = crate::builtins::split_builtin_kwargs(args);
24652469
if crate::builtins::has_real_kwargs(kwargs) {

0 commit comments

Comments
 (0)