Make sure we don't count down past 0 QT_FATAL_CRITICALS
The old code first checked for == 0, then, if false, executed a
fetchAndAdd(-1), both with relaxed memory ordering. This can lead to
executions that, counter to what the code comment states, can count
down past 0:
// T1 T2
loadRelaxed() // true
loadRelaxed() // true
fetchAndAddRelaxed(-1) // e.g. 1 → 0
fetchAndAddRelaxed(-1) // 0 → -1
while fatality is detected exactly once, this execution doesn't stop
at 0 and causes further calls to isFatal() to count down further, with
the (very) remote spectre of underflow past INT_MIN.
Fix by using a CAS loop instead, so each count-down uses only one
step, not two, which therefore can no longer interleave.
Fixes: QTBUG-115062
Pick-to: 6.6 6.5 6.2 5.15
Change-Id: If77b906c94cb4b9fa91bfad84fe63bc8d9103b0a
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
parent
bbb71e7e80
commit
b933a5668c
|
|
@ -188,7 +188,11 @@ static bool is_fatal_count_down(QAtomicInt &n)
|
|||
{
|
||||
// it's fatal if the current value is exactly 1,
|
||||
// otherwise decrement if it's non-zero
|
||||
return n.loadRelaxed() && n.fetchAndAddRelaxed(-1) == 1;
|
||||
|
||||
int v = n.loadRelaxed();
|
||||
while (v != 0 && !n.testAndSetRelaxed(v, v - 1, v))
|
||||
;
|
||||
return v == 1; // we exited the loop, so either v == 0 or CAS succeeded to set n from v to v-1
|
||||
}
|
||||
|
||||
static bool isFatal(QtMsgType msgType)
|
||||
|
|
|
|||
Loading…
Reference in New Issue