From 34cd681a48b1cf597d04ca3f29b08326d81e3065 Mon Sep 17 00:00:00 2001 From: YimingWu Date: Tue, 27 May 2025 10:01:41 +0200 Subject: [PATCH] Fix #139387: Try to handle mmap exception on Win32 `IMB_load_image_from_file_descriptor` use mmap to read images, and mmap sometimes can have erroreous state llike accessing a file from network drives. This patch tries to handle these exceptions like `BLI_mmap_read` on Win32 (On unix the `sigbus_handler` will be called instead). Pull Request: https://projects.blender.org/blender/blender/pulls/139472 --- source/blender/blenlib/BLI_mmap.h | 1 + source/blender/blenlib/intern/BLI_mmap.cc | 5 +++++ source/blender/imbuf/intern/readimage.cc | 26 ++++++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/source/blender/blenlib/BLI_mmap.h b/source/blender/blenlib/BLI_mmap.h index 2a8f507f5c2..4f775b20dd0 100644 --- a/source/blender/blenlib/BLI_mmap.h +++ b/source/blender/blenlib/BLI_mmap.h @@ -30,5 +30,6 @@ bool BLI_mmap_read(BLI_mmap_file *file, void *dest, size_t offset, size_t length void *BLI_mmap_get_pointer(BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT; size_t BLI_mmap_get_length(const BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT; +bool BLI_mmap_any_io_error(const BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT; void BLI_mmap_free(BLI_mmap_file *file) ATTR_NONNULL(1); diff --git a/source/blender/blenlib/intern/BLI_mmap.cc b/source/blender/blenlib/intern/BLI_mmap.cc index 5317e7935ba..e3c1ce9d43e 100644 --- a/source/blender/blenlib/intern/BLI_mmap.cc +++ b/source/blender/blenlib/intern/BLI_mmap.cc @@ -219,6 +219,11 @@ size_t BLI_mmap_get_length(const BLI_mmap_file *file) return file->length; } +bool BLI_mmap_any_io_error(const BLI_mmap_file *file) +{ + return file->io_error; +} + void BLI_mmap_free(BLI_mmap_file *file) { #ifndef WIN32 diff --git a/source/blender/imbuf/intern/readimage.cc b/source/blender/imbuf/intern/readimage.cc index b58fe7d12ec..ca3f4e13c23 100644 --- a/source/blender/imbuf/intern/readimage.cc +++ b/source/blender/imbuf/intern/readimage.cc @@ -7,6 +7,7 @@ */ #ifdef _WIN32 +# include # include # include # include @@ -167,7 +168,30 @@ ImBuf *IMB_load_image_from_file_descriptor(const int file, const uchar *mem = static_cast(BLI_mmap_get_pointer(mmap_file)); const size_t size = BLI_mmap_get_length(mmap_file); - ibuf = IMB_load_image_from_memory(mem, size, flags, filepath, filepath, r_colorspace); + /* There could be broken mmap due to network drives and other issues, handles exception the + * same way as in #BLI_mmap_read. Note that if the mmap becomes invalid mid-way through reading, + * external calls in #IMB_load_image_from_memory could leave unfreed memory, but this is the + * limitation of current exception handling method. Ref #139472. */ +#ifdef WIN32 + __try + { +#endif + + ibuf = IMB_load_image_from_memory(mem, size, flags, filepath, filepath, r_colorspace); + +#ifdef WIN32 + } + __except (GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : + EXCEPTION_CONTINUE_SEARCH) + { + ibuf = nullptr; + } +#else + /* For unix, if mmap encounters an exception, BLI_mmap_file::io_error would be set. */ + if (BLI_mmap_any_io_error(mmap_file)) { + ibuf = nullptr; + } +#endif imb_mmap_lock(); BLI_mmap_free(mmap_file);