Skip to content

Commit

Permalink
FIX(server): Respect Qt's desired initialization order
Browse files Browse the repository at this point in the history
In a Qt application, the QApplication object should be the first QObject
that is created. However, the `Meta` class used to have a static member
called `mp`, which means that this member gets initialized _before_
main() runs and therefore before the QApplication is created.

This has caused an "Invalid nullptr in QObject::connect" warning
somewhere in Qt's internals (since the move to Qt 6). The impact of this
warning is unclear at this point.

This commit makes the mp parameter a std::unique_ptr that gets
explicitly initialized in the main function (more or less right after
the QApplication object is created). This guarantees that the MetaParams
object does not get created before the QApplication object, fixing the
observed warning.

It is worth noting that we do have a couple of other static QObject
variables in the main translation unit, but these seem to be
inconsequential (at least they don't seem to trigger a similar warning).

Fixes #6669
  • Loading branch information
Krzmbrzl committed Jan 11, 2025
1 parent 2aeb6cb commit 7271bca
Show file tree
Hide file tree
Showing 13 changed files with 795 additions and 248 deletions.
14 changes: 7 additions & 7 deletions scripts/generateIceWrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,23 @@ def create_disclaimerComment():

def generateFunction(className, functionName, wrapArgs, callArgs):
function = "void ::MumbleServer::" + className + "I::" + functionName + "_async(" + (", ".join(wrapArgs)) + ") {\n"
function += "\t// qWarning() << \"" + functionName + "\" << meta->mp.qsIceSecretRead.isNull() << meta->mp.qsIceSecretRead.isEmpty();\n"
function += "\t// qWarning() << \"" + functionName + "\" << ::Meta::mp->qsIceSecretRead.isNull() << ::Meta::mp->qsIceSecretRead.isEmpty();\n"
function += "#ifndef ACCESS_" + className + "_" + functionName + "_ALL\n"
function += "#\tifdef ACCESS_" + className + "_" + functionName + "_READ\n"
function += "\tif (!meta->mp.qsIceSecretRead.isNull()) {\n"
function += "\t\tbool ok = !meta->mp.qsIceSecretRead.isEmpty();\n"
function += "\tif (!::Meta::mp->qsIceSecretRead.isNull()) {\n"
function += "\t\tbool ok = !::Meta::mp->qsIceSecretRead.isEmpty();\n"
function += "#\telse\n"
function += "\tif (!meta->mp.qsIceSecretRead.isNull() || !meta->mp.qsIceSecretWrite.isNull()) {\n"
function += "\t\tbool ok = !meta->mp.qsIceSecretWrite.isEmpty();\n"
function += "\tif (!::Meta::mp->qsIceSecretRead.isNull() || !::Meta::mp->qsIceSecretWrite.isNull()) {\n"
function += "\t\tbool ok = !::Meta::mp->qsIceSecretWrite.isEmpty();\n"
function += "#\tendif // ACCESS_" + className + "_" + functionName + "_READ\n"
function += "\t\t::Ice::Context::const_iterator i = current.ctx.find(\"secret\");\n"
function += "\t\tok = ok && (i != current.ctx.end());\n"
function += "\t\tif (ok) {\n"
function += "\t\t\tconst QString &secret = u8((*i).second);\n"
function += "#\tifdef ACCESS_" + className + "_" + functionName + "_READ\n"
function += "\t\t\tok = ((secret == meta->mp.qsIceSecretRead) || (secret == meta->mp.qsIceSecretWrite));\n"
function += "\t\t\tok = ((secret == ::Meta::mp->qsIceSecretRead) || (secret == ::Meta::mp->qsIceSecretWrite));\n"
function += "#\telse\n"
function += "\t\t\tok = (secret == meta->mp.qsIceSecretWrite);\n"
function += "\t\t\tok = (secret == ::Meta::mp->qsIceSecretWrite);\n"
function += "#\tendif // ACCESS_" + className + "_" + functionName + "_READ\n"
function += "\t\t}\n"
function += "\n"
Expand Down
353 changes: 353 additions & 0 deletions src/PacketDataStream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,353 @@
// Copyright The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "PacketDataStream.h"

quint32 PacketDataStream::size() const {
return offset;
}

quint32 PacketDataStream::capacity() const {
return maxsize;
}

bool PacketDataStream::isValid() const {
return ok;
}

quint32 PacketDataStream::left() const {
return maxsize - offset;
}

quint32 PacketDataStream::undersize() const {
return overshoot;
}

void PacketDataStream::append(const quint64 v) {
#ifndef QT_NO_DEBUG
Q_ASSERT(v <= 0xff);
#endif
if (offset < maxsize)
data[offset++] = static_cast< unsigned char >(v);
else {
ok = false;
overshoot++;
}
};

void PacketDataStream::append(const char *d, quint32 len) {
if (left() >= len) {
memcpy(&data[offset], d, len);
offset += len;
} else {
unsigned int l = left();
memset(&data[offset], 0, l);
offset += l;
overshoot += len - l;
ok = false;
}
}

void PacketDataStream::skip(quint32 len) {
if (left() >= len)
offset += len;
else
ok = false;
}

quint64 PacketDataStream::next() {
if (offset < maxsize)
return data[offset++];
else {
ok = false;
return 0;
}
};

quint8 PacketDataStream::next8() {
if (offset < maxsize)
return data[offset++];
else {
ok = false;
return 0;
}
}

void PacketDataStream::rewind() {
offset = 0;
}

void PacketDataStream::truncate() {
maxsize = offset;
}

const unsigned char *PacketDataStream::dataPtr() const {
return reinterpret_cast< const unsigned char * >(&data[offset]);
}

unsigned char *PacketDataStream::dataPtr() {
return reinterpret_cast< unsigned char * >(&data[offset]);
}

const char *PacketDataStream::charPtr() const {
return reinterpret_cast< const char * >(&data[offset]);
}

QByteArray PacketDataStream::dataBlock(quint32 len) {
if (len <= left()) {
QByteArray a(charPtr(), static_cast< int >(len));
offset += len;
return a;
} else {
ok = false;
return QByteArray();
}
}

void PacketDataStream::setup(unsigned char *d, unsigned int msize) {
data = d;
offset = 0;
overshoot = 0;
maxsize = msize;
ok = true;
}

PacketDataStream::PacketDataStream(const unsigned char *d, unsigned int msize) {
setup(const_cast< unsigned char * >(d), msize);
};

PacketDataStream::PacketDataStream(const char *d, unsigned int msize) {
setup(const_cast< unsigned char * >(reinterpret_cast< const unsigned char * >(d)), msize);
};

PacketDataStream::PacketDataStream(char *d, unsigned int msize) {
setup(reinterpret_cast< unsigned char * >(d), msize);
};

PacketDataStream::PacketDataStream(unsigned char *d, unsigned int msize) {
setup(d, msize);
};

PacketDataStream::PacketDataStream(const QByteArray &qba) {
setup(const_cast< unsigned char * >(reinterpret_cast< const unsigned char * >(qba.constData())),
static_cast< unsigned int >(qba.size()));
}

PacketDataStream::PacketDataStream(QByteArray &qba) {
unsigned char *ptr = reinterpret_cast< unsigned char * >(qba.data());
setup(ptr, static_cast< unsigned int >(qba.capacity()));
}

PacketDataStream &PacketDataStream::operator<<(const quint64 value) {
quint64 i = value;

if ((i & 0x8000000000000000LL) && (~i < 0x100000000LL)) {
// Signed number.
i = ~i;
if (i <= 0x3) {
// Special case for -1 to -4. The most significant bits of the first byte must be (in binary) 111111
// followed by the 2 bits representing the absolute value of the encoded number. Shortcase for -1 to -4
append(0xFC | i);
return *this;
} else {
// Add flag byte, whose most significant bits are (in binary) 111110 that indicates
// that what follows is the varint encoding of the absolute value of i, but that the
// value itself is supposed to be negative.
append(0xF8);
}
}
if (i < 0x80) {
// Encode as 7-bit, positive number -> most significant bit of first byte must be zero
append(i);
} else if (i < 0x4000) {
// Encode as 14-bit, positive number -> most significant bits of first byte must be (in binary) 10
append((i >> 8) | 0x80);
append(i & 0xFF);
} else if (i < 0x200000) {
// Encode as 21-bit, positive number -> most significant bits of first byte must be (in binary) 110
append((i >> 16) | 0xC0);
append((i >> 8) & 0xFF);
append(i & 0xFF);
} else if (i < 0x10000000) {
// Encode as 28-bit, positive number -> most significant bits of first byte must be (in binary) 1110
append((i >> 24) | 0xE0);
append((i >> 16) & 0xFF);
append((i >> 8) & 0xFF);
append(i & 0xFF);
} else if (i < 0x100000000LL) {
// Encode as 32-bit, positive number -> most significant bits of first byte must be (in binary) 111100
// Remaining bits in first byte remain unused
append(0xF0);
append((i >> 24) & 0xFF);
append((i >> 16) & 0xFF);
append((i >> 8) & 0xFF);
append(i & 0xFF);
} else {
// Encode as 64-bit, positive number -> most significant bits of first byte must be (in binary) 111101
// Remaining bits in first byte remain unused
append(0xF4);
append((i >> 56) & 0xFF);
append((i >> 48) & 0xFF);
append((i >> 40) & 0xFF);
append((i >> 32) & 0xFF);
append((i >> 24) & 0xFF);
append((i >> 16) & 0xFF);
append((i >> 8) & 0xFF);
append(i & 0xFF);
}
return *this;
}

PacketDataStream &PacketDataStream::operator>>(quint64 &i) {
quint64 v = next();

if ((v & 0x80) == 0x00) {
i = (v & 0x7F);
} else if ((v & 0xC0) == 0x80) {
i = (v & 0x3F) << 8 | next();
} else if ((v & 0xF0) == 0xF0) {
switch (v & 0xFC) {
case 0xF0:
i = next() << 24 | next() << 16 | next() << 8 | next();
break;
case 0xF4:
i = next() << 56 | next() << 48 | next() << 40 | next() << 32 | next() << 24 | next() << 16
| next() << 8 | next();
break;
case 0xF8:
*this >> i;
i = ~i;
break;
case 0xFC:
i = v & 0x03;
i = ~i;
break;
default:
ok = false;
i = 0;
break;
}
} else if ((v & 0xF0) == 0xE0) {
i = (v & 0x0F) << 24 | next() << 16 | next() << 8 | next();
} else if ((v & 0xE0) == 0xC0) {
i = (v & 0x1F) << 16 | next() << 8 | next();
}
return *this;
}

PacketDataStream &PacketDataStream::operator<<(const QByteArray &a) {
*this << a.size();
append(a.constData(), static_cast< unsigned int >(a.size()));
return *this;
}

PacketDataStream &PacketDataStream::operator>>(QByteArray &a) {
quint32 len;
*this >> len;
if (len > left()) {
len = left();
ok = false;
}
a = QByteArray(reinterpret_cast< const char * >(&data[offset]), static_cast< int >(len));
offset += len;
return *this;
}

PacketDataStream &PacketDataStream::operator<<(const QString &s) {
return *this << s.toUtf8();
}

// Using the data directly instead of through qbuff avoids a copy.
PacketDataStream &PacketDataStream::operator>>(QString &s) {
quint32 len;
*this >> len;
if (len > left()) {
len = left();
ok = false;
}
s = QString::fromUtf8(reinterpret_cast< const char * >(&data[offset]), static_cast< int >(len));
offset += len;
return *this;
}

PacketDataStream &PacketDataStream::operator<<(const bool b) {
quint32 v = b ? 1 : 0;
return *this << v;
}

PacketDataStream &PacketDataStream::operator>>(bool &b) {
quint32 v;
*this >> v;
b = v ? true : false;
return *this;
}

union double64u {
quint64 ui;
double d;
};

PacketDataStream &PacketDataStream::operator<<(const double v) {
double64u u;
u.d = v;
return *this << u.ui;
}

PacketDataStream &PacketDataStream::operator>>(double &v) {
double64u u;
*this >> u.ui;
v = u.d;
return *this;
}

union float32u {
quint8 ui[4];
float f;
};

PacketDataStream &PacketDataStream::operator<<(const float v) {
float32u u;
u.f = v;
append(u.ui[0]);
append(u.ui[1]);
append(u.ui[2]);
append(u.ui[3]);
return *this;
}

PacketDataStream &PacketDataStream::operator>>(float &v) {
float32u u;
if (left() < 4) {
ok = false;
v = 0;
}
u.ui[0] = next8();
u.ui[1] = next8();
u.ui[2] = next8();
u.ui[3] = next8();
v = u.f;
return *this;
}

#define INTMAPOPERATOR(type) \
template<> PacketDataStream &PacketDataStream::operator<<< type >(const type v) { \
return *this << static_cast< quint64 >(v); \
} \
template<> PacketDataStream &PacketDataStream::operator>>< type >(type &v) { \
quint64 vv; \
*this >> vv; \
v = static_cast< type >(vv); \
return *this; \
}

// INTMAPOPERATOR(qsizetype);
INTMAPOPERATOR(int);
INTMAPOPERATOR(unsigned int);
INTMAPOPERATOR(short);
INTMAPOPERATOR(unsigned short);
INTMAPOPERATOR(char);
INTMAPOPERATOR(unsigned char);

#undef INTMAPOPERATOR
Loading

0 comments on commit 7271bca

Please sign in to comment.