mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Fix panic in code.replace() with non-interned strings (#8471)
code.replace() called as_interned_str().unwrap() on its string arguments, which panics when the caller passes a string that has not been interned. modulefinder's replace_paths_in_code() builds a fresh co_filename, so any use of ModuleFinder(replace_paths=...) aborted the interpreter. Intern the incoming strings instead, and raise TypeError rather than panicking when a non-string appears in co_names/co_varnames/ co_cellvars/co_freevars. Unskips test_modulefinder.test_replace_paths. Co-authored-by: Pablo Garcia <pablito@MacBook-Neo-de-Pablo.local>
This commit is contained in:
1 parent
d6161ac321
commit
ecfc5cd578
2 files changed
+19
-21
No files matched your search
Vendored
-2
@@ -390,8 +390,6 @@ class ModuleFinderTest(unittest.TestCase):
|
||||
os.remove(source_path)
|
||||
self._do_test(bytecode_test)
|
||||
|
||||
# TODO: RUSTPYTHON; panics at code.rs with 'called Option::unwrap() on a None value'
|
||||
@unittest.skip("TODO: RUSTPYTHON; panics in co_filename replacement")
|
||||
def test_replace_paths(self):
|
||||
old_path = os.path.join(self.test_dir, 'a', 'module.py')
|
||||
new_path = os.path.join(self.test_dir, 'a', 'spam.py')
|
||||
|
||||
@@ -1366,19 +1366,25 @@ impl PyCode {
|
||||
OptionalArg::Missing => self.code.instructions.clone(),
|
||||
};
|
||||
|
||||
let intern_all = |objs: Vec<PyObjectRef>, field: &str| -> PyResult<Box<[_]>> {
|
||||
objs.into_iter()
|
||||
.map(|o| {
|
||||
let s = o.downcast_ref::<super::pystr::PyStr>().ok_or_else(|| {
|
||||
vm.new_type_error(format!("{field} must be a tuple of strings"))
|
||||
})?;
|
||||
Ok(vm.ctx.intern_str(s.as_wtf8()))
|
||||
})
|
||||
.collect::<PyResult<Vec<_>>>()
|
||||
.map(Vec::into_boxed_slice)
|
||||
};
|
||||
|
||||
let cellvars = match co_cellvars {
|
||||
OptionalArg::Present(cellvars) => cellvars
|
||||
.into_iter()
|
||||
.map(|o| o.as_interned_str(vm).unwrap())
|
||||
.collect(),
|
||||
OptionalArg::Present(cellvars) => intern_all(cellvars, "co_cellvars")?,
|
||||
OptionalArg::Missing => self.code.cellvars.clone(),
|
||||
};
|
||||
|
||||
let freevars = match co_freevars {
|
||||
OptionalArg::Present(freevars) => freevars
|
||||
.into_iter()
|
||||
.map(|o| o.as_interned_str(vm).unwrap())
|
||||
.collect(),
|
||||
OptionalArg::Present(freevars) => intern_all(freevars, "co_freevars")?,
|
||||
OptionalArg::Missing => self.code.freevars.clone(),
|
||||
};
|
||||
|
||||
@@ -1411,10 +1417,10 @@ impl PyCode {
|
||||
posonlyarg_count,
|
||||
arg_count,
|
||||
kwonlyarg_count,
|
||||
source_path: source_path.as_object().as_interned_str(vm).unwrap(),
|
||||
source_path: vm.ctx.intern_str(source_path.as_wtf8()),
|
||||
first_line_number,
|
||||
obj_name: obj_name.as_object().as_interned_str(vm).unwrap(),
|
||||
qualname: qualname.as_object().as_interned_str(vm).unwrap(),
|
||||
obj_name: vm.ctx.intern_str(obj_name.as_wtf8()),
|
||||
qualname: vm.ctx.intern_str(qualname.as_wtf8()),
|
||||
|
||||
max_stackdepth,
|
||||
instructions,
|
||||
@@ -1422,14 +1428,8 @@ impl PyCode {
|
||||
// It can be removed once we move every other code to use linetable only.
|
||||
locations: self.code.locations.clone(),
|
||||
constants: constants.into_iter().map(Literal).collect(),
|
||||
names: names
|
||||
.into_iter()
|
||||
.map(|o| o.as_interned_str(vm).unwrap())
|
||||
.collect(),
|
||||
varnames: varnames
|
||||
.into_iter()
|
||||
.map(|o| o.as_interned_str(vm).unwrap())
|
||||
.collect(),
|
||||
names: intern_all(names, "co_names")?,
|
||||
varnames: intern_all(varnames, "co_varnames")?,
|
||||
cellvars,
|
||||
freevars,
|
||||
localspluskinds: self.code.localspluskinds.clone(),
|
||||
|
||||
Reference in new issue
Block a user