From 329dea217d05a47ee00bb005eba1f0fc6b3dd0f6 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sat, 29 May 2021 19:58:36 -0300
Subject: shader: Always initialize up reference in structure control flow

Fixes ubsan issue.
---
 .../frontend/maxwell/structured_control_flow.cpp   | 67 ++++++++++++----------
 1 file changed, 36 insertions(+), 31 deletions(-)

(limited to 'src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp')

diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index ebe5c2654e..c1e0646e6b 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -101,22 +101,24 @@ struct Statement : ListBaseHook {
         : children{std::move(children_)}, cond{cond_}, up{up_}, type{StatementType::Loop} {}
     Statement(Break, Statement* cond_, Statement* up_)
         : cond{cond_}, up{up_}, type{StatementType::Break} {}
-    Statement(Return) : type{StatementType::Return} {}
-    Statement(Kill) : type{StatementType::Kill} {}
-    Statement(Unreachable) : type{StatementType::Unreachable} {}
+    Statement(Return, Statement* up_) : up{up_}, type{StatementType::Return} {}
+    Statement(Kill, Statement* up_) : up{up_}, type{StatementType::Kill} {}
+    Statement(Unreachable, Statement* up_) : up{up_}, type{StatementType::Unreachable} {}
     Statement(FunctionTag) : children{}, type{StatementType::Function} {}
-    Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {}
-    Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {}
-    Statement(Or, Statement* op_a_, Statement* op_b_)
-        : op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {}
+    Statement(Identity, IR::Condition cond_, Statement* up_)
+        : guest_cond{cond_}, up{up_}, type{StatementType::Identity} {}
+    Statement(Not, Statement* op_, Statement* up_) : op{op_}, up{up_}, type{StatementType::Not} {}
+    Statement(Or, Statement* op_a_, Statement* op_b_, Statement* up_)
+        : op_a{op_a_}, op_b{op_b_}, up{up_}, type{StatementType::Or} {}
     Statement(SetVariable, u32 id_, Statement* op_, Statement* up_)
         : op{op_}, id{id_}, up{up_}, type{StatementType::SetVariable} {}
-    Statement(SetIndirectBranchVariable, IR::Reg branch_reg_, s32 branch_offset_)
+    Statement(SetIndirectBranchVariable, IR::Reg branch_reg_, s32 branch_offset_, Statement* up_)
         : branch_offset{branch_offset_},
-          branch_reg{branch_reg_}, type{StatementType::SetIndirectBranchVariable} {}
-    Statement(Variable, u32 id_) : id{id_}, type{StatementType::Variable} {}
-    Statement(IndirectBranchCond, u32 location_)
-        : location{location_}, type{StatementType::IndirectBranchCond} {}
+          branch_reg{branch_reg_}, up{up_}, type{StatementType::SetIndirectBranchVariable} {}
+    Statement(Variable, u32 id_, Statement* up_)
+        : id{id_}, up{up_}, type{StatementType::Variable} {}
+    Statement(IndirectBranchCond, u32 location_, Statement* up_)
+        : location{location_}, up{up_}, type{StatementType::IndirectBranchCond} {}
 
     ~Statement() {
         if (HasChildren(type)) {
@@ -385,7 +387,7 @@ private:
     void BuildTree(Flow::CFG& cfg, Flow::Function& function, u32& label_id,
                    std::vector<Node>& gotos, Node function_insert_point,
                    std::optional<Node> return_label) {
-        Statement* const false_stmt{pool.Create(Identity{}, IR::Condition{false})};
+        Statement* const false_stmt{pool.Create(Identity{}, IR::Condition{false}, &root_stmt)};
         Tree& root{root_stmt.children};
         std::unordered_map<Flow::Block*, Node> local_labels;
         local_labels.reserve(function.blocks.size());
@@ -411,7 +413,8 @@ private:
 
             switch (block.end_class) {
             case Flow::EndClass::Branch: {
-                Statement* const always_cond{pool.Create(Identity{}, IR::Condition{true})};
+                Statement* const always_cond{
+                    pool.Create(Identity{}, IR::Condition{true}, &root_stmt)};
                 if (block.cond == IR::Condition{true}) {
                     const Node true_label{local_labels.at(block.branch_true)};
                     gotos.push_back(
@@ -423,7 +426,7 @@ private:
                 } else {
                     const Node true_label{local_labels.at(block.branch_true)};
                     const Node false_label{local_labels.at(block.branch_false)};
-                    Statement* const true_cond{pool.Create(Identity{}, block.cond)};
+                    Statement* const true_cond{pool.Create(Identity{}, block.cond, &root_stmt)};
                     gotos.push_back(
                         root.insert(ip, *pool.Create(Goto{}, true_cond, true_label, &root_stmt)));
                     gotos.push_back(root.insert(
@@ -433,14 +436,15 @@ private:
             }
             case Flow::EndClass::IndirectBranch:
                 root.insert(ip, *pool.Create(SetIndirectBranchVariable{}, block.branch_reg,
-                                             block.branch_offset));
+                                             block.branch_offset, &root_stmt));
                 for (const Flow::IndirectBranch& indirect : block.indirect_branches) {
                     const Node indirect_label{local_labels.at(indirect.block)};
-                    Statement* cond{pool.Create(IndirectBranchCond{}, indirect.address)};
+                    Statement* cond{
+                        pool.Create(IndirectBranchCond{}, indirect.address, &root_stmt)};
                     Statement* goto_stmt{pool.Create(Goto{}, cond, indirect_label, &root_stmt)};
                     gotos.push_back(root.insert(ip, *goto_stmt));
                 }
-                root.insert(ip, *pool.Create(Unreachable{}));
+                root.insert(ip, *pool.Create(Unreachable{}, &root_stmt));
                 break;
             case Flow::EndClass::Call: {
                 Flow::Function& call{cfg.Functions()[block.function_call]};
@@ -449,16 +453,16 @@ private:
                 break;
             }
             case Flow::EndClass::Exit:
-                root.insert(ip, *pool.Create(Return{}));
+                root.insert(ip, *pool.Create(Return{}, &root_stmt));
                 break;
             case Flow::EndClass::Return: {
-                Statement* const always_cond{pool.Create(Identity{}, block.cond)};
+                Statement* const always_cond{pool.Create(Identity{}, block.cond, &root_stmt)};
                 auto goto_stmt{pool.Create(Goto{}, always_cond, return_label.value(), &root_stmt)};
                 gotos.push_back(root.insert(ip, *goto_stmt));
                 break;
             }
             case Flow::EndClass::Kill:
-                root.insert(ip, *pool.Create(Kill{}));
+                root.insert(ip, *pool.Create(Kill{}, &root_stmt));
                 break;
             }
         }
@@ -474,7 +478,7 @@ private:
         Tree& body{goto_stmt->up->children};
         Tree if_body;
         if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_stmt);
-        Statement* const cond{pool.Create(Not{}, goto_stmt->cond)};
+        Statement* const cond{pool.Create(Not{}, goto_stmt->cond, &root_stmt)};
         Statement* const if_stmt{pool.Create(If{}, cond, std::move(if_body), goto_stmt->up)};
         UpdateTreeUp(if_stmt);
         body.insert(goto_stmt, *if_stmt);
@@ -516,8 +520,8 @@ private:
 
         Tree if_body;
         if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_nested_stmt);
-        Statement* const variable{pool.Create(Variable{}, label_id)};
-        Statement* const neg_var{pool.Create(Not{}, variable)};
+        Statement* const variable{pool.Create(Variable{}, label_id, &root_stmt)};
+        Statement* const neg_var{pool.Create(Not{}, variable, &root_stmt)};
         if (!if_body.empty()) {
             Statement* const if_stmt{pool.Create(If{}, neg_var, std::move(if_body), parent)};
             UpdateTreeUp(if_stmt);
@@ -528,7 +532,8 @@ private:
         switch (label_nested_stmt->type) {
         case StatementType::If:
             // Update nested if condition
-            label_nested_stmt->cond = pool.Create(Or{}, variable, label_nested_stmt->cond);
+            label_nested_stmt->cond =
+                pool.Create(Or{}, variable, label_nested_stmt->cond, &root_stmt);
             break;
         case StatementType::Loop:
             break;
@@ -550,7 +555,7 @@ private:
         Tree loop_body;
         loop_body.splice(loop_body.begin(), body, label_nested_stmt, goto_stmt);
         SanitizeNoBreaks(loop_body);
-        Statement* const variable{pool.Create(Variable{}, label_id)};
+        Statement* const variable{pool.Create(Variable{}, label_id, &root_stmt)};
         Statement* const loop_stmt{pool.Create(Loop{}, variable, std::move(loop_body), parent)};
         UpdateTreeUp(loop_stmt);
         body.insert(goto_stmt, *loop_stmt);
@@ -577,15 +582,15 @@ private:
         Tree if_body;
         if_body.splice(if_body.begin(), body, std::next(goto_stmt), body.end());
         if_body.pop_front();
-        Statement* const cond{pool.Create(Variable{}, label_id)};
-        Statement* const neg_cond{pool.Create(Not{}, cond)};
+        Statement* const cond{pool.Create(Variable{}, label_id, &root_stmt)};
+        Statement* const neg_cond{pool.Create(Not{}, cond, &root_stmt)};
         Statement* const if_stmt{pool.Create(If{}, neg_cond, std::move(if_body), &*parent)};
         UpdateTreeUp(if_stmt);
         body.insert(goto_stmt, *if_stmt);
 
         body.erase(goto_stmt);
 
-        Statement* const new_cond{pool.Create(Variable{}, label_id)};
+        Statement* const new_cond{pool.Create(Variable{}, label_id, &root_stmt)};
         Statement* const new_goto{pool.Create(Goto{}, new_cond, goto_stmt->label, parent->up)};
         Tree& parent_tree{parent->up->children};
         return parent_tree.insert(std::next(parent), *new_goto);
@@ -597,14 +602,14 @@ private:
         const u32 label_id{goto_stmt->label->id};
         Statement* const goto_cond{goto_stmt->cond};
         Statement* const set_goto_var{pool.Create(SetVariable{}, label_id, goto_cond, parent)};
-        Statement* const cond{pool.Create(Variable{}, label_id)};
+        Statement* const cond{pool.Create(Variable{}, label_id, &root_stmt)};
         Statement* const break_stmt{pool.Create(Break{}, cond, parent)};
         body.insert(goto_stmt, *set_goto_var);
         body.insert(goto_stmt, *break_stmt);
         body.erase(goto_stmt);
 
         const Node loop{Tree::s_iterator_to(*goto_stmt->up)};
-        Statement* const new_goto_cond{pool.Create(Variable{}, label_id)};
+        Statement* const new_goto_cond{pool.Create(Variable{}, label_id, &root_stmt)};
         Statement* const new_goto{pool.Create(Goto{}, new_goto_cond, goto_stmt->label, loop->up)};
         Tree& parent_tree{loop->up->children};
         return parent_tree.insert(std::next(loop), *new_goto);
-- 
cgit v1.2.3-70-g09d2