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;
|
||||
_translationUnit = 0;
|
||||
if (_control) {
|
||||
delete _control->diagnosticClient();
|
||||
delete _control;
|
||||
}
|
||||
_control = 0;
|
||||
}
|
||||
|
||||
@@ -296,6 +298,25 @@ Control *Document::control() const
|
||||
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
|
||||
{
|
||||
return _revision;
|
||||
@@ -696,6 +717,7 @@ void Document::releaseSourceAndAST()
|
||||
if (!_keepSourceAndASTCount.deref()) {
|
||||
_source.clear();
|
||||
_translationUnit->release();
|
||||
if (_control)
|
||||
_control->squeeze();
|
||||
}
|
||||
}
|
||||
|
@@ -78,6 +78,7 @@ public:
|
||||
unsigned bytesOffset, unsigned utf16charsOffset);
|
||||
|
||||
Control *control() const;
|
||||
Control *swapControl(Control *newControl);
|
||||
TranslationUnit *translationUnit() const;
|
||||
|
||||
bool skipFunctionBody() const;
|
||||
|
@@ -688,6 +688,31 @@ public:
|
||||
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
|
||||
|
||||
bool ResolveExpression::visit(SimpleNameAST *ast)
|
||||
@@ -730,9 +755,9 @@ bool ResolveExpression::visit(SimpleNameAST *ast)
|
||||
exprTyper.init(doc, _context.snapshot(), _context.bindings(),
|
||||
QSet<const Declaration* >(_autoDeclarationsBeingResolved) << decl);
|
||||
|
||||
Document::Ptr exprDoc =
|
||||
documentForExpression(exprTyper.preprocessedExpression(initializer));
|
||||
exprDoc->check();
|
||||
const ExpressionDocumentHelper exprHelper(exprTyper.preprocessedExpression(initializer),
|
||||
_context.bindings()->control().data());
|
||||
const Document::Ptr exprDoc = exprHelper.document;
|
||||
|
||||
DeduceAutoCheck deduceAuto(ast->name->identifier(), exprDoc->translationUnit());
|
||||
if (deduceAuto._block)
|
||||
|
Reference in New Issue
Block a user