TextEditor: Add valid checks for text lines

QTextLayout::lineForTextPosition can return invalid lines,
which when accessed may crash. To workaround we add
QTC_ASSERT to guard against this (see linked issue crash report)

Fixes: QTCREATORBUG-28837
Change-Id: I66d8d8a46e766caa492ec2178b1fa88e35211333
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-04-27 08:30:19 +02:00
parent 2b640f3dc3
commit 1339a4a998

View File

@@ -129,6 +129,7 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
QTextLayout *blockLayout = block.layout(); QTextLayout *blockLayout = block.layout();
int pos = begin.position() - begin.block().position(); int pos = begin.position() - begin.block().position();
QTextLine line = blockLayout->lineForTextPosition(pos); QTextLine line = blockLayout->lineForTextPosition(pos);
QTC_ASSERT(line.isValid(), return {});
QRectF lineRect = line.naturalTextRect(); QRectF lineRect = line.naturalTextRect();
lineRect = lineRect.translated(blockGeometry.topLeft()); lineRect = lineRect.translated(blockGeometry.topLeft());
int x = line.cursorToX(pos); int x = line.cursorToX(pos);
@@ -154,12 +155,12 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
QTextLayout *blockLayout = block.layout(); QTextLayout *blockLayout = block.layout();
int firstLine = 0; int firstLine = 0;
QTextLine line = blockLayout->lineAt(firstLine);
int beginChar = 0; int beginChar = 0;
if (block == begin.block()) { if (block == begin.block()) {
beginChar = begin.positionInBlock(); beginChar = begin.positionInBlock();
line = blockLayout->lineForTextPosition(beginChar); QTextLine line = blockLayout->lineForTextPosition(beginChar);
QTC_ASSERT(line.isValid(), return {});
firstLine = line.lineNumber(); firstLine = line.lineNumber();
const int lineEnd = line.textStart() + line.textLength(); const int lineEnd = line.textStart() + line.textLength();
if (beginChar == lineEnd) if (beginChar == lineEnd)
@@ -170,7 +171,9 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
int endChar = -1; int endChar = -1;
if (block == end.block()) { if (block == end.block()) {
endChar = end.positionInBlock(); endChar = end.positionInBlock();
lastLine = blockLayout->lineForTextPosition(endChar).lineNumber(); QTextLine line = blockLayout->lineForTextPosition(endChar);
QTC_ASSERT(line.isValid(), return {});
lastLine = line.lineNumber();
if (endChar == beginChar) if (endChar == beginChar)
break; // Do not expand overlay to empty selection at end break; // Do not expand overlay to empty selection at end
} else { } else {
@@ -181,7 +184,8 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
} }
for (int i = firstLine; i <= lastLine; ++i) { for (int i = firstLine; i <= lastLine; ++i) {
line = blockLayout->lineAt(i); QTextLine line = blockLayout->lineAt(i);
QTC_ASSERT(line.isValid(), return {});
QRectF lineRect = line.naturalTextRect(); QRectF lineRect = line.naturalTextRect();
if (i == firstLine && beginChar > 0) if (i == firstLine && beginChar > 0)
lineRect.setLeft(line.cursorToX(beginChar)); lineRect.setLeft(line.cursorToX(beginChar));