From 3c3e867c3700c741faeaa6eac8a6dabc56adc6f2 Mon Sep 17 00:00:00 2001 From: Bram Stolk Date: Mon, 30 Sep 2024 00:57:23 -0700 Subject: [PATCH] [Math] Fix Nan from powf() domain error. This change prevents calling powf(x,y) with negative x. The SIMD versions using ssePower() already seem to be resistent to negative pixel values, but the scalar version was not. This would cause a SIGFPE on apps that have floating point exceptions enabled. FIXES: #2066 Signed-off-by: Bram Stolk --- src/OpenColorIO/ops/gamma/GammaOpCPU.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/OpenColorIO/ops/gamma/GammaOpCPU.cpp b/src/OpenColorIO/ops/gamma/GammaOpCPU.cpp index ace0006ca8..a7f008d30a 100644 --- a/src/OpenColorIO/ops/gamma/GammaOpCPU.cpp +++ b/src/OpenColorIO/ops/gamma/GammaOpCPU.cpp @@ -13,6 +13,11 @@ #include "SSE.h" +// powf() throws a domain error if the base is negative and the exponent non-integer. +// This is a safer call to powf() that avoids a negative base. +#define POW_NON_NEG(B, E) \ + std::pow((B) < 0.0f ? 0.0f : (B), (E)) + namespace OCIO_NAMESPACE { @@ -540,10 +545,10 @@ void GammaMoncurveOpCPUFwd::apply(const void * inImg, void * outImg, long numPix { const float pixel[4] = { in[0], in[1], in[2], in[3] }; - const float data[4] = { std::pow(pixel[0] * red[0] + red[1], red[2]), - std::pow(pixel[1] * grn[0] + grn[1], grn[2]), - std::pow(pixel[2] * blu[0] + blu[1], blu[2]), - std::pow(pixel[3] * alp[0] + alp[1], alp[2]) }; + const float data[4] = { POW_NON_NEG(pixel[0] * red[0] + red[1], red[2]), + POW_NON_NEG(pixel[1] * grn[0] + grn[1], grn[2]), + POW_NON_NEG(pixel[2] * blu[0] + blu[1], blu[2]), + POW_NON_NEG(pixel[3] * alp[0] + alp[1], alp[2]) }; out[0] = pixel[0]<=red[3] ? pixel[0] * red[4] : data[0]; out[1] = pixel[1]<=grn[3] ? pixel[1] * grn[4] : data[1]; @@ -629,10 +634,10 @@ void GammaMoncurveOpCPURev::apply(const void * inImg, void * outImg, long numPix { const float pixel[4] = { in[0], in[1], in[2], in[3] }; - const float data[4] = { std::pow(pixel[0], red[0]) * red[1] - red[2], - std::pow(pixel[1], grn[0]) * grn[1] - grn[2], - std::pow(pixel[2], blu[0]) * blu[1] - blu[2], - std::pow(pixel[3], alp[0]) * alp[1] - alp[2] }; + const float data[4] = { POW_NON_NEG(pixel[0], red[0]) * red[1] - red[2], + POW_NON_NEG(pixel[1], grn[0]) * grn[1] - grn[2], + POW_NON_NEG(pixel[2], blu[0]) * blu[1] - blu[2], + POW_NON_NEG(pixel[3], alp[0]) * alp[1] - alp[2] }; out[0] = pixel[0]<=red[3] ? pixel[0] * red[4] : data[0]; out[1] = pixel[1]<=grn[3] ? pixel[1] * grn[4] : data[1];