fix: critical bugs — unsafe torch.load (RCE), UnboundLocalError crash, thread leak, broken tests - #333
Conversation
…, thread leak, broken tests, non-CUDA crash Bug 1 (CRITICAL — Security): torch.load() without weights_only=True allows arbitrary code execution via pickle deserialization when loading pytorch_model.bin checkpoints. Added weights_only=True to all 3 call sites (lines 273, 434, 448 of utils.py). Bug 2 (HIGH — Crash): remove_real_and_linked_file() references 'targetpath' outside the if-block where it is assigned, causing UnboundLocalError when delete_original=True and the file is not a symlink. Initialized targetpath=None before the conditional. Bug 3 (HIGH — Resource Leak): ThreadPoolExecutor created for prefetching is never shut down. Added close() method and __del__ safety net to AirLLMBaseModel. Bug 4 (MEDIUM — Broken Tests): test_automodel.py expects old class names (AirLLMLlama2, AirLLMMistral, AirLLMMixtral) but these architectures now correctly fall through to AirLLMBaseModel after the ARCH_OVERRIDES refactor. Updated test expectations. Bug 5 (MEDIUM — Crash): torch.cuda.empty_cache() in clean_memory() called unconditionally, crashes on non-CUDA systems. Added torch.cuda.is_available() guard.
|
Heads up on Bug 2 — I ran your version against the real call site and it still crashes. Initialising
to_delete = checkpoint_path / shard_num_to_file[shard]
remove_real_and_linked_file(to_delete)
I compared the four open variants of this helper on a temp file, using the exact
The fix is to ask the question you actually mean — is this a symlink whose target should also go? — rather than comparing paths: targetpath = os.path.realpath(to_delete) if os.path.islink(to_delete) else NoneWorth knowing there are now four PRs on this one helper: #303 (oldest, 2026-07-19), #337, #362, and this one. #303 and #362 are logically identical; #337 adds Transparency: your Bug 1 ( (I couldn't test the symlink case — this box won't let me create symlinks without elevation — so I can't speak to the HF-cache blob behaviour, which is where #337's extra guards would matter.) |
Summary
Deep manual code audit of the entire airllm codebase found 5 real bugs — a security vulnerability, crash bugs, a resource leak, and broken tests.
Bug 1 — 🔴 CRITICAL: Arbitrary Code Execution via Unsafe orch.load
File: �ir_llm/airllm/utils.py (lines 273, 434, 448)
Fix: Added weights_only=True to all 3 orch.load() call sites.
Ref: https://pytorch.org/docs/stable/generated/torch.load.html
Bug 2 — 🔴 HIGH:
emove_real_and_linked_file() Crashes with UnboundLocalError
File: �ir_llm/airllm/utils.py (lines 198–204)
\\python
def remove_real_and_linked_file(to_delete):
if (os.path.realpath(to_delete) != to_delete):
targetpath = os.path.realpath(to_delete) # only assigned inside if
os.remove(to_delete)
if (targetpath): # ← UnboundLocalError when file is NOT a symlink
os.remove(targetpath)
\\
When the file is not a symlink, argetpath is never assigned, causing UnboundLocalError. This crashes the delete_original=True workflow (critical for 1.5TB+ models like Kimi K3).
Fix: Initialize argetpath = None before the conditional.
Bug 3 — 🟡 HIGH: ThreadPoolExecutor Resource Leak
File: �ir_llm/airllm/airllm_base.py (line 175)
The executor for prefetching is created but never shut down — no del, close(), or context manager. Each model instance leaks a daemon thread.
Fix: Added close() method and del safety net.
Bug 4 — 🟡 MEDIUM: Unit Tests Outdated After Refactor
File: �ir_llm/tests/test_automodel.py
Tests expect AirLLMLlama2, AirLLMMistral, AirLLMMixtral but these architectures are no longer in ARCH_OVERRIDES — they correctly fall through to AirLLMBaseModel. Tests fail on every run.
Fix: Updated expected class names to match current ARCH_OVERRIDES.
Bug 5 — 🟡 MEDIUM: clean_memory() Crashes on Non-CUDA Systems
File: �ir_llm/airllm/utils.py (line 83)
Fix: Added orch.cuda.is_available() guard.
Files Changed