Details
-
Bug
-
Resolution: Done
-
P3: Somewhat important
-
4.7.1
-
None
-
Windows XP
-
185f9e0758cd7ee649f42b5c788fdfff6031d83c (qt/qtbase/dev)
Description
There are four instances of "Duff's device" in qdrawhelper_p.h. Three of them are labeled as such. I will show the fourth as an example:
template <class T>
inline void qt_memfill(T *dest, T value, int count)
{
int n = (count + 7) / 8;
switch (count & 0x07)
{
case 0: do { *dest++ = value;
case 7: *dest++ = value;
case 6: *dest++ = value;
case 5: *dest++ = value;
case 4: *dest++ = value;
case 3: *dest++ = value;
case 2: *dest++ = value;
case 1: *dest++ = value;
} while (--n > 0);
}
}
If this is called with count==0, then because (0 & 0x07)==0, the switch will jump to case 0 and thus fill eight elements, as if count had been 8. The do-while doesn't prevent this, of course, because do-while always executes its body at least once.
The same problem (effectively a buffer overflow) exists in all four Duff's devices in this file.
This has occassionally caused access violations in an older version of our product, using Qt 4.5.1, when a buffer was located immediately before a page boundary and then overflowed into an unassigned address range. We didn't observe any other effects, but a buffer overflow usually does no good.
The crash we observed was in gui\painting\qblendfunctions.cpp, in the function:
static void qt_blend_rgb16_on_rgb16(uchar *dst, int dbpl,
const uchar *src, int sbpl,
int w, int h,
int const_alpha)
in the line calling:
QT_MEMCPY_USHORT(dst, src, w);
(which contains Duff's device) with w==0.
The call to func = qt_blend_rgb16_on_rgb16 originated from:
void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
const QImage &img,
SrcOverBlendFunc func,
const QRect &clip,
int alpha,
const QRect &sr)
We are now using Qt 4.6.2, and in that version, QRasterPaintEnginePrivate::drawImage avoids calling func with w==0, because the code from Qt 4.5.1:
if (iw < 0)
return;
has been changed to:
if (iw <= 0)
return;
somewhere between those two versions of Qt.
I don't know if this was done to fix that particular crash, or if it was just an optimization.
This issue in qt_memfill has been fixed with the commit 500f28f04a08e37525e3d1deb5cfe6e908c66b15, however it would be safer to check (count<=0) than just (!count).
A negative count would cause a buffer overflow of 1 to 8 bytes depending on the last 3 bits of count. While all current callers might be avoiding this, I would not rely on it in the future. The checks for ==0 and <=0 should perform equally fast.
the other three Duff's devices still have the same problem:
template <class DST, class SRC>
inline void qt_memconvert(DST *dest, const SRC *src, int count)
See the else branch.
#define QT_MEMCPY_REV_UINT(dest, src, length)
#define QT_MEMCPY_USHORT(dest, src, length)
I therefore kindly ask you to re-open the case and
1. fix the remaining three instances of Duff's device, and
2. consider checking (count<=0) instead of (!count) in qt_memfill.