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
Nicolas Hake 2016-02-08 02:39:54 +01:00
parent 4fdafbc78a
commit 5fe327663f
1 changed files with 3 additions and 3 deletions

View File

@ -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
}