fix: handle top-down DIB images in clipboard bitmap converter

A BITMAPINFOHEADER with negative biHeight (top-down DIB) caused
std::length_error crash in toIClipboard because 4 * w * h went
negative and wrapped to a huge size_t in string::append.

Fix: use abs(height) for buffer size and SetDIBitsToDevice, and
add null check for CreateDIBSection.

fixes: #9869
This commit is contained in:
Mustafa Senoglu 2026-07-31 22:47:43 +03:00 committed by Nick Bolton
parent 3c37f2ff11
commit 40f743fb37

View file

@ -1,6 +1,7 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Synergy App Ltd * SPDX-FileCopyrightText: (C) 2012 - 2016 Synergy App Ltd
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/ */
@ -72,6 +73,7 @@ std::string MSWindowsClipboardBitmapConverter::toIClipboard(HANDLE data) const
BITMAPINFOHEADER info; BITMAPINFOHEADER info;
LONG w = bitmap->bmiHeader.biWidth; LONG w = bitmap->bmiHeader.biWidth;
LONG h = bitmap->bmiHeader.biHeight; LONG h = bitmap->bmiHeader.biHeight;
const LONG absHeight = (h < 0) ? -h : h;
info.biSize = sizeof(BITMAPINFOHEADER); info.biSize = sizeof(BITMAPINFOHEADER);
info.biWidth = w; info.biWidth = w;
info.biHeight = h; info.biHeight = h;
@ -85,6 +87,12 @@ std::string MSWindowsClipboardBitmapConverter::toIClipboard(HANDLE data) const
info.biClrImportant = 0; info.biClrImportant = 0;
HDC dc = GetDC(nullptr); HDC dc = GetDC(nullptr);
HBITMAP dst = CreateDIBSection(dc, (BITMAPINFO *)&info, DIB_RGB_COLORS, &raw, nullptr, 0); HBITMAP dst = CreateDIBSection(dc, (BITMAPINFO *)&info, DIB_RGB_COLORS, &raw, nullptr, 0);
if (dst == nullptr || raw == nullptr) {
LOG_WARN("failed to allocate destination bitmap for clipboard image");
ReleaseDC(nullptr, dc);
GlobalUnlock(data);
return std::string();
}
// find the start of the pixel data // find the start of the pixel data
const char *srcBits = (const char *)bitmap + bitmap->bmiHeader.biSize; const char *srcBits = (const char *)bitmap + bitmap->bmiHeader.biSize;
@ -103,14 +111,14 @@ std::string MSWindowsClipboardBitmapConverter::toIClipboard(HANDLE data) const
// copy source image to destination image // copy source image to destination image
HDC dstDC = CreateCompatibleDC(dc); HDC dstDC = CreateCompatibleDC(dc);
HGDIOBJ oldBitmap = SelectObject(dstDC, dst); HGDIOBJ oldBitmap = SelectObject(dstDC, dst);
SetDIBitsToDevice(dstDC, 0, 0, w, h, 0, 0, 0, h, srcBits, bitmap, DIB_RGB_COLORS); SetDIBitsToDevice(dstDC, 0, 0, w, absHeight, 0, 0, 0, absHeight, srcBits, bitmap, DIB_RGB_COLORS);
SelectObject(dstDC, oldBitmap); SelectObject(dstDC, oldBitmap);
DeleteDC(dstDC); DeleteDC(dstDC);
GdiFlush(); GdiFlush();
// extract data // extract data
std::string image((const char *)&info, info.biSize); std::string image((const char *)&info, info.biSize);
image.append((const char *)raw, 4 * w * h); image.append((const char *)raw, static_cast<size_t>(4) * static_cast<size_t>(w) * static_cast<size_t>(absHeight));
// clean up GDI // clean up GDI
DeleteObject(dst); DeleteObject(dst);