Repository: godotengine/godot (language: cpp)

Issue:
Editor crash on startup caused by loading VRAM compressed texture with specific range of dimensions
### Tested versions

- Reproduced in 4.4 dev6, all betas, and rc1
- Not reproduced in 4.4 dev1 through dev5

### System information

Godot v4.4.dev6 - Windows 10.0.19045 - Multi-window, 3 monitors - Vulkan (Forward+) - dedicated Radeon RX 580 Series (Advanced Micro Devices, Inc.; 31.0.21921.1000) - AMD Ryzen 5 3600 6-Core Processor (12 threads)

### Issue description

The editor crashes after initialization. When running my big project with -v, the last lines displayed are these:
```
Loading resource: res://.godot/imported/some_texture.png-1c25004a89b329a9613253a73f2f1983.s3tc.ctex
	Compressed image's dimensions are not multiples of 4 (1024x1023), aligning to (1028x1024)
```
The presence of `some_texture.png` actually causes the crash. I copied that texture to an empty project and found out that its dimensions, as well as it having alpha, cause a crash. Note that in the MRP, the above log message doesn't appear, although the same crash happens.

I compiled with debug symbols and debugged in VS code, and the exception message is this:
`Exception 0xc0000005 encountered at address 0x7ff6f73f5535: Access violation reading location 0x1589ca2d008`
It happens in `thirdparty/misc/bcdec.h`
```
static void bcdec__color_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int onlyOpaqueMode) {
    unsigned short c0, c1;
    unsigned int refColors[4]; /* 0xAABBGGRR */
    unsigned char* dstColors;
    unsigned int colorIndices;
    int i, j, idx;
    unsigned int r0, g0, b0, r1, g1, b1, r, g, b;

    c0 = ((unsigned short*)compressedBlock)[0]; <--------- exception here on line 119
    c1 = ((unsigned short*)compressedBlock)[1];
```
And here's the call stack in case it helps:
```
static void bcdec__color_block(const void *, void *, int, int) (c:\tools\Godot\src\godot\thirdparty\misc\bcdec.h:119)
bcdec_bc3 (c:\tools\Godot\src\godot\thirdparty\misc\bcdec.h:287)
static void decompress_image(BCdecFormat, const void *, void *, const unsigned __int64, const unsigned __int64) (c:\tools\Godot\src\godot\modules\bcdec\image_decompress_bcdec.cpp:129)
void __cdecl image_decompress_bcdec(class Image *) (c:\tools\Godot\src\godot\modules\bcdec\image_decompress_bcdec.cpp:239)
public: enum Error __cdecl Image::decompress(void) (c:\tools\Godot\src\godot\core\io\image.cpp:2670)
public: virtual class Ref<class Texture2D> __cdecl EditorTexturePreviewPlugin::generate(class Ref<class Resource> const &,struct Vector2 const &,class Dictionary &)const  (c:\tools\Godot\src\godot\editor\plugins\editor_preview_plugins.cpp:164)
public: virtual class Ref<class Texture2D> __cdecl EditorResourcePreviewGenerator::generate_from_path(class String const &,struct Vector2 const &,class Dictionary &)const  (c:\tools\Godot\src\godot\editor\editor_resource_preview.cpp:73)
private: void __cdecl EditorResourcePreview::_generate_preview(class Ref<class ImageTexture> &,class Ref<class ImageTexture> &,struct EditorResourcePreview::QueueItem const &,class String const &,class Dictionary &) (c:\tools\Godot\src\godot\editor\editor_resource_preview.cpp:205)
private: void __cdecl EditorResourcePreview::_iterate(void) (c:\tools\Godot\src\godot\editor\editor_resource_preview.cpp:379)
private: void __cdecl EditorResourcePreview::_thread(void) (c:\tools\Godot\src\godot\editor\editor_resource_preview.cpp:407)
private: static void __cdecl EditorResourcePreview::_thread_func(void *) (c:\tools\Godot\src\godot\editor\editor_resource_preview.cpp:139)
private: static void __cdecl Thread::callback(unsigned __int64,struct Thread::Settings const &,void (__cdecl*)(void *),void *) (c:\tools\Godot\src\godot\core\os\thread.cpp:64)
void std::invoke<void (__cdecl*)(unsigned __int64,Thread::Settings const &,void (__cdecl*)(void *),void *),unsigned __int64,Thread::Settings,void (__cdecl*)(void *),void *>( * *, unsigned __int64 *, struct Thread::Settings *,  * *, void * *) (c:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\type_traits:1741)
unsigned int std::thread::_Invoke<std::tuple<void (__cdecl*)(unsigned __int64,Thread::Settings const &,void (__cdecl*)(void *),void *),unsigned __int64,Thread::Settings,void (__cdecl*)(void *),void *>,0,1,2,3,4>(void *) (c:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\thread:60)
static unsigned long thread_start<unsigned int (__cdecl*)(void *),1>(void *) (@NoHotPatch:29828)
BaseThreadInitThunk (@BaseThreadInitThunk:9)
RtlUserThreadStart (@RtlUserThreadStart:12)
```

### Steps to reproduce

1. Add a PNG texture to a project with dimensions of 1024x1023, and some alpha on at least one pixel. The MRP's `crash_texture.png` meets these criteria.
2. Select the PNG in filesystem dock to reveal its import settings, and change the compress mode to "VRAM compressed"
3. Reimport the texture and the editor crashes. It will also crash on each subsequent startup.

Other resolutions that cause crash: 1024x1022, 1024x1021
No crash: 1024x1020, 1025x1023, 512x511

### Minimal reproduction project (MRP)

[texture_crash_mrp.zip](https://github.com/user-attachments/files/18947915/texture_crash_mrp.zip)


Discussion / hints:
I can reproduce this crash, bisecting.

Fix patch:
diff --git a/modules/bcdec/image_decompress_bcdec.cpp b/modules/bcdec/image_decompress_bcdec.cpp
index 6d97ca38abef..ad0c1729d64c 100644
--- a/modules/bcdec/image_decompress_bcdec.cpp
+++ b/modules/bcdec/image_decompress_bcdec.cpp
@@ -158,9 +158,12 @@ void image_decompress_bcdec(Image *p_image) {
 
 	// Compressed images' dimensions should be padded to the upper multiple of 4.
 	// If they aren't, they need to be realigned (the actual data is correctly padded though).
-	if (width % 4 != 0 || height % 4 != 0) {
-		int new_width = width + (4 - (width % 4));
-		int new_height = height + (4 - (height % 4));
+	const bool need_width_realign = width % 4 != 0;
+	const bool need_height_realign = height % 4 != 0;
+
+	if (need_width_realign || need_height_realign) {
+		int new_width = need_width_realign ? width + (4 - (width % 4)) : width;
+		int new_height = need_height_realign ? height + (4 - (height % 4)) : height;
 
 		print_verbose(vformat("Compressed image's dimensions are not multiples of 4 (%dx%d), aligning to (%dx%d)", width, height, new_width, new_height));
 


Test patch: