From 5bcbc8fcef7f0888bacd16c34295666d407a19b6 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 8 Dec 2021 17:10:39 -0800 Subject: [PATCH] CodeViewWidget: Fix undefined behavior when centered around address 0 --- .../DolphinQt/Debugger/CodeViewWidget.cpp | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp index a2b113f881..77bb8c8bd3 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp @@ -20,6 +20,7 @@ #include #include +#include "Common/Assert.h" #include "Common/GekkoDisassembler.h" #include "Common/StringUtil.h" #include "Core/Core.h" @@ -393,26 +394,27 @@ void CodeViewWidget::CalculateBranchIndentation() // build a 2D lookup table representing the columns and rows the arrow could be drawn in // and try to place all branch arrows in it as far left as possible std::vector arrow_space_used(columns * rows, false); - const auto index = [&](u32 column, u32 row) { return column * rows + row; }; - const u32 first_visible_addr = AddressForRow(0); - const u32 last_visible_addr = AddressForRow(static_cast(rows - 1)); - for (CodeViewBranch& branch : m_branches) - { + const auto index = [&](u32 column, u32 row) { + ASSERT(row <= rows); + ASSERT(column <= columns); + return column * rows + row; + }; + + const auto add_branch_arrow = [&](CodeViewBranch& branch, u32 first_addr, u32 first_row, + u32 last_addr) { const u32 arrow_src_addr = branch.src_addr; const u32 arrow_dst_addr = branch.is_link ? branch.src_addr : branch.dst_addr; - const u32 arrow_addr_lower = std::min(arrow_src_addr, arrow_dst_addr); - const u32 arrow_addr_higher = std::max(arrow_src_addr, arrow_dst_addr); - const bool is_visible = - last_visible_addr >= arrow_addr_lower || first_visible_addr <= arrow_addr_higher; - if (!is_visible) - continue; + const auto [arrow_addr_lower, arrow_addr_higher] = std::minmax(arrow_src_addr, arrow_dst_addr); - const u32 arrow_first_visible_addr = - std::clamp(arrow_addr_lower, first_visible_addr, last_visible_addr); - const u32 arrow_last_visible_addr = - std::clamp(arrow_addr_higher, first_visible_addr, last_visible_addr); - const u32 arrow_first_visible_row = (arrow_first_visible_addr - first_visible_addr) / 4; - const u32 arrow_last_visible_row = (arrow_last_visible_addr - first_visible_addr) / 4; + const bool is_visible = + std::max(arrow_addr_lower, first_addr) <= std::min(arrow_addr_higher, last_addr); + if (!is_visible) + return; + + const u32 arrow_first_visible_addr = std::clamp(arrow_addr_lower, first_addr, last_addr); + const u32 arrow_last_visible_addr = std::clamp(arrow_addr_higher, first_addr, last_addr); + const u32 arrow_first_visible_row = (arrow_first_visible_addr - first_addr) / 4 + first_row; + const u32 arrow_last_visible_row = (arrow_last_visible_addr - first_addr) / 4 + first_row; const auto free_column = [&]() -> std::optional { for (u32 column = 0; column < columns; ++column) @@ -432,11 +434,43 @@ void CodeViewWidget::CalculateBranchIndentation() }(); if (!free_column) - continue; + return; branch.indentation = *free_column; for (u32 row = arrow_first_visible_row; row <= arrow_last_visible_row; ++row) arrow_space_used[index(*free_column, row)] = true; + }; + + const u32 first_visible_addr = AddressForRow(0); + const u32 last_visible_addr = AddressForRow(static_cast(rows - 1)); + + if (first_visible_addr <= last_visible_addr) + { + for (CodeViewBranch& branch : m_branches) + add_branch_arrow(branch, first_visible_addr, 0, last_visible_addr); + } + else + { + // Scrolling defaults to being centered around address 00000000, which means addresses before + // the start are visible (e.g. ffffffa8 - 00000050). We need to do this in two parts, one for + // first_visible_addr to fffffffc, and the second for 00000000 to last_visible_addr. + // That means we need to find the row corresponding to 00000000. + int addr_zero_row = -1; + for (int row = 0; row < rows; row++) + { + if (AddressForRow(row) == 0) + { + addr_zero_row = row; + break; + } + } + ASSERT(addr_zero_row != -1); + + for (CodeViewBranch& branch : m_branches) + { + add_branch_arrow(branch, first_visible_addr, 0, 0xfffffffc); + add_branch_arrow(branch, 0x00000000, addr_zero_row, last_visible_addr); + } } }