QSimplex: split QConcreteSimplexVariable from QSimplexVariable

The latter was used both as a concrete type as well as a base class,
driving Coverity nuts because it couldn't prove that we weren't
deleting derived classes (AnchorData) through a QSimplexVariable
pointer.

This is the same issue that Coverity took with QBrushData (CIDs
218724, 11772), and the solution is the same
(cf. 3bbc9e29ef59683351cf35c19a8bd4a030615c64):

Split the Janus-headed class into one that acts only as the base class
(and has a protected dtor) and one that only acts as a concrete class
(and we can mark it final).

The protected dtor in the former now statically ensures we don't
delete a derived class object through a QSimplexVariable pointer.

We don't need to modify AnchorData subclasses, because AnchorData
introduces a virtual destructor.

Coverity-Id: 390828
Pick-to: 6.8 6.5
Change-Id: I981c02e69af44ebacd4ba3aec76792e14eb15836
Reviewed-by: Mate Barany <mate.barany@qt.io>
(cherry picked from commit a405834ae694ef791d0b648b9a6bb65b67904731)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2025-03-12 15:03:45 +01:00 committed by Qt Cherry-pick Bot
parent 5ed1dcd1cc
commit ef60ea194e
3 changed files with 17 additions and 11 deletions

View File

@ -2764,11 +2764,11 @@ enum slackType { Grower = -1, Shrinker = 1 };
static auto createSlack(QSimplexConstraint *sizeConstraint, qreal interval, slackType type) static auto createSlack(QSimplexConstraint *sizeConstraint, qreal interval, slackType type)
{ {
struct R { struct R {
QSimplexVariable *slack; QConcreteSimplexVariable *slack;
QSimplexConstraint *limit; QSimplexConstraint *limit;
}; };
QSimplexVariable *slack = new QSimplexVariable; auto slack = new QConcreteSimplexVariable;
sizeConstraint->variables.insert(slack, type); sizeConstraint->variables.insert(slack, type);
QSimplexConstraint *limit = new QSimplexConstraint; QSimplexConstraint *limit = new QSimplexConstraint;
@ -2783,7 +2783,7 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint
const QList<AnchorData *> &variables) const QList<AnchorData *> &variables)
{ {
QList<QSimplexConstraint *> preferredConstraints; QList<QSimplexConstraint *> preferredConstraints;
QList<QSimplexVariable *> preferredVariables; QList<QConcreteSimplexVariable *> preferredVariables;
QSimplexConstraint objective; QSimplexConstraint objective;
// Fill the objective coefficients for this variable. In the // Fill the objective coefficients for this variable. In the

View File

@ -156,28 +156,28 @@ bool QSimplex::setConstraints(const QList<QSimplexConstraint *> &newConstraints)
QList <QSimplexVariable *> artificialList; QList <QSimplexVariable *> artificialList;
for (int i = 0; i < constraints.size(); ++i) { for (int i = 0; i < constraints.size(); ++i) {
QSimplexVariable *slack; QConcreteSimplexVariable *slack;
QSimplexVariable *surplus; QConcreteSimplexVariable *surplus;
QSimplexVariable *artificial; QConcreteSimplexVariable *artificial;
Q_ASSERT(constraints[i]->helper.first == 0); Q_ASSERT(constraints[i]->helper.first == 0);
Q_ASSERT(constraints[i]->artificial == nullptr); Q_ASSERT(constraints[i]->artificial == nullptr);
switch(constraints[i]->ratio) { switch(constraints[i]->ratio) {
case QSimplexConstraint::LessOrEqual: case QSimplexConstraint::LessOrEqual:
slack = new QSimplexVariable; slack = new QConcreteSimplexVariable;
slack->index = ++variableIndex; slack->index = ++variableIndex;
constraints[i]->helper.first = slack; constraints[i]->helper.first = slack;
constraints[i]->helper.second = 1.0; constraints[i]->helper.second = 1.0;
break; break;
case QSimplexConstraint::MoreOrEqual: case QSimplexConstraint::MoreOrEqual:
surplus = new QSimplexVariable; surplus = new QConcreteSimplexVariable;
surplus->index = ++variableIndex; surplus->index = ++variableIndex;
constraints[i]->helper.first = surplus; constraints[i]->helper.first = surplus;
constraints[i]->helper.second = -1.0; constraints[i]->helper.second = -1.0;
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case QSimplexConstraint::Equal: case QSimplexConstraint::Equal:
artificial = new QSimplexVariable; artificial = new QConcreteSimplexVariable;
constraints[i]->artificial = artificial; constraints[i]->artificial = artificial;
artificialList += constraints[i]->artificial; artificialList += constraints[i]->artificial;
break; break;

View File

@ -29,8 +29,14 @@ struct QSimplexVariable
qreal result; qreal result;
int index; int index;
protected:
QT_DECLARE_RO5_SMF_AS_DEFAULTED(QSimplexVariable)
}; };
// "pure" QSimplexVariable without the protected destructor
struct QConcreteSimplexVariable final : QSimplexVariable
{
};
/*! /*!
\internal \internal
@ -59,8 +65,8 @@ struct QSimplexConstraint final
qreal constant; qreal constant;
Ratio ratio; Ratio ratio;
std::pair<QSimplexVariable *, qreal> helper; std::pair<QConcreteSimplexVariable *, qreal> helper;
QSimplexVariable * artificial; QConcreteSimplexVariable *artificial;
void invert(); void invert();