From 915ea71fc2fbbd45668bd4111ea506c51749d13e Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Fri, 1 Aug 2025 23:54:14 +0100 Subject: [PATCH] Avoid aliasing and UB in mspnr_operator --- Source/astcenc_color_unquantize.cpp | 2 +- Source/astcenccli_error_metrics.cpp | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Source/astcenc_color_unquantize.cpp b/Source/astcenc_color_unquantize.cpp index 0b237c21d..70f2debad 100644 --- a/Source/astcenc_color_unquantize.cpp +++ b/Source/astcenc_color_unquantize.cpp @@ -53,7 +53,7 @@ static ASTCENC_SIMD_INLINE vint4 uncontract_color( */ static ASTCENC_SIMD_INLINE int32_t safe_signed_lsh(int32_t val, int shift) { - // Future: When we support C++20 can swap memcpy for std::bitcast + // Future: Can use std:bit_cast with C++20 uint32_t uval; std::memcpy(&uval, &val, sizeof(uint32_t)); uval <<= shift; diff --git a/Source/astcenccli_error_metrics.cpp b/Source/astcenccli_error_metrics.cpp index 4e01a9eef..828b7e078 100644 --- a/Source/astcenccli_error_metrics.cpp +++ b/Source/astcenccli_error_metrics.cpp @@ -68,13 +68,19 @@ static float mpsnr_operator( float val, int fstop ) { - if32 p; - p.u = 0x3f800000 + (fstop << 23); // 0x3f800000 is 1.0f - val *= p.f; - val = powf(val, (1.0f / 2.2f)); - val *= 255.0f; + // Future: Can use std:bit_cast with C++20 - return astc::clamp(val, 0.0f, 255.0f); + // Fast implementation of pow(2.0, fstop), assuming IEEE float layout + // Memcpy to uint avoids ubsan complaints shift of negative int + unsigned int fstopu; + std::memcpy(&fstopu, &fstop, sizeof(int)); + uint32_t uscale = 0x3f800000 + (fstopu << 23); + + float scale; + std::memcpy(&scale, &uscale, sizeof(float)); + + val = powf(val * scale, (1.0f / 2.2f)); + return astc::clamp(val * 255.0f, 0.0f, 255.0f); } /**