[clang] [clang][bytecode] Fix an inconsistency with loop condition jumps (PR #135530)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 13 01:00:47 PDT 2025
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/135530
When emitting the jump for e.g. a for loop condition, we used to jump out of the CondScope, leaving the scope initialized, because we skipped the corresponding Destroy opcode. If that loop was in a loop itself, that outer loop could then iterate once more, leading to us initializing a scope that was still initialized.
Fix this by also destroying the scope after the EndLabel.
>From 52b7e8519cb4612f0b4dd803762d010145144e24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 12 Apr 2025 17:40:19 +0200
Subject: [PATCH] [clang][bytecode] Fix an inconsistency with loop condition
jumps
When emitting the jump for e.g. a for loop condition, we used to jump
out of the CondScope, leaving the scope initialized, because we skipped
the corresponding Destroy opcode. If that loop was in a loop itself,
that outer loop could then iterate once more, leading to us initializing
a scope that was still initialized.
Fix this by also destroying the scope after the EndLabel.
---
clang/lib/AST/ByteCode/Compiler.cpp | 31 +++++++++++++++--------------
clang/lib/AST/ByteCode/Compiler.h | 3 ++-
2 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 86b43585cd292..376daec5cd0d2 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5431,21 +5431,21 @@ bool Compiler<Emitter>::visitForStmt(const ForStmt *S) {
this->fallthrough(CondLabel);
this->emitLabel(CondLabel);
- {
- LocalScope<Emitter> CondScope(this);
- if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
- if (!visitDeclStmt(CondDecl))
- return false;
+ // Start of loop body.
+ LocalScope<Emitter> CondScope(this);
+ if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
+ if (!visitDeclStmt(CondDecl))
+ return false;
- if (Cond) {
- if (!this->visitBool(Cond))
- return false;
- if (!this->jumpFalse(EndLabel))
- return false;
- }
+ if (!this->maybeEmitDeferredVarInit(S->getConditionVariable()))
+ return false;
- if (!this->maybeEmitDeferredVarInit(S->getConditionVariable()))
+ if (Cond) {
+ if (!this->visitBool(Cond))
+ return false;
+ if (!this->jumpFalse(EndLabel))
return false;
+ }
if (Body && !this->visitStmt(Body))
return false;
@@ -5457,13 +5457,14 @@ bool Compiler<Emitter>::visitForStmt(const ForStmt *S) {
if (!CondScope.destroyLocals())
return false;
- }
if (!this->jump(CondLabel))
return false;
+ // End of loop body.
- this->fallthrough(EndLabel);
this->emitLabel(EndLabel);
- return true;
+ // If we jumped out of the loop above, we still need to clean up the condition
+ // scope.
+ return CondScope.destroyLocals();
}
template <class Emitter>
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 256e917728886..858957367d85d 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -531,9 +531,10 @@ template <class Emitter> class LocalScope : public VariableScope<Emitter> {
if (!Idx)
return true;
+ // NB: We are *not* resetting Idx here as to allow multiple
+ // calls to destroyLocals().
bool Success = this->emitDestructors(E);
this->Ctx->emitDestroy(*Idx, E);
- this->Idx = std::nullopt;
return Success;
}
More information about the cfe-commits
mailing list