From 3cfa233b63dfcd734be2dd0ae4bd0d3e98109df6 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 13 Apr 2024 18:29:52 +0200 Subject: VideoCommon: Use GetSpanForAddress safely in texture decoding Now only VertexLoader remains... But that one might be tricky. --- Source/Core/Common/CMakeLists.txt | 1 + Source/Core/Common/SpanUtils.h | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 Source/Core/Common/SpanUtils.h (limited to 'Source/Core/Common') diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 7b81cd2c6d..af48ba7e13 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -126,6 +126,7 @@ add_library(common SmallVector.h SocketContext.cpp SocketContext.h + SpanUtils.h SPSCQueue.h StringLiteral.h StringUtil.cpp diff --git a/Source/Core/Common/SpanUtils.h b/Source/Core/Common/SpanUtils.h new file mode 100644 index 0000000000..d09193b314 --- /dev/null +++ b/Source/Core/Common/SpanUtils.h @@ -0,0 +1,41 @@ +// Copyright 2024 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include + +#include "Common/CommonTypes.h" + +namespace Common +{ + +// Like std::span::subspan, except undefined behavior is replaced with returning a 0-length span. +template +[[nodiscard]] constexpr std::span SafeSubspan(std::span span, size_t offset, + size_t count = std::dynamic_extent) +{ + if (count == std::dynamic_extent || offset > span.size()) + return span.subspan(std::min(offset, span.size())); + else + return span.subspan(offset, std::min(count, span.size() - offset)); +} + +// Default-constructs an object of type T, then copies data into it from the specified offset in +// the specified span. Out-of-bounds reads will be skipped, meaning that specifying a too large +// offset results in the object partially or entirely remaining default constructed. +template +[[nodiscard]] T SafeSpanRead(std::span span, size_t offset) +{ + static_assert(std::is_trivially_copyable()); + + const std::span subspan = SafeSubspan(span, offset); + T result{}; + std::memcpy(&result, subspan.data(), std::min(subspan.size(), sizeof(result))); + return result; +} + +} // namespace Common -- cgit v1.2.3