forked from qt-creator/qt-creator
C++: Fix use-after-free crash when handling auto expressions
The Control of the Document "exprDoc" in ResolveExpression::visit( SimpleNameAST*ast) owns names that are passed on further as part of the LookupItems. However, the life time of that Document and thus the Control ends in that function. Fix by using the appropriate Control object. Task-number: QTCREATORBUG-16731 Change-Id: I5a7af0a67613fff79f7e07865801585c13bb9b45 Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
@@ -286,8 +286,10 @@ Document::~Document()
|
|||||||
{
|
{
|
||||||
delete _translationUnit;
|
delete _translationUnit;
|
||||||
_translationUnit = 0;
|
_translationUnit = 0;
|
||||||
|
if (_control) {
|
||||||
delete _control->diagnosticClient();
|
delete _control->diagnosticClient();
|
||||||
delete _control;
|
delete _control;
|
||||||
|
}
|
||||||
_control = 0;
|
_control = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,6 +298,25 @@ Control *Document::control() const
|
|||||||
return _control;
|
return _control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Control *Document::swapControl(Control *newControl)
|
||||||
|
{
|
||||||
|
if (newControl) {
|
||||||
|
const StringLiteral *fileId = newControl->stringLiteral(_translationUnit->fileId()->chars(),
|
||||||
|
_translationUnit->fileId()->size());
|
||||||
|
const auto newTranslationUnit = new TranslationUnit(newControl, fileId);
|
||||||
|
newTranslationUnit->setLanguageFeatures(_translationUnit->languageFeatures());
|
||||||
|
delete _translationUnit;
|
||||||
|
_translationUnit = newTranslationUnit;
|
||||||
|
} else {
|
||||||
|
delete _translationUnit;
|
||||||
|
_translationUnit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Control *oldControl = _control;
|
||||||
|
_control = newControl;
|
||||||
|
return oldControl;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned Document::revision() const
|
unsigned Document::revision() const
|
||||||
{
|
{
|
||||||
return _revision;
|
return _revision;
|
||||||
@@ -696,6 +717,7 @@ void Document::releaseSourceAndAST()
|
|||||||
if (!_keepSourceAndASTCount.deref()) {
|
if (!_keepSourceAndASTCount.deref()) {
|
||||||
_source.clear();
|
_source.clear();
|
||||||
_translationUnit->release();
|
_translationUnit->release();
|
||||||
|
if (_control)
|
||||||
_control->squeeze();
|
_control->squeeze();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -78,6 +78,7 @@ public:
|
|||||||
unsigned bytesOffset, unsigned utf16charsOffset);
|
unsigned bytesOffset, unsigned utf16charsOffset);
|
||||||
|
|
||||||
Control *control() const;
|
Control *control() const;
|
||||||
|
Control *swapControl(Control *newControl);
|
||||||
TranslationUnit *translationUnit() const;
|
TranslationUnit *translationUnit() const;
|
||||||
|
|
||||||
bool skipFunctionBody() const;
|
bool skipFunctionBody() const;
|
||||||
|
@@ -688,6 +688,31 @@ public:
|
|||||||
bool _block;
|
bool _block;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExpressionDocumentHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Set up an expression document with an external Control
|
||||||
|
ExpressionDocumentHelper(const QByteArray &utf8code, Control *control)
|
||||||
|
: document(Document::create(QLatin1String("<completion>")))
|
||||||
|
{
|
||||||
|
Control *oldControl = document->swapControl(control);
|
||||||
|
delete oldControl->diagnosticClient();
|
||||||
|
delete oldControl;
|
||||||
|
document->setUtf8Source(utf8code);
|
||||||
|
document->parse(Document::ParseExpression);
|
||||||
|
document->check();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the external Control is not deleted
|
||||||
|
~ExpressionDocumentHelper()
|
||||||
|
{
|
||||||
|
document->swapControl(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Document::Ptr document;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace anonymous
|
} // namespace anonymous
|
||||||
|
|
||||||
bool ResolveExpression::visit(SimpleNameAST *ast)
|
bool ResolveExpression::visit(SimpleNameAST *ast)
|
||||||
@@ -730,9 +755,9 @@ bool ResolveExpression::visit(SimpleNameAST *ast)
|
|||||||
exprTyper.init(doc, _context.snapshot(), _context.bindings(),
|
exprTyper.init(doc, _context.snapshot(), _context.bindings(),
|
||||||
QSet<const Declaration* >(_autoDeclarationsBeingResolved) << decl);
|
QSet<const Declaration* >(_autoDeclarationsBeingResolved) << decl);
|
||||||
|
|
||||||
Document::Ptr exprDoc =
|
const ExpressionDocumentHelper exprHelper(exprTyper.preprocessedExpression(initializer),
|
||||||
documentForExpression(exprTyper.preprocessedExpression(initializer));
|
_context.bindings()->control().data());
|
||||||
exprDoc->check();
|
const Document::Ptr exprDoc = exprHelper.document;
|
||||||
|
|
||||||
DeduceAutoCheck deduceAuto(ast->name->identifier(), exprDoc->translationUnit());
|
DeduceAutoCheck deduceAuto(ast->name->identifier(), exprDoc->translationUnit());
|
||||||
if (deduceAuto._block)
|
if (deduceAuto._block)
|
||||||
|
Reference in New Issue
Block a user