From f726edee5d5c61f481c18ea351bb7ec8eebb0882 Mon Sep 17 00:00:00 2001 From: Artem Frolov Date: Mon, 25 May 2026 11:10:57 +0300 Subject: [PATCH] Fix GGUF reload race causing heap corruption on Apple Silicon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On MPS, WanVideoSampler.process() re-reads the multi-GB GGUF tensor blob on every prompt. Async device frees race against CPU allocations in unified memory and corrupt a libmalloc free-block header — the 2nd render onward dies with BUG IN CLIENT OF LIBMALLOC / EXC_BREAKPOINT. Guard the GGUF branch with a one-shot transformer._gguf_weights_loaded flag and reuse the already-resident weights on subsequent calls. Set WANVIDEO_DISABLE_GGUF_RELOAD_GUARD=1 to restore the original behaviour for LoRA hot-swap scenarios. Tested on M4 Pro / macOS 25.5 / torch 2.7.1 (MPS) with Wan2.2 GGUF Q5_K_M: 11 sequential renders, zero crashes, output bit-identical to single-scene baseline. Co-Authored-By: Claude Opus 4.7 (1M context) --- nodes_sampler.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/nodes_sampler.py b/nodes_sampler.py index 32b51c6a..28eeb569 100644 --- a/nodes_sampler.py +++ b/nodes_sampler.py @@ -126,8 +126,19 @@ def process(self, model, image_embeds, shift, steps, cfg, seed, scheduler, rifle block_swap_args=block_swap_args, compile_args=model["compile_args"]) if gguf_reader is not None: #handle GGUF - load_weights(transformer, patcher.model["sd"], base_dtype=dtype, transformer_load_device=device, patcher=patcher, gguf=True, - reader=gguf_reader, block_swap_args=block_swap_args, compile_args=model["compile_args"]) + # Skip GGUF reload after the first call to avoid heap corruption on + # Apple Silicon (MPS): repeatedly re-reading the multi-GB GGUF blob + # races MPS async frees against CPU allocations in unified memory + # and triggers BUG IN CLIENT OF LIBMALLOC on the 2nd render onward. + # Set WANVIDEO_DISABLE_GGUF_RELOAD_GUARD=1 to restore the original + # behaviour (needed for mid-process LoRA hot-swap). + _gguf_reload_guard = ( + os.environ.get("WANVIDEO_DISABLE_GGUF_RELOAD_GUARD", "0") != "1" + ) + if not _gguf_reload_guard or not getattr(transformer, "_gguf_weights_loaded", False): + load_weights(transformer, patcher.model["sd"], base_dtype=dtype, transformer_load_device=device, patcher=patcher, gguf=True, + reader=gguf_reader, block_swap_args=block_swap_args, compile_args=model["compile_args"]) + transformer._gguf_weights_loaded = True set_lora_params_gguf(transformer, patcher.patches) transformer.patched_linear = True elif len(patcher.patches) != 0: #handle patched linear layers (unmerged loras, fp8 scaled)