dds: Use put_u32 for unsigned integer puts.

UBSan reports:
  image_saver_dds.cpp:417: implicit conversion from type 'uint32_t'
  of value 4278190080 to type 'int32_t' changed the value to -16777216
  stream_peer.cpp:184: implicit conversion from type 'int32_t'
  of value -16777216 to type 'uint32_t' changed the value to 4278190080

The DDS pixel format masks (r/g/b/a_mask) are uint32_t but put_32
takes int32_t. Use put_u32 to avoid the round-trip conversion that
UBSan flags when the high bit is set (e.g. a_mask = 0xFF000000).

This fix found a large class of uses where we put unsigned integer values into
integer puts.
This commit is contained in:
K. S. Ernest (iFire) Lee 2026-04-12 10:46:50 -07:00
parent 1aabcb9e9b
commit 65ca207d2c

View file

@ -343,8 +343,8 @@ Vector<uint8_t> save_dds_buffer(const Ref<Image> &p_img) {
Ref<Image> image = p_img;
stream_buffer->put_32(DDS_MAGIC);
stream_buffer->put_32(DDS_HEADER_SIZE);
stream_buffer->put_u32(DDS_MAGIC);
stream_buffer->put_u32(DDS_HEADER_SIZE);
uint32_t flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_LINEARSIZE;
@ -352,13 +352,13 @@ Vector<uint8_t> save_dds_buffer(const Ref<Image> &p_img) {
flags |= DDSD_MIPMAPCOUNT;
}
stream_buffer->put_32(flags);
stream_buffer->put_u32(flags);
uint32_t height = image->get_height();
stream_buffer->put_32(height);
stream_buffer->put_u32(height);
uint32_t width = image->get_width();
stream_buffer->put_32(width);
stream_buffer->put_u32(width);
DDSFormat dds_format = _image_format_to_dds_format(image->get_format());
const DDSFormatInfo &info = dds_format_info[dds_format];
@ -372,18 +372,18 @@ Vector<uint8_t> save_dds_buffer(const Ref<Image> &p_img) {
pitch = width * info.block_size;
}
stream_buffer->put_32(pitch);
stream_buffer->put_32(depth);
stream_buffer->put_u32(pitch);
stream_buffer->put_u32(depth);
uint32_t mipmaps = image->get_mipmap_count() + 1;
stream_buffer->put_32(mipmaps);
stream_buffer->put_u32(mipmaps);
uint32_t reserved = 0;
for (int i = 0; i < 11; i++) {
stream_buffer->put_32(reserved);
stream_buffer->put_u32(reserved);
}
stream_buffer->put_32(DDS_PIXELFORMAT_SIZE);
stream_buffer->put_u32(DDS_PIXELFORMAT_SIZE);
uint32_t pf_flags = 0;
@ -399,22 +399,22 @@ Vector<uint8_t> save_dds_buffer(const Ref<Image> &p_img) {
pf_flags = DDPF_FOURCC;
}
stream_buffer->put_32(pf_flags);
stream_buffer->put_u32(pf_flags);
bool needs_pixeldata_swap = false;
if (format_type == DDFT_BITMASK) {
// Uncompressed bitmasked.
stream_buffer->put_32(0); // FourCC
stream_buffer->put_u32(0); // FourCC
uint32_t bit_count, r_mask, g_mask, b_mask, a_mask;
_get_dds_pixel_bitmask(image->get_format(), bit_count, r_mask, g_mask, b_mask, a_mask);
stream_buffer->put_32(bit_count);
stream_buffer->put_32(r_mask);
stream_buffer->put_32(g_mask);
stream_buffer->put_32(b_mask);
stream_buffer->put_32(a_mask);
stream_buffer->put_u32(bit_count);
stream_buffer->put_u32(r_mask);
stream_buffer->put_u32(g_mask);
stream_buffer->put_u32(b_mask);
stream_buffer->put_u32(a_mask);
if (image->get_format() == Image::FORMAT_RGBA4444 || image->get_format() == Image::FORMAT_RGB8) {
needs_pixeldata_swap = true;
@ -422,40 +422,40 @@ Vector<uint8_t> save_dds_buffer(const Ref<Image> &p_img) {
} else if (format_type == DDFT_FOURCC) {
// FourCC.
uint32_t fourcc = _image_format_to_fourcc_format(image->get_format());
stream_buffer->put_32(fourcc);
stream_buffer->put_u32(fourcc);
stream_buffer->put_32(0); // Bit count
stream_buffer->put_32(0); // R Bitmask
stream_buffer->put_32(0); // G Bitmask
stream_buffer->put_32(0); // B Bitmask
stream_buffer->put_32(0); // A Bitmask
stream_buffer->put_u32(0); // Bit count
stream_buffer->put_u32(0); // R Bitmask
stream_buffer->put_u32(0); // G Bitmask
stream_buffer->put_u32(0); // B Bitmask
stream_buffer->put_u32(0); // A Bitmask
} else {
// DXGI format and DX10 header.
stream_buffer->put_32(DDFCC_DX10);
stream_buffer->put_u32(DDFCC_DX10);
stream_buffer->put_32(0); // Bit count
stream_buffer->put_32(0); // R Bitmask
stream_buffer->put_32(0); // G Bitmask
stream_buffer->put_32(0); // B Bitmask
stream_buffer->put_32(0); // A Bitmask
stream_buffer->put_u32(0); // Bit count
stream_buffer->put_u32(0); // R Bitmask
stream_buffer->put_u32(0); // G Bitmask
stream_buffer->put_u32(0); // B Bitmask
stream_buffer->put_u32(0); // A Bitmask
}
uint32_t caps1 = info.compressed ? DDSD_LINEARSIZE : DDSD_PITCH;
stream_buffer->put_32(caps1);
stream_buffer->put_u32(caps1);
stream_buffer->put_32(0); // Caps2
stream_buffer->put_32(0); // Caps3
stream_buffer->put_32(0); // Caps4
stream_buffer->put_32(0); // Reserved 2
stream_buffer->put_u32(0); // Caps2
stream_buffer->put_u32(0); // Caps3
stream_buffer->put_u32(0); // Caps4
stream_buffer->put_u32(0); // Reserved 2
if (format_type == DDFT_DXGI) {
// DX10 header.
uint32_t dxgi_format = _image_format_to_dxgi_format(image->get_format());
stream_buffer->put_32(dxgi_format);
stream_buffer->put_32(DX10D_2D);
stream_buffer->put_32(0); // Misc flags 1
stream_buffer->put_32(1); // Array size
stream_buffer->put_32(0); // Misc flags 2
stream_buffer->put_u32(dxgi_format);
stream_buffer->put_u32(DX10D_2D);
stream_buffer->put_u32(0); // Misc flags 1
stream_buffer->put_u32(1); // Array size
stream_buffer->put_u32(0); // Misc flags 2
}
for (uint32_t mip_i = 0; mip_i < mipmaps; mip_i++) {