◐ Shell
clean mode source ↗

Update tarfile from v3.14.3 and fix bugs by youknowone · Pull Request #7223 · RustPython/RustPython

98-102: ⚠️ Potential issue | 🟡 Minor

Use a non-empty message for MemoryError.

Error::Mem currently produces MemoryError(""), which is hard to diagnose in user reports.

Suggested fix
-            Error::Mem => vm.new_memory_error(""),
+            Error::Mem => vm.new_memory_error("Memory allocation failed"),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/stdlib/src/lzma.rs` around lines 98 - 102, In catch_lzma_error,
Error::Mem returns an empty MemoryError message which is unhelpful; update the
Error::Mem arm in the catch_lzma_error function to call vm.new_memory_error with
a descriptive non-empty string (e.g., "LZMA decompression memory exhausted" or
similar) so MemoryError carries useful context when raised.

461-481: ⚠️ Potential issue | 🟠 Major

build_filter_spec accepts malformed property lengths.

FILTER_LZMA2/FILTER_DELTA should require exactly 1 byte, and BCJ filters should accept only 0 or 4 bytes; current logic silently accepts invalid blobs.

Suggested fix
             FILTER_LZMA2 => {
-                if props.is_empty() {
+                if props.len() != 1 {
                     return Err(new_lzma_error("Invalid or unsupported options", vm));
                 }
                 let dict_size = lzma2_dict_size_from_prop(props[0]);
                 dict.set_item("dict_size", vm.new_pyobj(dict_size), vm)?;
             }
             FILTER_DELTA => {
-                if props.is_empty() {
+                if props.len() != 1 {
                     return Err(new_lzma_error("Invalid or unsupported options", vm));
                 }
                 let dist = props[0] as u32 + 1;
                 dict.set_item("dist", vm.new_pyobj(dist), vm)?;
             }
             FILTER_X86 | FILTER_POWERPC | FILTER_IA64 | FILTER_ARM | FILTER_ARMTHUMB
             | FILTER_SPARC => {
-                if props.len() == 4 {
+                if props.is_empty() {
+                    // default start_offset = 0
+                } else if props.len() == 4 {
                     let start_offset = u32::from_le_bytes([props[0], props[1], props[2], props[3]]);
                     dict.set_item("start_offset", vm.new_pyobj(start_offset), vm)?;
+                } else {
+                    return Err(new_lzma_error("Invalid or unsupported options", vm));
                 }
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/stdlib/src/lzma.rs` around lines 461 - 481, The build_filter_spec
branch handling FILTER_LZMA2, FILTER_DELTA, and BCJ filters (FILTER_X86,
FILTER_POWERPC, FILTER_IA64, FILTER_ARM, FILTER_ARMTHUMB, FILTER_SPARC)
currently accepts malformed props lengths; update it so FILTER_LZMA2 and
FILTER_DELTA require props.len() == 1 (otherwise return
Err(new_lzma_error("Invalid or unsupported options", vm))) and the BCJ branches
only accept props.len() == 0 or props.len() == 4 (if 4 parse start_offset, else
if 0 do nothing; any other length return the same LZMA error). Keep the existing
dict.set_item calls but gate them behind these strict length checks in
build_filter_spec.

755-766: ⚠️ Potential issue | 🟠 Major

FORMAT_ALONE currently ignores caller-provided filters.

When filter_specs is Some, this path still builds encoder options only from preset, silently dropping user configuration.

Suggested fix
     fn init_alone(
         preset: u32,
         filter_specs: Option<Vec<PyObjectRef>>,
         vm: &VirtualMachine,
     ) -> PyResult<Stream> {
-        if let Some(_filter_specs) = filter_specs {
-            // TODO: validate single LZMA1 filter and use its options
-            let options = LzmaOptions::new_preset(preset).map_err(|_| {
-                new_lzma_error(format!("Invalid compression preset: {preset}"), vm)
-            })?;
-            Stream::new_lzma_encoder(&options).map_err(|e| catch_lzma_error(e, vm))
-        } else {
-            let options = LzmaOptions::new_preset(preset).map_err(|_| {
-                new_lzma_error(format!("Invalid compression preset: {preset}"), vm)
-            })?;
-            Stream::new_lzma_encoder(&options).map_err(|e| catch_lzma_error(e, vm))
-        }
+        if filter_specs.is_some() {
+            return Err(new_lzma_error(
+                "FORMAT_ALONE with custom filters is not implemented",
+                vm,
+            ));
+        }
+        let options = LzmaOptions::new_preset(preset)
+            .map_err(|_| new_lzma_error(format!("Invalid compression preset: {preset}"), vm))?;
+        Stream::new_lzma_encoder(&options).map_err(|e| catch_lzma_error(e, vm))
     }
As per coding guidelines: "When branches differ only in a value but share common logic, extract the differing value first, then call the common logic once to avoid duplicate code".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/stdlib/src/lzma.rs` around lines 755 - 766, The branch currently
ignores caller-provided filters: when filter_specs is Some you still call
LzmaOptions::new_preset(preset) and drop the filters; instead, compute the LZMA
encoder options once by first deriving options depending on filter_specs
(validate that filter_specs contains a single LZMA1 filter and build LzmaOptions
from its options when Some, falling back to LzmaOptions::new_preset(preset) when
None), then call Stream::new_lzma_encoder(&options).map_err(|e|
catch_lzma_error(e, vm)) a single time; update the code around filter_specs,
LzmaOptions::new_preset and Stream::new_lzma_encoder to remove the duplicated
logic and correctly honor the caller-provided filters.

207-233: ⚠️ Potential issue | 🟡 Minor

TypeError text over-promises dict-like support.

Both helpers require PyDict via downcast_ref::<PyDict>(), but the message says “dict or dict-like object”.

Suggested fix
-        let dict = spec.downcast_ref::<PyDict>().ok_or_else(|| {
-            vm.new_type_error("Filter specifier must be a dict or dict-like object")
-        })?;
+        let dict = spec
+            .downcast_ref::<PyDict>()
+            .ok_or_else(|| vm.new_type_error("Filter specifier must be a dict"))?;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/stdlib/src/lzma.rs` around lines 207 - 233, The TypeError message in
get_dict_opt_u32 and get_dict_opt_u64 incorrectly promises "dict-like" support
while downcasting only to PyDict; update the vm.new_type_error call in both
functions to state that the filter specifier "must be a dict" (or alternatively,
implement true mapping support by accepting mapping protocol), so the error text
matches the actual check performed by the downcast_ref::<PyDict>() used in
get_dict_opt_u32 and get_dict_opt_u64.