forked from Mirrors/openclonk
Fix signed int overflow in BltAlpha (#1661)
The red color channel calculation could overflow into the sign bit, which is undefined behavior. At least one compiler takes advantage of this and assumes it cannot happen, resulting in incorrect results. BltAlphaAdd looks similar, but does in fact not have this bug because it shifts the color channel far enough that multiplication can't overflow.liquid_container
parent
4fdafbc78a
commit
5fe327663f
|
@ -35,9 +35,9 @@ inline void BltAlpha(DWORD &dwDst, DWORD dwSrc)
|
|||
// blit one color value w/alpha on another
|
||||
if (dwDst>>24 == 0x00) { dwDst=dwSrc; return; }
|
||||
BYTE byAlphaSrc=BYTE(dwSrc>>24); BYTE byAlphaDst=255-byAlphaSrc;
|
||||
dwDst = std::min<uint32_t>((int(dwDst & 0xff ) * byAlphaDst + int(dwSrc & 0xff ) * byAlphaSrc) >>8, 0xff) | // blue
|
||||
std::min<uint32_t>((int(dwDst & 0xff00) * byAlphaDst + int(dwSrc & 0xff00 ) * byAlphaSrc) >>8 & 0xff00, 0xff00) | // green
|
||||
std::min<uint32_t>((int(dwDst & 0xff0000) * byAlphaDst + int(dwSrc & 0xff0000) * byAlphaSrc) >>8 & 0xff0000, 0xff0000) | // red
|
||||
dwDst = std::min<uint32_t>(((dwDst & 0xff ) * byAlphaDst + (dwSrc & 0xff ) * byAlphaSrc) >>8, 0xff) | // blue
|
||||
std::min<uint32_t>(((dwDst & 0xff00) * byAlphaDst + (dwSrc & 0xff00 ) * byAlphaSrc) >>8 & 0xff00, 0xff00) | // green
|
||||
std::min<uint32_t>(((dwDst & 0xff0000) * byAlphaDst + (dwSrc & 0xff0000) * byAlphaSrc) >>8 & 0xff0000, 0xff0000) | // red
|
||||
std::min<uint32_t>( (dwDst >> 24) + byAlphaSrc, 255) << 24; // alpha
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue