tst_QLocale: actually check formattedDataSize() with qint64

... not just int, and not just non-negative values.

Reveals a problem with bytes == numeric_limit<qint64>::min(), says
ubsan (example; all min64 fail):

    global/qnumeric.h:479:26: runtime error: negation of -9223372036854775808 cannot be represented in type 'long long int'; cast to an unsigned type to negate this value to itself
    text/qlocale.cpp:5062:82: runtime error: signed integer overflow: -2147483648 * 3 cannot be represented in type 'int'
    text/qlocale.cpp:5062:26: runtime error: division by zero
    FAIL!  : tst_QLocale::formattedDataSize(English-Decimal-min) Compared values are not the same
       Actual   (QLocale(language).formattedDataSize(bytes, decimalPlaces, units)): "-inf bytes"
       Expected ("output")                                                        : "-9.22 EB"

So exclude that from testing, for now.

Pick-to: 6.9 6.8 6.5 6.2 5.15
Coverity-Id: 474294
Change-Id: Ia1f8e87c58a9fdc2668b6745956e913384cff4c7
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Marc Mutz 2025-02-17 10:34:49 +01:00
parent 24a26ed3a3
commit 562cb8e4d9

View File

@ -4210,7 +4210,7 @@ void tst_QLocale::formattedDataSize_data()
QTest::addColumn<QLocale::Language>("language"); QTest::addColumn<QLocale::Language>("language");
QTest::addColumn<int>("decimalPlaces"); QTest::addColumn<int>("decimalPlaces");
QTest::addColumn<QLocale::DataSizeFormats>("units"); QTest::addColumn<QLocale::DataSizeFormats>("units");
QTest::addColumn<int>("bytes"); QTest::addColumn<qint64>("bytes");
QTest::addColumn<QString>("output"); QTest::addColumn<QString>("output");
struct { struct {
@ -4225,45 +4225,66 @@ void tst_QLocale::formattedDataSize_data()
{ "C", QLocale::C, "bytes", 'B', '.' } { "C", QLocale::C, "bytes", 'B', '.' }
}; };
constexpr auto min64 = (std::numeric_limits<qint64>::min)();
constexpr auto max64 = (std::numeric_limits<qint64>::max)();
for (const auto row : data) { for (const auto row : data) {
#define ROWB(id, deci, num, text) \ #define ROWB(id, deci, num, text) \
QTest::addRow("%s-%s", row.name, id) \ QTest::addRow("%s-%s", row.name, id) \
<< row.lang << deci << format \ << row.lang << deci << format \
<< num << (QString(text) + QChar(' ') + QString(row.bytes)) << qint64{num} << (QString(text) + QChar(' ') + QString(row.bytes))
#define ROWQ(id, deci, num, head, tail) \ #define ROWQ(id, deci, num, head, tail) \
QTest::addRow("%s-%s", row.name, id) \ QTest::addRow("%s-%s", row.name, id) \
<< row.lang << deci << format \ << row.lang << deci << format \
<< num << (QString(head) + QChar(row.sep) + QString(tail) + QChar(row.abbrev)) << qint64{num} << (QString(head) + QChar(row.sep) + QString(tail) + QChar(row.abbrev))
// Metatype system fails to handle raw enum members as format; needs variable // Metatype system fails to handle raw enum members as format; needs variable
{ {
const QLocale::DataSizeFormats format = QLocale::DataSizeIecFormat; const QLocale::DataSizeFormats format = QLocale::DataSizeIecFormat;
ROWB("IEC-0", 2, 0, "0"); ROWB("IEC-0", 2, 0, "0");
ROWB("IEC-10", 2, 10, "10"); ROWB("IEC-10", 2, 10, "10");
ROWB("IEC--10", 2, -10, "-10");
ROWQ("IEC-12Ki", 2, 12345, "12", "06 Ki"); ROWQ("IEC-12Ki", 2, 12345, "12", "06 Ki");
ROWQ("IEC-16Ki", 2, 16384, "16", "00 Ki"); ROWQ("IEC-16Ki", 2, 16384, "16", "00 Ki");
ROWQ("IEC--16Ki", 2, -16384, "-16", "00 Ki");
ROWQ("IEC-1235k", 2, 1234567, "1", "18 Mi"); ROWQ("IEC-1235k", 2, 1234567, "1", "18 Mi");
ROWQ("IEC-1374k", 2, 1374744, "1", "31 Mi"); ROWQ("IEC-1374k", 2, 1374744, "1", "31 Mi");
ROWQ("IEC-1234M", 2, 1234567890, "1", "15 Gi"); ROWQ("IEC-1234M", 2, 1234567890, "1", "15 Gi");
if (false) { // hits UB
ROWQ("IEC-min", 2, min64, "-8", "00 Ei");
}
ROWQ("IEC-max", 2, max64, "8", "00 Ei");
} }
{ {
const QLocale::DataSizeFormats format = QLocale::DataSizeTraditionalFormat; const QLocale::DataSizeFormats format = QLocale::DataSizeTraditionalFormat;
ROWB("Trad-0", 2, 0, "0"); ROWB("Trad-0", 2, 0, "0");
ROWB("Trad-10", 2, 10, "10"); ROWB("Trad-10", 2, 10, "10");
ROWB("Trad--10", 2, -10, "-10");
ROWQ("Trad-12Ki", 2, 12345, "12", "06 k"); ROWQ("Trad-12Ki", 2, 12345, "12", "06 k");
ROWQ("Trad-16Ki", 2, 16384, "16", "00 k"); ROWQ("Trad-16Ki", 2, 16384, "16", "00 k");
ROWQ("Trad-1235k", 2, 1234567, "1", "18 M"); ROWQ("Trad-1235k", 2, 1234567, "1", "18 M");
ROWQ("Trad--1235k", 2, -1234567, "-1", "18 M");
ROWQ("Trad-1374k", 2, 1374744, "1", "31 M"); ROWQ("Trad-1374k", 2, 1374744, "1", "31 M");
ROWQ("Trad-1234M", 2, 1234567890, "1", "15 G"); ROWQ("Trad-1234M", 2, 1234567890, "1", "15 G");
if (false) { // hits UB
ROWQ("Trad-min", 2, min64, "-8", "00 E");
}
ROWQ("Trad-max", 2, max64, "8", "00 E");
} }
{ {
const QLocale::DataSizeFormats format = QLocale::DataSizeSIFormat; const QLocale::DataSizeFormats format = QLocale::DataSizeSIFormat;
ROWB("Decimal-0", 2, 0, "0"); ROWB("Decimal-0", 2, 0, "0");
ROWB("Decimal-10", 2, 10, "10"); ROWB("Decimal-10", 2, 10, "10");
ROWB("Decimal--10", 2, -10, "-10");
ROWQ("Decimal-16Ki", 2, 16384, "16", "38 k"); ROWQ("Decimal-16Ki", 2, 16384, "16", "38 k");
ROWQ("Decimal-1234k", 2, 1234567, "1", "23 M"); ROWQ("Decimal-1234k", 2, 1234567, "1", "23 M");
ROWQ("Decimal-1374k", 2, 1374744, "1", "37 M"); ROWQ("Decimal-1374k", 2, 1374744, "1", "37 M");
ROWQ("Decimal-1234M", 2, 1234567890, "1", "23 G"); ROWQ("Decimal-1234M", 2, 1234567890, "1", "23 G");
ROWQ("Decimal--1234M", 2, -1234567890, "-1", "23 G");
if (false) { // hits UB
ROWQ("Decimal-min", 2, min64, "-9", "22 E");
}
ROWQ("Decimal-max", 2, max64, "9", "22 E");
} }
#undef ROWQ #undef ROWQ
#undef ROWB #undef ROWB
@ -4276,29 +4297,29 @@ void tst_QLocale::formattedDataSize_data()
const QLocale::DataSizeFormats siFormat = QLocale::DataSizeSIFormat; const QLocale::DataSizeFormats siFormat = QLocale::DataSizeSIFormat;
const QLocale::Language lang = QLocale::Russian; const QLocale::Language lang = QLocale::Russian;
QTest::newRow("Russian-IEC-0") << lang << 2 << iecFormat << 0 << QString("0 \u0431\u0430\u0439\u0442\u044B"); QTest::newRow("Russian-IEC-0") << lang << 2 << iecFormat << 0LL << QString("0 \u0431\u0430\u0439\u0442\u044B");
QTest::newRow("Russian-IEC-10") << lang << 2 << iecFormat << 10 << QString("10 \u0431\u0430\u0439\u0442\u044B"); QTest::newRow("Russian-IEC-10") << lang << 2 << iecFormat << 10LL << QString("10 \u0431\u0430\u0439\u0442\u044B");
// CLDR doesn't provide IEC prefixes (yet?) so they aren't getting translated // CLDR doesn't provide IEC prefixes (yet?) so they aren't getting translated
QTest::newRow("Russian-IEC-12Ki") << lang << 2 << iecFormat << 12345 << QString("12,06 KiB"); QTest::newRow("Russian-IEC-12Ki") << lang << 2 << iecFormat << 12345LL << QString("12,06 KiB");
QTest::newRow("Russian-IEC-16Ki") << lang << 2 << iecFormat << 16384 << QString("16,00 KiB"); QTest::newRow("Russian-IEC-16Ki") << lang << 2 << iecFormat << 16384LL << QString("16,00 KiB");
QTest::newRow("Russian-IEC-1235k") << lang << 2 << iecFormat << 1234567 << QString("1,18 MiB"); QTest::newRow("Russian-IEC-1235k") << lang << 2 << iecFormat << 1234567LL << QString("1,18 MiB");
QTest::newRow("Russian-IEC-1374k") << lang << 2 << iecFormat << 1374744 << QString("1,31 MiB"); QTest::newRow("Russian-IEC-1374k") << lang << 2 << iecFormat << 1374744LL << QString("1,31 MiB");
QTest::newRow("Russian-IEC-1234M") << lang << 2 << iecFormat << 1234567890 << QString("1,15 GiB"); QTest::newRow("Russian-IEC-1234M") << lang << 2 << iecFormat << 1234567890LL << QString("1,15 GiB");
QTest::newRow("Russian-Trad-0") << lang << 2 << traditionalFormat << 0 << QString("0 \u0431\u0430\u0439\u0442\u044B"); QTest::newRow("Russian-Trad-0") << lang << 2 << traditionalFormat << 0LL << QString("0 \u0431\u0430\u0439\u0442\u044B");
QTest::newRow("Russian-Trad-10") << lang << 2 << traditionalFormat << 10 << QString("10 \u0431\u0430\u0439\u0442\u044B"); QTest::newRow("Russian-Trad-10") << lang << 2 << traditionalFormat << 10LL << QString("10 \u0431\u0430\u0439\u0442\u044B");
QTest::newRow("Russian-Trad-12Ki") << lang << 2 << traditionalFormat << 12345 << QString("12,06 \u043A\u0411"); QTest::newRow("Russian-Trad-12Ki") << lang << 2 << traditionalFormat << 12345LL << QString("12,06 \u043A\u0411");
QTest::newRow("Russian-Trad-16Ki") << lang << 2 << traditionalFormat << 16384 << QString("16,00 \u043A\u0411"); QTest::newRow("Russian-Trad-16Ki") << lang << 2 << traditionalFormat << 16384LL << QString("16,00 \u043A\u0411");
QTest::newRow("Russian-Trad-1235k") << lang << 2 << traditionalFormat << 1234567 << QString("1,18 \u041C\u0411"); QTest::newRow("Russian-Trad-1235k") << lang << 2 << traditionalFormat << 1234567LL << QString("1,18 \u041C\u0411");
QTest::newRow("Russian-Trad-1374k") << lang << 2 << traditionalFormat << 1374744 << QString("1,31 \u041C\u0411"); QTest::newRow("Russian-Trad-1374k") << lang << 2 << traditionalFormat << 1374744LL << QString("1,31 \u041C\u0411");
QTest::newRow("Russian-Trad-1234M") << lang << 2 << traditionalFormat << 1234567890 << QString("1,15 \u0413\u0411"); QTest::newRow("Russian-Trad-1234M") << lang << 2 << traditionalFormat << 1234567890LL << QString("1,15 \u0413\u0411");
QTest::newRow("Russian-Decimal-0") << lang << 2 << siFormat << 0 << QString("0 \u0431\u0430\u0439\u0442\u044B"); QTest::newRow("Russian-Decimal-0") << lang << 2 << siFormat << 0LL << QString("0 \u0431\u0430\u0439\u0442\u044B");
QTest::newRow("Russian-Decimal-10") << lang << 2 << siFormat << 10 << QString("10 \u0431\u0430\u0439\u0442\u044B"); QTest::newRow("Russian-Decimal-10") << lang << 2 << siFormat << 10LL << QString("10 \u0431\u0430\u0439\u0442\u044B");
QTest::newRow("Russian-Decimal-16Ki") << lang << 2 << siFormat << 16384 << QString("16,38 \u043A\u0411"); QTest::newRow("Russian-Decimal-16Ki") << lang << 2 << siFormat << 16384LL << QString("16,38 \u043A\u0411");
QTest::newRow("Russian-Decimal-1234k") << lang << 2 << siFormat << 1234567 << QString("1,23 \u041C\u0411"); QTest::newRow("Russian-Decimal-1234k") << lang << 2 << siFormat << 1234567LL << QString("1,23 \u041C\u0411");
QTest::newRow("Russian-Decimal-1374k") << lang << 2 << siFormat << 1374744 << QString("1,37 \u041C\u0411"); QTest::newRow("Russian-Decimal-1374k") << lang << 2 << siFormat << 1374744LL << QString("1,37 \u041C\u0411");
QTest::newRow("Russian-Decimal-1234M") << lang << 2 << siFormat << 1234567890 << QString("1,23 \u0413\u0411"); QTest::newRow("Russian-Decimal-1234M") << lang << 2 << siFormat << 1234567890LL << QString("1,23 \u0413\u0411");
} }
void tst_QLocale::formattedDataSize() void tst_QLocale::formattedDataSize()
@ -4306,7 +4327,7 @@ void tst_QLocale::formattedDataSize()
QFETCH(QLocale::Language, language); QFETCH(QLocale::Language, language);
QFETCH(int, decimalPlaces); QFETCH(int, decimalPlaces);
QFETCH(QLocale::DataSizeFormats, units); QFETCH(QLocale::DataSizeFormats, units);
QFETCH(int, bytes); QFETCH(const qint64, bytes);
QTEST(QLocale(language).formattedDataSize(bytes, decimalPlaces, units), "output"); QTEST(QLocale(language).formattedDataSize(bytes, decimalPlaces, units), "output");
} }