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)
{
struct R {
QSimplexVariable *slack;
QConcreteSimplexVariable *slack;
QSimplexConstraint *limit;
};
QSimplexVariable *slack = new QSimplexVariable;
auto slack = new QConcreteSimplexVariable;
sizeConstraint->variables.insert(slack, type);
QSimplexConstraint *limit = new QSimplexConstraint;
@ -2783,7 +2783,7 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint
const QList<AnchorData *> &variables)
{
QList<QSimplexConstraint *> preferredConstraints;
QList<QSimplexVariable *> preferredVariables;
QList<QConcreteSimplexVariable *> preferredVariables;
QSimplexConstraint objective;
// 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;
for (int i = 0; i < constraints.size(); ++i) {
QSimplexVariable *slack;
QSimplexVariable *surplus;
QSimplexVariable *artificial;
QConcreteSimplexVariable *slack;
QConcreteSimplexVariable *surplus;
QConcreteSimplexVariable *artificial;
Q_ASSERT(constraints[i]->helper.first == 0);
Q_ASSERT(constraints[i]->artificial == nullptr);
switch(constraints[i]->ratio) {
case QSimplexConstraint::LessOrEqual:
slack = new QSimplexVariable;
slack = new QConcreteSimplexVariable;
slack->index = ++variableIndex;
constraints[i]->helper.first = slack;
constraints[i]->helper.second = 1.0;
break;
case QSimplexConstraint::MoreOrEqual:
surplus = new QSimplexVariable;
surplus = new QConcreteSimplexVariable;
surplus->index = ++variableIndex;
constraints[i]->helper.first = surplus;
constraints[i]->helper.second = -1.0;
Q_FALLTHROUGH();
case QSimplexConstraint::Equal:
artificial = new QSimplexVariable;
artificial = new QConcreteSimplexVariable;
constraints[i]->artificial = artificial;
artificialList += constraints[i]->artificial;
break;

View File

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