Details
-
Bug
-
Resolution: Done
-
P1: Critical
-
6.0, 6.1, 6.2.0, 6.2.1, 6.2.2, 6.2.3, 6.2.4, 6.3.0, 6.3.1, 6.4.0 Beta1
-
None
-
-
a2501fff81 (qt/qtbase/dev) a2501fff81 (qt/tqtc-qtbase/dev) b2fe6b1c05 (qt/qtbase/6.4) b2fe6b1c05 (qt/tqtc-qtbase/6.4) 2648d10229 (qt/qtbase/6.3) 2648d10229 (qt/tqtc-qtbase/6.3)
Description
A bug presumably introduced in f493d41722fc76a04f699ea26128fdf3d215d913 causes to access a table at index -1.
Callstack:
> Qt6Guid.dll!QColorTransferTable::applyInverse(float x, float resultLargerThan) Line 143 C++ Qt6Guid.dll!QColorTrcLut::fromTransferTable(const QColorTransferTable & table) Line 79 C++ Qt6Guid.dll!lutFromTrc(const QColorTrc & trc) Line 62 C++ Qt6Guid.dll!QColorTransformPrivate::updateLutsIn() Line 83 C++ Qt6Guid.dll!QColorTransformPrivate::apply<unsigned int>(unsigned int * dst, const unsigned int * src, __int64 count, QFlags<enum QColorTransformPrivate::TransformFlag> flags) Line 907 C++ Qt6Guid.dll!QColorTransformPrivate::apply(unsigned int * dst, const unsigned int * src, __int64 count, QFlags<enum QColorTransformPrivate::TransformFlag> flags) Line 1004 C++ Qt6Guid.dll!QImage::applyColorTransform::__l29::<lambda>(int yStart, int yEnd) Line 5063 C++ Qt6Guid.dll!std::invoke<void <lambda>(int, int) &,int,int>(QImage::applyColorTransform::__l29::void <lambda>(int, int) & _Obj, int && _Arg1, int && <_Args2_0>) Line 1503 C++ Qt6Guid.dll!std::_Invoker_ret<void,1>::_Call<void <lambda>(int, int) &,int,int>(QImage::applyColorTransform::__l29::void <lambda>(int, int) & _Func, int && <_Vals_0>, int && <_Vals_1>) Line 652 C++ Qt6Guid.dll!std::_Func_impl_no_alloc<void <lambda>(int, int),void,int,int>::_Do_call(int && <_Args_0>, int && <_Args_1>) Line 823 C++ Qt6Guid.dll!std::_Func_class<void,int,int>::operator()(int <_Args_0>, int <_Args_1>) Line 870 C++ Qt6Guid.dll!QImage::applyColorTransform(const QColorTransform & transform) Line 5087 C++
Explanation:
QColorTransferTable::applyInverse() is called in a for loop by QColorTrcLut::fromTransferTable(), here:
minInverse = table.applyInverse(i / qreal(255 * 16), minInverse);
The first time it is called, i is zero. I.e. the first argument passed to applyInverse() is zero. Therefore, applyInverse returns zero and minInverse becomes zero.
When the second call is made, the first argument is no longer zero, but now the second argument is zero. When evaluating the line
uint32_t i = static_cast<uint32_t>(std::floor(resultLargerThan * (m_tableSize - 1)));
i is assigned zero. In the line
auto it = std::lower_bound(m_table16.cbegin() + i, m_table16.cend(), v);
cbegin() is assigned to it. Therefore, i stays zero during the assignment of
i = it - m_table16.cbegin();
And finally, when evaluating
m_table16[i - 1];
we are accessing the table at index -1. Applications compiled in debug mode will assert. All others will crash.
Pls. note that the same broken logic is used a few lines below for m_table8.