aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4codegen.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-11-11 14:23:42 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-11-14 10:19:08 +0100
commit1d3d7437bab7c3a0c3222de3a00bcf2c9437ae76 (patch)
treef01eb6c6a415cbdb2e0ff5b031624228a9282eed /src/qml/compiler/qv4codegen.cpp
parent0dbb801920ea04d99834f7e89e02241f12bd54f8 (diff)
QML: Fix the most blatant TDZ violations
When reading a let or const register before its declaration we can be sure this is invalid. Task-number: QTBUG-108362 Fixes: QTBUG-77428 Change-Id: I7e8f8b46079860f00c051c1a91f773dc8cdd5595 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r--src/qml/compiler/qv4codegen.cpp73
1 files changed, 53 insertions, 20 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 5851ca3827..44e283a71b 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -69,6 +69,28 @@ static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGene
}
}
+void Codegen::generateThrowException(const QString &type, const QString &text)
+{
+ RegisterScope scope(this);
+ Instruction::Construct construct;
+ if (text.isEmpty()) {
+ construct.argc = 0;
+ construct.argv = 0;
+ } else {
+ construct.argc = 1;
+ Instruction::LoadRuntimeString load;
+ load.stringId = registerString(text);
+ bytecodeGenerator->addInstruction(load);
+ construct.argv = Reference::fromAccumulator(this).storeOnStack().stackSlot();
+ }
+ Reference r = referenceForName(type, false);
+ r = r.storeOnStack();
+ construct.func = r.stackSlot();
+ bytecodeGenerator->addInstruction(construct);
+ Instruction::ThrowException throwException;
+ bytecodeGenerator->addInstruction(throwException);
+}
+
Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict,
CodegenWarningInterface *interface, bool storeSourceLocations)
: _module(nullptr),
@@ -2139,6 +2161,10 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
Reference e = expression(it->expression);
if (hasError())
break;
+ if (e.throwsReferenceError) {
+ generateThrowException(QStringLiteral("ReferenceError"),
+ e.name + QStringLiteral(" is not defined"));
+ }
if (!argc && !it->next && !hasSpread) {
// avoid copy for functions taking a single argument
if (e.isStackSlot())
@@ -2560,6 +2586,7 @@ bool Codegen::visit(FunctionExpression *ast)
Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, const SourceLocation &accessLocation)
{
Context::ResolvedName resolved = _context->resolveName(name, accessLocation);
+ bool throwsReferenceError = false;
if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack
|| resolved.type == Context::ResolvedName::Import) {
@@ -2572,6 +2599,8 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co
Q_ASSERT(_interface);
_interface->reportVarUsedBeforeDeclaration(
name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
+ if (resolved.type == Context::ResolvedName::Stack && resolved.requiresTDZCheck)
+ throwsReferenceError = true;
}
if (resolved.isInjected && accessLocation.isValid()) {
@@ -2600,6 +2629,7 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co
r.requiresTDZCheck = resolved.requiresTDZCheck;
r.name = name; // used to show correct name at run-time when TDZ check fails.
r.sourceLocation = accessLocation;
+ r.throwsReferenceError = throwsReferenceError;
return r;
}
@@ -4447,20 +4477,18 @@ bool Codegen::Reference::storeWipesAccumulator() const
void Codegen::Reference::storeAccumulator() const
{
+ if (throwsReferenceError) {
+ codegen->generateThrowException(QStringLiteral("ReferenceError"),
+ name + QStringLiteral(" is not defined"));
+ return;
+ }
+
if (isReferenceToConst) {
// throw a type error
- RegisterScope scope(codegen);
- Reference r = codegen->referenceForName(QStringLiteral("TypeError"), false);
- r = r.storeOnStack();
- Instruction::Construct construct;
- construct.func = r.stackSlot();
- construct.argc = 0;
- construct.argv = 0;
- codegen->bytecodeGenerator->addInstruction(construct);
- Instruction::ThrowException throwException;
- codegen->bytecodeGenerator->addInstruction(throwException);
+ codegen->generateThrowException(QStringLiteral("TypeError"));
return;
}
+
switch (type) {
case Super:
Q_UNREACHABLE_RETURN();
@@ -4531,20 +4559,25 @@ void Codegen::Reference::storeAccumulator() const
void Codegen::Reference::loadInAccumulator() const
{
- auto tdzCheck = [this](bool requiresCheck){
+ auto tdzCheck = [this](bool requiresCheck, bool throwsReferenceError) {
+ if (throwsReferenceError) {
+ codegen->generateThrowException(QStringLiteral("ReferenceError"),
+ name + QStringLiteral(" is not defined"));
+ return;
+ }
if (!requiresCheck)
return;
Instruction::DeadTemporalZoneCheck check;
check.name = codegen->registerString(name);
codegen->bytecodeGenerator->addInstruction(check);
};
- auto tdzCheckStackSlot = [this, tdzCheck](Moth::StackSlot slot, bool requiresCheck){
+ auto tdzCheckStackSlot = [this, tdzCheck](Moth::StackSlot slot, bool requiresCheck, bool throwsReferenceError) {
if (!requiresCheck)
return;
Instruction::LoadReg load;
load.reg = slot;
codegen->bytecodeGenerator->addInstruction(load);
- tdzCheck(true);
+ tdzCheck(true, throwsReferenceError);
};
switch (type) {
@@ -4553,7 +4586,7 @@ void Codegen::Reference::loadInAccumulator() const
case Super:
Q_UNREACHABLE_RETURN();
case SuperProperty:
- tdzCheckStackSlot(property, subscriptRequiresTDZCheck);
+ tdzCheckStackSlot(property, subscriptRequiresTDZCheck, false);
Instruction::LoadSuperProperty load;
load.property = property.stackSlot();
codegen->bytecodeGenerator->addInstruction(load);
@@ -4600,7 +4633,7 @@ QT_WARNING_POP
Instruction::LoadReg load;
load.reg = stackSlot();
codegen->bytecodeGenerator->addInstruction(load);
- tdzCheck(requiresTDZCheck);
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
} return;
case ScopedLocal: {
if (!scope) {
@@ -4613,7 +4646,7 @@ QT_WARNING_POP
load.scope = scope;
codegen->bytecodeGenerator->addInstruction(load);
}
- tdzCheck(requiresTDZCheck);
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
return;
}
case Name:
@@ -4655,7 +4688,7 @@ QT_WARNING_POP
return;
case Member:
propertyBase.loadInAccumulator();
- tdzCheck(requiresTDZCheck);
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
if (sourceLocation.isValid())
codegen->bytecodeGenerator->setLocation(sourceLocation);
@@ -4691,12 +4724,12 @@ QT_WARNING_POP
Instruction::LoadImport load;
load.index = index;
codegen->bytecodeGenerator->addInstruction(load);
- tdzCheck(requiresTDZCheck);
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
} return;
case Subscript: {
- tdzCheckStackSlot(elementBase, requiresTDZCheck);
+ tdzCheckStackSlot(elementBase, requiresTDZCheck, throwsReferenceError);
elementSubscript.loadInAccumulator();
- tdzCheck(subscriptRequiresTDZCheck);
+ tdzCheck(subscriptRequiresTDZCheck, false);
Instruction::LoadElement load;
load.base = elementBase;
codegen->bytecodeGenerator->addInstruction(load);