From 32e4f861d6c79912fc068b5ef02ced25722cacf7 Mon Sep 17 00:00:00 2001 From: akleine Date: Tue, 26 May 2026 16:05:35 +0200 Subject: [PATCH 1/4] fix: prevent crash in case of a memory allocation error ...and ensure a graceful exit --- src/model.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/model.cpp b/src/model.cpp index 8351a2be6..f7fb7fa22 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -995,6 +995,12 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread continue; } + if (dst_tensor->data == nullptr) { + LOG_ERROR("memory allocation failed '%s'", tensor_storage.name.c_str()); + failed = true; + break; + } + // skip mmapped tensors if (dst_tensor->buffer != nullptr && dst_tensor->buffer == fdata.mmbuffer.get()) { continue; From d3cc717298710ff66c7bc753843648379227bc74 Mon Sep 17 00:00:00 2001 From: akleine Date: Thu, 28 May 2026 07:18:40 +0200 Subject: [PATCH 2/4] chore: switch some alloc_params_buffer() methods to 'bool' and check their return values to catch OOM situations. --- src/conditioner.hpp | 72 +++++++++++++++++++++++++++++----------- src/diffusion_model.hpp | 72 ++++++++++++++++++++++++++++------------ src/hidream_o1.hpp | 7 ++-- src/stable-diffusion.cpp | 18 ++++++++-- 4 files changed, 123 insertions(+), 46 deletions(-) diff --git a/src/conditioner.hpp b/src/conditioner.hpp index 3963f3abf..b0feca4a5 100644 --- a/src/conditioner.hpp +++ b/src/conditioner.hpp @@ -114,7 +114,7 @@ struct Conditioner { public: virtual SDCondition get_learned_condition(int n_threads, const ConditionerParams& conditioner_params) = 0; - virtual void alloc_params_buffer() = 0; + virtual bool alloc_params_buffer() = 0; virtual void free_params_buffer() = 0; virtual void get_param_tensors(std::map& tensors) = 0; virtual size_t get_params_buffer_size() = 0; @@ -177,11 +177,16 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner { } } - void alloc_params_buffer() override { - text_model->alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!text_model->alloc_params_buffer()) { + return false; + } if (sd_version_is_sdxl(version)) { - text_model2->alloc_params_buffer(); + if (!text_model2->alloc_params_buffer()) { + return false; + } } + return true; } void free_params_buffer() override { @@ -784,16 +789,23 @@ struct SD3CLIPEmbedder : public Conditioner { } } - void alloc_params_buffer() override { + bool alloc_params_buffer() override { if (clip_l) { - clip_l->alloc_params_buffer(); + if (!clip_l->alloc_params_buffer()) { + return false; + } } if (clip_g) { - clip_g->alloc_params_buffer(); + if (!clip_g->alloc_params_buffer()) { + return false; + } } if (t5) { - t5->alloc_params_buffer(); + if (!t5->alloc_params_buffer()) { + return false; + } } + return true; } void free_params_buffer() override { @@ -1148,15 +1160,21 @@ struct FluxCLIPEmbedder : public Conditioner { } } - void alloc_params_buffer() override { + bool alloc_params_buffer() override { if (clip_l) { - clip_l->alloc_params_buffer(); + if (!clip_l->alloc_params_buffer()) { + return false; + } } if (t5) { - t5->alloc_params_buffer(); + if (!t5->alloc_params_buffer()) { + return false; + } } + return true; } + void free_params_buffer() override { if (clip_l) { clip_l->free_params_buffer(); @@ -1391,10 +1409,13 @@ struct T5CLIPEmbedder : public Conditioner { } } - void alloc_params_buffer() override { + bool alloc_params_buffer() override { if (t5) { - t5->alloc_params_buffer(); + if (!t5->alloc_params_buffer()) { + return false; + } } + return true; } void free_params_buffer() override { @@ -1581,8 +1602,11 @@ struct AnimaConditioner : public Conditioner { llm->get_param_tensors(tensors, "text_encoders.llm"); } - void alloc_params_buffer() override { - llm->alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!llm->alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -1716,8 +1740,11 @@ struct LLMEmbedder : public Conditioner { llm->get_param_tensors(tensors, "text_encoders.llm"); } - void alloc_params_buffer() override { - llm->alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!llm->alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -2211,9 +2238,14 @@ struct LTXAVEmbedder : public Conditioner { projector->get_param_tensors(tensors, "text_embedding_projection"); } - void alloc_params_buffer() override { - llm->alloc_params_buffer(); - projector->alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!llm->alloc_params_buffer()) { + return false; + } + if (!projector->alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { diff --git a/src/diffusion_model.hpp b/src/diffusion_model.hpp index 9e4e444ec..2f0e716d9 100644 --- a/src/diffusion_model.hpp +++ b/src/diffusion_model.hpp @@ -54,7 +54,7 @@ struct DiffusionModel { virtual std::string get_desc() = 0; virtual sd::Tensor compute(int n_threads, const DiffusionParams& diffusion_params) = 0; - virtual void alloc_params_buffer() = 0; + virtual bool alloc_params_buffer() = 0; virtual void free_params_buffer() = 0; virtual void free_compute_buffer() = 0; virtual void get_param_tensors(std::map& tensors) = 0; @@ -80,8 +80,11 @@ struct UNetModel : public DiffusionModel { return unet.get_desc(); } - void alloc_params_buffer() override { - unet.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!unet.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -150,8 +153,11 @@ struct MMDiTModel : public DiffusionModel { return mmdit.get_desc(); } - void alloc_params_buffer() override { - mmdit.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!mmdit.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -219,8 +225,11 @@ struct FluxModel : public DiffusionModel { return flux.get_desc(); } - void alloc_params_buffer() override { - flux.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!flux.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -293,8 +302,11 @@ struct AnimaModel : public DiffusionModel { return anima.get_desc(); } - void alloc_params_buffer() override { - anima.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!anima.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -362,8 +374,11 @@ struct WanModel : public DiffusionModel { return wan.get_desc(); } - void alloc_params_buffer() override { - wan.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!wan.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -435,8 +450,11 @@ struct QwenImageModel : public DiffusionModel { return qwen_image.get_desc(); } - void alloc_params_buffer() override { - qwen_image.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!qwen_image.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -504,8 +522,11 @@ struct HiDreamO1Model : public DiffusionModel { return hidream_o1.get_desc(); } - void alloc_params_buffer() override { - hidream_o1.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!hidream_o1.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -581,8 +602,11 @@ struct ZImageModel : public DiffusionModel { return z_image.get_desc(); } - void alloc_params_buffer() override { - z_image.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!z_image.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -650,8 +674,11 @@ struct ErnieImageModel : public DiffusionModel { return ernie_image.get_desc(); } - void alloc_params_buffer() override { - ernie_image.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!ernie_image.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { @@ -716,8 +743,11 @@ struct LTXAVModel : public DiffusionModel { return ltxav.get_desc(); } - void alloc_params_buffer() override { - ltxav.alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!ltxav.alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { diff --git a/src/hidream_o1.hpp b/src/hidream_o1.hpp index d72739d56..ba88fe975 100644 --- a/src/hidream_o1.hpp +++ b/src/hidream_o1.hpp @@ -469,8 +469,11 @@ namespace HiDreamO1 { vision_runner->get_param_tensors(tensors); } - void alloc_params_buffer() override { - vision_runner->alloc_params_buffer(); + bool alloc_params_buffer() override { + if (!vision_runner->alloc_params_buffer()) { + return false; + } + return true; } void free_params_buffer() override { diff --git a/src/stable-diffusion.cpp b/src/stable-diffusion.cpp index 9e8e4744e..937ead7f8 100644 --- a/src/stable-diffusion.cpp +++ b/src/stable-diffusion.cpp @@ -954,13 +954,25 @@ class StableDiffusionGGML { return false; } if (cond_stage_model) { - cond_stage_model->alloc_params_buffer(); + if (!cond_stage_model->alloc_params_buffer()) { + LOG_ERROR("Conditioner model params buffer allocation failed"); + ggml_free(ctx); + return false; + } } if (diffusion_model) { - diffusion_model->alloc_params_buffer(); + if (!diffusion_model->alloc_params_buffer()) { + LOG_ERROR("Diffusion model params buffer allocation failed"); + ggml_free(ctx); + return false; + } } if (high_noise_diffusion_model) { - high_noise_diffusion_model->alloc_params_buffer(); + if (!high_noise_diffusion_model->alloc_params_buffer()) { + LOG_ERROR("High noise diffusion model params buffer allocation failed"); + ggml_free(ctx); + return false; + } } if (first_stage_model && !first_stage_model->alloc_params_buffer()) { LOG_ERROR("VAE params buffer allocation failed"); From 275d1228db180e30dbe6bcf2f59e02c7cfe3f0e0 Mon Sep 17 00:00:00 2001 From: akleine Date: Thu, 28 May 2026 08:38:43 +0200 Subject: [PATCH 3/4] chore: check all other alloc_params_buffer() return values.. ..for the sake of completeness. (Some are probably rather unimportant.) --- src/control.hpp | 6 +++++- src/esrgan.hpp | 6 +++++- src/flux.hpp | 6 +++++- src/llm.hpp | 13 ++++++++++--- src/lora.hpp | 6 +++++- src/ltx_audio_vae.h | 6 +++++- src/ltx_vae.hpp | 6 +++++- src/ltxv.hpp | 5 ++++- src/mmdit.hpp | 6 +++++- src/pmid.hpp | 5 ++++- src/qwen_image.hpp | 6 +++++- src/t5.hpp | 12 +++++++++--- src/wan.hpp | 11 +++++++++-- src/z_image.hpp | 5 ++++- 14 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/control.hpp b/src/control.hpp index fd1f6d869..a38f5d14c 100644 --- a/src/control.hpp +++ b/src/control.hpp @@ -457,7 +457,11 @@ struct ControlNet : public GGMLRunner { bool load_from_file(const std::string& file_path, int n_threads) { LOG_INFO("loading control net from '%s'", file_path.c_str()); - alloc_params_buffer(); + if (!alloc_params_buffer()) { + LOG_ERROR("control net model buffer allocation failed"); + return false; + } + std::map tensors; control_net.get_param_tensors(tensors); std::set ignore_tensors; diff --git a/src/esrgan.hpp b/src/esrgan.hpp index f54baca3c..a651007de 100644 --- a/src/esrgan.hpp +++ b/src/esrgan.hpp @@ -270,7 +270,11 @@ struct ESRGAN : public GGMLRunner { rrdb_net = std::make_unique(detected_scale, detected_num_block, detected_num_in_ch, detected_num_out_ch, detected_num_feat, detected_num_grow_ch); rrdb_net->init(params_ctx, {}, ""); - alloc_params_buffer(); + if (!alloc_params_buffer()) { + LOG_ERROR("esrgan model buffer allocation failed"); + return false; + } + std::map esrgan_tensors; rrdb_net->get_param_tensors(esrgan_tensors); diff --git a/src/flux.hpp b/src/flux.hpp index 85da3043a..a0e1fadb1 100644 --- a/src/flux.hpp +++ b/src/flux.hpp @@ -1572,7 +1572,11 @@ namespace Flux { VERSION_FLUX2, false); - flux->alloc_params_buffer(); + if (!flux->alloc_params_buffer()) { + LOG_ERROR("flux model allocation failed"); + return; + } + std::map tensors; flux->get_param_tensors(tensors, "model.diffusion_model"); diff --git a/src/llm.hpp b/src/llm.hpp index cec8b1dcc..a62ae2172 100644 --- a/src/llm.hpp +++ b/src/llm.hpp @@ -1494,8 +1494,11 @@ namespace LLM { model.get_param_tensors(tensors, prefix); } - void alloc_params_buffer() { - model.alloc_params_buffer(); + bool alloc_params_buffer() { + if (!model.alloc_params_buffer()) { + return false; + } + return true; } std::tuple, std::vector> tokenize(std::string text, @@ -1737,7 +1740,11 @@ namespace LLM { "text_encoders.llm", true); - llm->alloc_params_buffer(); + if (!llm->alloc_params_buffer()) { + LOG_ERROR("llm model allocation failed"); + return; + } + std::map tensors; llm->get_param_tensors(tensors, "text_encoders.llm"); diff --git a/src/lora.hpp b/src/lora.hpp index 3d2b76992..89803e330 100644 --- a/src/lora.hpp +++ b/src/lora.hpp @@ -86,7 +86,11 @@ struct LoraModel : public GGMLRunner { lora_tensors[name] = real; } - alloc_params_buffer(); + if (!alloc_params_buffer()) { + LOG_ERROR("lora model buffer allocation failed"); + return false; + } + dry_run = false; model_loader.load_tensors(on_new_tensor_cb, n_threads); diff --git a/src/ltx_audio_vae.h b/src/ltx_audio_vae.h index a160338f4..f7aa1e268 100644 --- a/src/ltx_audio_vae.h +++ b/src/ltx_audio_vae.h @@ -1068,7 +1068,11 @@ namespace LTXV { tensor_storage_map, prefix); - ltx_audio_vae->alloc_params_buffer(); + if (!ltx_audio_vae->alloc_params_buffer()) { + LOG_ERROR("ltx audio vae buffer allocation failed"); + return; + } + std::map tensors; ltx_audio_vae->get_param_tensors(tensors, ""); diff --git a/src/ltx_vae.hpp b/src/ltx_vae.hpp index 5fdce6c28..5f5467be5 100644 --- a/src/ltx_vae.hpp +++ b/src/ltx_vae.hpp @@ -1534,7 +1534,11 @@ struct LTXVideoVAE : public VAE { true, VERSION_LTXAV); - vae->alloc_params_buffer(); + if (!vae->alloc_params_buffer()) { + LOG_ERROR("vae buffer allocation failed"); + return; + } + std::map tensors; vae->get_param_tensors(tensors, "first_stage_model"); diff --git a/src/ltxv.hpp b/src/ltxv.hpp index fd19595ef..c17f3331b 100644 --- a/src/ltxv.hpp +++ b/src/ltxv.hpp @@ -2002,7 +2002,10 @@ namespace LTXV { tensor_storage_map, "model.diffusion_model"); - ltxav->alloc_params_buffer(); + if (!ltxav->alloc_params_buffer()) { + LOG_ERROR("ltxav buffer allocation failed"); + return; + } std::map tensors; ltxav->get_param_tensors(tensors, "model.diffusion_model"); diff --git a/src/mmdit.hpp b/src/mmdit.hpp index 6fcd732e5..966cdf555 100644 --- a/src/mmdit.hpp +++ b/src/mmdit.hpp @@ -938,7 +938,11 @@ struct MMDiTRunner : public GGMLRunner { { LOG_INFO("loading from '%s'", file_path.c_str()); - mmdit->alloc_params_buffer(); + if (!mmdit->alloc_params_buffer()) { + LOG_ERROR("mmdit embeds buffer allocation failed"); + return; + } + std::map tensors; mmdit->get_param_tensors(tensors, "model.diffusion_model"); diff --git a/src/pmid.hpp b/src/pmid.hpp index 2a9d2da7c..6e3d5e611 100644 --- a/src/pmid.hpp +++ b/src/pmid.hpp @@ -615,7 +615,10 @@ struct PhotoMakerIDEmbed : public GGMLRunner { }; model_loader->load_tensors(on_new_tensor_cb, n_threads); - alloc_params_buffer(); + if (!alloc_params_buffer()) { + LOG_ERROR("PhotoMaker ID embeds buffer allocation failed"); + return false; + } dry_run = false; model_loader->load_tensors(on_new_tensor_cb, n_threads); diff --git a/src/qwen_image.hpp b/src/qwen_image.hpp index 73c1f9aec..b37de772e 100644 --- a/src/qwen_image.hpp +++ b/src/qwen_image.hpp @@ -691,7 +691,11 @@ namespace Qwen { "model.diffusion_model", VERSION_QWEN_IMAGE); - qwen_image->alloc_params_buffer(); + if (!qwen_image->alloc_params_buffer()) { + LOG_ERROR("qwen_image buffer allocation failed"); + return; + } + std::map tensors; qwen_image->get_param_tensors(tensors, "model.diffusion_model"); diff --git a/src/t5.hpp b/src/t5.hpp index 01c35d7de..dd4a3d41e 100644 --- a/src/t5.hpp +++ b/src/t5.hpp @@ -475,8 +475,11 @@ struct T5Embedder { model.get_param_tensors(tensors, prefix); } - void alloc_params_buffer() { - model.alloc_params_buffer(); + bool alloc_params_buffer() { + if (!model.alloc_params_buffer()) { + return false; + } + return true; } std::tuple, std::vector, std::vector> tokenize(std::string text, @@ -578,7 +581,10 @@ struct T5Embedder { std::shared_ptr t5 = std::make_shared(backend, backend, tensor_storage_map, "", true); - t5->alloc_params_buffer(); + if (!t5->alloc_params_buffer()) { + LOG_ERROR("t5 params buffer allocation failed"); + return; + } std::map tensors; t5->get_param_tensors(tensors, ""); diff --git a/src/wan.hpp b/src/wan.hpp index ddd9680e7..403cf1c87 100644 --- a/src/wan.hpp +++ b/src/wan.hpp @@ -1333,7 +1333,10 @@ namespace WAN { { LOG_INFO("loading from '%s'", file_path.c_str()); - vae->alloc_params_buffer(); + if (!vae->alloc_params_buffer()) { + LOG_ERROR("vae buffer allocation failed"); + return; + } std::map tensors; vae->get_param_tensors(tensors, "first_stage_model"); @@ -2351,7 +2354,11 @@ namespace WAN { "model.diffusion_model", VERSION_WAN2_2_TI2V); - wan->alloc_params_buffer(); + if (!wan->alloc_params_buffer()) { + LOG_ERROR("wan buffer allocation failed"); + return; + } + std::map tensors; wan->get_param_tensors(tensors, "model.diffusion_model"); diff --git a/src/z_image.hpp b/src/z_image.hpp index c0546931f..a3f644d48 100644 --- a/src/z_image.hpp +++ b/src/z_image.hpp @@ -625,7 +625,10 @@ namespace ZImage { "model.diffusion_model", VERSION_QWEN_IMAGE); - z_image->alloc_params_buffer(); + if (!z_image->alloc_params_buffer()) { + LOG_ERROR("z_image buffer allocation failed"); + return; + } std::map tensors; z_image->get_param_tensors(tensors, "model.diffusion_model"); From 3c6904d94792c8481d312685518f1d6344a7b238 Mon Sep 17 00:00:00 2001 From: akleine Date: Fri, 29 May 2026 08:53:05 +0200 Subject: [PATCH 4/4] chore: minor changes in code style and in failure message --- src/model.cpp | 2 +- src/stable-diffusion.cpp | 30 ++++++++++++------------------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/model.cpp b/src/model.cpp index 2d80e6b56..8e36e8298 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -1000,7 +1000,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread } if (dst_tensor->data == nullptr) { - LOG_ERROR("memory allocation failed '%s'", tensor_storage.name.c_str()); + LOG_ERROR("process tensor data failed: '%s'", tensor_storage.name.c_str()); failed = true; break; } diff --git a/src/stable-diffusion.cpp b/src/stable-diffusion.cpp index ce9e1009e..75f5a8155 100644 --- a/src/stable-diffusion.cpp +++ b/src/stable-diffusion.cpp @@ -984,26 +984,20 @@ class StableDiffusionGGML { ggml_free(ctx); return false; } - if (cond_stage_model) { - if (!cond_stage_model->alloc_params_buffer()) { - LOG_ERROR("Conditioner model params buffer allocation failed"); - ggml_free(ctx); - return false; - } + if (cond_stage_model && !cond_stage_model->alloc_params_buffer()) { + LOG_ERROR("Conditioner model params buffer allocation failed"); + ggml_free(ctx); + return false; } - if (diffusion_model) { - if (!diffusion_model->alloc_params_buffer()) { - LOG_ERROR("Diffusion model params buffer allocation failed"); - ggml_free(ctx); - return false; - } + if (diffusion_model && !diffusion_model->alloc_params_buffer()) { + LOG_ERROR("Diffusion model params buffer allocation failed"); + ggml_free(ctx); + return false; } - if (high_noise_diffusion_model) { - if (!high_noise_diffusion_model->alloc_params_buffer()) { - LOG_ERROR("High noise diffusion model params buffer allocation failed"); - ggml_free(ctx); - return false; - } + if (high_noise_diffusion_model && !high_noise_diffusion_model->alloc_params_buffer()) { + LOG_ERROR("High noise diffusion model params buffer allocation failed"); + ggml_free(ctx); + return false; } if (first_stage_model && !first_stage_model->alloc_params_buffer()) { LOG_ERROR("VAE params buffer allocation failed");