Skip to content

Commit

Permalink
moc: remove the attempt to create one large string literal
Browse files Browse the repository at this point in the history
Commit dda9c9e fixed some outstanding
issues with moc's calculation of the maximum string length, but it
missed one. This commit instead opts to remove the calculation entirely
and instead have multiple char array members in the qt_meta_stringdata.
We needed a single string back in Qt 4.0 when the stringdata *was* a
single char array.

Since 5.0, we've used a structure with multiple members and pointer
arithmetic going past the end of the arrays, from the top of the object.
That's UB, but since it's always been UB and can't be fixed until Qt 7
anyway, let's go full monty on it and have one char array per meta
object string.

The struct qt_meta_stringdata_Qt_t for namespace Qt now has 1217
stringdataXXX members.

Pick-to: 6.2 6.3 6.4
Change-Id: I6d3880c7d99d4fc494c8fffd16fb0d1573e387dc
Reviewed-by: Qt CI Bot <[email protected]>
Reviewed-by: Fabian Kosmale <[email protected]>
  • Loading branch information
thiagomacieira committed Jun 25, 2022
1 parent 3816b14 commit 0978646
Showing 1 changed file with 30 additions and 58 deletions.
88 changes: 30 additions & 58 deletions src/tools/moc/generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,27 @@ static inline uint lengthOfEscapedString(const QByteArray &str)
return str.length() - extra;
}

// Prints \a s to \a out, breaking it into lines of at most ColumnWidth. The
// opening and closing quotes are NOT included (it's up to the caller).
static void printStringWithIndentation(FILE *out, const QByteArray &s)
{
static constexpr int ColumnWidth = 72;
int len = s.length();
int idx = 0;

do {
int spanLen = qMin(ColumnWidth - 2, len - idx);
// don't cut escape sequences at the end of a line
int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
if (backSlashPos >= idx) {
int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, len - idx);
}
fprintf(out, "\n \"%.*s\"", spanLen, s.constData() + idx);
idx += spanLen;
} while (idx < len);
}

void Generator::strreg(const QByteArray &s)
{
if (!strings.contains(s))
Expand Down Expand Up @@ -231,23 +252,11 @@ void Generator::generateCode()
//
// Build stringdata struct
//
const int constCharArraySizeLimit = 65535;
fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, " uint offsetsAndSizes[%d];\n", int(strings.size() * 2));
{
int stringDataLength = 0;
int stringDataCounter = 0;
for (int i = 0; i < strings.size(); ++i) {
int thisLength = lengthOfEscapedString(strings.at(i)) + 1;
stringDataLength += thisLength;
if (stringDataLength / constCharArraySizeLimit) {
// save previous stringdata and start computing the next one.
fprintf(out, " char stringdata%d[%d];\n", stringDataCounter++, stringDataLength - thisLength);
stringDataLength = thisLength;
}
}
fprintf(out, " char stringdata%d[%d];\n", stringDataCounter, stringDataLength);

for (int i = 0; i < strings.size(); ++i) {
int thisLength = lengthOfEscapedString(strings.at(i)) + 1;
fprintf(out, " char stringdata%d[%d];\n", i, thisLength);
}
fprintf(out, "};\n");

Expand All @@ -272,56 +281,19 @@ void Generator::generateCode()

idx += len + 1;
}
fprintf(out, "\n },\n");
fprintf(out, "\n }");
}

//
// Build stringdata array
// Build stringdata arrays
//
fprintf(out, " \"");
int col = 0;
int len = 0;
int stringDataLength = 0;
for (int i = 0; i < strings.size(); ++i) {
QByteArray s = strings.at(i);
len = s.length();
stringDataLength += len + 1;
if (stringDataLength >= constCharArraySizeLimit) {
fprintf(out, "\",\n \"");
stringDataLength = len + 1;
col = 0;
} else if (i)
fputs("\\0", out); // add \0 at the end of each string

if (col && col + len >= 72) {
fprintf(out, "\"\n \"");
col = 0;
} else if (len && s.at(0) >= '0' && s.at(0) <= '9') {
fprintf(out, "\"\"");
len += 2;
}
int idx = 0;
while (idx < s.length()) {
if (idx > 0) {
col = 0;
fprintf(out, "\"\n \"");
}
int spanLen = qMin(70, s.length() - idx);
// don't cut escape sequences at the end of a line
int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
if (backSlashPos >= idx) {
int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx);
}
fprintf(out, "%.*s", spanLen, s.constData() + idx);
idx += spanLen;
col += spanLen;
}
col += len + 2;
for (const QByteArray &s : qAsConst(strings)) {
fputc(',', out);
printStringWithIndentation(out, s);
}

// Terminate stringdata struct
fprintf(out, "\"\n};\n");
fprintf(out, "\n};\n");
fprintf(out, "#undef QT_MOC_LITERAL\n\n");

//
Expand Down

0 comments on commit 0978646

Please sign in to comment.