V4: Fix multiplication

Ensure that negative number times positive zero yields negative zero,
not positive zero.
Do the same adjustment in QJSPrimitiveValue

Fixes: QTBUG-104582
Change-Id: I8231bfb051b7d902e5e50bbd282410a572b1628a
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
(cherry picked from commit f59af767ae)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Fabian Kosmale 2023-01-05 17:39:15 +01:00 committed by Qt Cherry-pick Bot
parent 3951642331
commit 2a39659aee
4 changed files with 36 additions and 1 deletions

View File

@ -93,7 +93,11 @@ class QJSPrimitiveValue
static constexpr double op(double lhs, double rhs) { return lhs * rhs; }
static bool opOverflow(int lhs, int rhs, int *result)
{
return qMulOverflow(lhs, rhs, result);
// compare mul_int32 in qv4math_p.h
auto hadOverflow = qMulOverflow(lhs, rhs, result);
if (((lhs < 0) xor (rhs < 0)) && (*result == 0))
return true; // result must be negative 0, does not fit into int
return hadOverflow;
}
using StringNaNOperators::op;

View File

@ -52,6 +52,9 @@ static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b)
int result;
if (Q_UNLIKELY(mul_overflow(a, b, &result)))
return StaticValue::fromDouble(static_cast<double>(a) * b).asReturnedValue();
// need to handle the case where one number is negative and the other 0 ==> -0
if (((a < 0) xor (b < 0)) && (result == 0))
return StaticValue::fromDouble(-0.0).asReturnedValue();
return StaticValue::fromInt32(result).asReturnedValue();
}

View File

@ -225,6 +225,7 @@ private slots:
void returnError();
void catchError();
void mathMinMax();
void mathNegativeZero();
void importModule();
void importModuleRelative();
@ -4931,6 +4932,18 @@ void tst_QJSEngine::mathMinMax()
QVERIFY(QV4::Value(QJSValuePrivate::asReturnedValue(&result)).isInteger());
}
void tst_QJSEngine::mathNegativeZero()
{
QJSEngine engine;
QJSValue result = engine.evaluate("var a = 0; Object.is(-1*a, -0)");
QVERIFY(result.isBool());
QVERIFY(result.toBool());
result = engine.evaluate("var a = 0; Object.is(1*a, 0)");
QVERIFY(result.isBool());
QVERIFY(result.toBool());
}
void tst_QJSEngine::importModule()
{
// This is just a basic test for the API. Primary test coverage is via the ES test suite.

View File

@ -34,6 +34,8 @@ private slots:
void strictlyEquals();
void stringAndUrl();
void negativeNullMult();
private:
QJSEngine engine;
@ -929,6 +931,19 @@ void tst_QJSPrimitiveValue::stringAndUrl()
QCOMPARE(engine.fromPrimitiveValue<QUrl>(immediateStringValue), url);
}
void tst_QJSPrimitiveValue::negativeNullMult()
{
QJSPrimitiveValue zero(0);
QJSPrimitiveValue negative(-1);
QJSPrimitiveValue positive(1);
QCOMPARE((zero * negative).type(), QJSPrimitiveValue::Double);
QCOMPARE((negative * zero).type(), QJSPrimitiveValue::Double);
QCOMPARE((zero * positive).type(), QJSPrimitiveValue::Integer);
QCOMPARE((positive * zero).type(), QJSPrimitiveValue::Integer);
}
QTEST_MAIN(tst_QJSPrimitiveValue)
#include "tst_qjsprimitivevalue.moc"