From 91d5ba444a62945a5c15eafaad20d018d3f1f7da Mon Sep 17 00:00:00 2001 From: Triang3l Date: Sat, 14 Nov 2020 23:22:24 +0300 Subject: [PATCH] [Base/Kernel] Add and use truncating null-terminating string copying --- src/xenia/base/string_util.h | 38 +++++++++++++++++++++++++++++ src/xenia/kernel/xam/xam_content.cc | 4 ++- src/xenia/kernel/xam/xam_info.cc | 19 ++++++++------- src/xenia/kernel/xam/xam_ui.cc | 5 ++-- src/xenia/kernel/xam/xam_user.cc | 11 +++++---- 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/xenia/base/string_util.h b/src/xenia/base/string_util.h index f1499bb5f..adb2012af 100644 --- a/src/xenia/base/string_util.h +++ b/src/xenia/base/string_util.h @@ -10,11 +10,15 @@ #ifndef XENIA_BASE_STRING_UTIL_H_ #define XENIA_BASE_STRING_UTIL_H_ +#include #include +#include +#include #include #include "third_party/fmt/include/fmt/format.h" #include "xenia/base/assert.h" +#include "xenia/base/memory.h" #include "xenia/base/platform.h" #include "xenia/base/string.h" #include "xenia/base/vec128.h" @@ -30,6 +34,40 @@ namespace xe { namespace string_util { +inline size_t copy_truncating(char* dest, const std::string_view source, + size_t dest_buffer_count) { + if (!dest_buffer_count) { + return 0; + } + size_t chars_copied = std::min(source.size(), dest_buffer_count - size_t(1)); + std::memcpy(dest, source.data(), chars_copied); + dest[chars_copied] = '\0'; + return chars_copied; +} + +inline size_t copy_truncating(char16_t* dest, const std::u16string_view source, + size_t dest_buffer_count) { + if (!dest_buffer_count) { + return 0; + } + size_t chars_copied = std::min(source.size(), dest_buffer_count - size_t(1)); + std::memcpy(dest, source.data(), chars_copied * sizeof(char16_t)); + dest[chars_copied] = u'\0'; + return chars_copied; +} + +inline size_t copy_and_swap_truncating(char16_t* dest, + const std::u16string_view source, + size_t dest_buffer_count) { + if (!dest_buffer_count) { + return 0; + } + size_t chars_copied = std::min(source.size(), dest_buffer_count - size_t(1)); + xe::copy_and_swap(dest, source.data(), chars_copied); + dest[chars_copied] = u'\0'; + return chars_copied; +} + inline std::string to_hex_string(uint32_t value) { return fmt::format("{:08X}", value); } diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index 7dd874b7b..d47dd0575 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -8,6 +8,7 @@ */ #include "xenia/base/logging.h" +#include "xenia/base/math.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xam/xam_private.h" @@ -223,7 +224,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type, xe::store_and_swap(&dev->device_type, dummy_device_info_.device_type); xe::store_and_swap(&dev->total_bytes, dummy_device_info_.total_bytes); xe::store_and_swap(&dev->free_bytes, dummy_device_info_.free_bytes); - xe::copy_and_swap(dev->name, dummy_device_info_.name, 28); + xe::copy_and_swap(dev->name, dummy_device_info_.name, + xe::countof(dev->name)); } *handle_out = e->handle(); diff --git a/src/xenia/kernel/xam/xam_info.cc b/src/xenia/kernel/xam/xam_info.cc index 0589e83a1..a08ab60aa 100644 --- a/src/xenia/kernel/xam/xam_info.cc +++ b/src/xenia/kernel/xam/xam_info.cc @@ -8,6 +8,7 @@ */ #include "xenia/base/logging.h" +#include "xenia/base/string_util.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/user_module.h" #include "xenia/kernel/util/shim_utils.h" @@ -74,15 +75,15 @@ static SYSTEMTIME xeGetLocalSystemTime(uint64_t filetime) { void XamFormatDateString(dword_t unk, qword_t filetime, lpvoid_t output_buffer, dword_t output_count) { - std::memset(output_buffer, 0, output_count * 2); + std::memset(output_buffer, 0, output_count * sizeof(char16_t)); // TODO: implement this for other platforms #if XE_PLATFORM_WIN32 auto st = xeGetLocalSystemTime(filetime); // TODO: format this depending on users locale? auto str = fmt::format(u"{:02d}/{:02d}/{}", st.wMonth, st.wDay, st.wYear); - auto copy_length = std::min(size_t(output_count), str.size()) * 2; - xe::copy_and_swap(output_buffer.as(), str.c_str(), copy_length); + xe::string_util::copy_and_swap_truncating(output_buffer.as(), str, + output_count); #else assert_always(); #endif @@ -91,15 +92,15 @@ DECLARE_XAM_EXPORT1(XamFormatDateString, kNone, kImplemented); void XamFormatTimeString(dword_t unk, qword_t filetime, lpvoid_t output_buffer, dword_t output_count) { - std::memset(output_buffer, 0, output_count * 2); + std::memset(output_buffer, 0, output_count * sizeof(char16_t)); // TODO: implement this for other platforms #if XE_PLATFORM_WIN32 auto st = xeGetLocalSystemTime(filetime); // TODO: format this depending on users locale? auto str = fmt::format(u"{:02d}:{:02d}", st.wHour, st.wMinute); - auto copy_count = std::min(size_t(output_count), str.size()); - xe::copy_and_swap(output_buffer.as(), str.c_str(), copy_count); + xe::string_util::copy_and_swap_truncating(output_buffer.as(), str, + output_count); #else assert_always(); #endif @@ -113,7 +114,7 @@ dword_result_t keXamBuildResourceLocator(uint64_t module, uint32_t buffer_count) { std::u16string path; if (!module) { - path = fmt::format(u"file://media:/{0}.xzp#{0}", container, resource); + path = fmt::format(u"file://media:/{}.xzp#{}", container, resource); XELOGD( "XamBuildResourceLocator({0}) returning locator to local file {0}.xzp", xe::to_utf8(container)); @@ -121,8 +122,8 @@ dword_result_t keXamBuildResourceLocator(uint64_t module, path = fmt::format(u"section://{:X},{}#{}", (uint32_t)module, container, resource); } - auto copy_count = std::min(size_t(buffer_count), path.size()); - xe::copy_and_swap(buffer_ptr.as(), path.c_str(), copy_count); + xe::string_util::copy_and_swap_truncating(buffer_ptr.as(), path, + buffer_count); return 0; } diff --git a/src/xenia/kernel/xam/xam_ui.cc b/src/xenia/kernel/xam/xam_ui.cc index 4e5f077aa..4f1348a69 100644 --- a/src/xenia/kernel/xam/xam_ui.cc +++ b/src/xenia/kernel/xam/xam_ui.cc @@ -9,6 +9,7 @@ #include "third_party/imgui/imgui.h" #include "xenia/base/logging.h" +#include "xenia/base/string_util.h" #include "xenia/emulator.h" #include "xenia/kernel/kernel_flags.h" #include "xenia/kernel/kernel_state.h" @@ -188,8 +189,8 @@ class KeyboardInputDialog : public xe::ui::ImGuiDialog { *out_text_ = default_text; } text_buffer_.resize(max_length); - std::strncpy(text_buffer_.data(), default_text_.c_str(), - std::min(text_buffer_.size() - 1, default_text_.size())); + xe::string_util::copy_truncating(text_buffer_.data(), default_text_, + text_buffer_.size()); } void OnDraw(ImGuiIO& io) override { diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 02dda8d2e..9cc2f1dce 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -10,6 +10,8 @@ #include #include "xenia/base/logging.h" +#include "xenia/base/math.h" +#include "xenia/base/string_util.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xam/xam_private.h" @@ -91,7 +93,8 @@ X_HRESULT_result_t XamUserGetSigninInfo(dword_t user_index, dword_t flags, const auto& user_profile = kernel_state()->user_profile(); info->xuid = user_profile->xuid(); info->signin_state = user_profile->signin_state(); - std::strncpy(info->name, user_profile->name().data(), 15); + xe::string_util::copy_truncating(info->name, user_profile->name(), + xe::countof(info->name)); return X_E_SUCCESS; } DECLARE_XAM_EXPORT1(XamUserGetSigninInfo, kUserProfiles, kImplemented); @@ -110,10 +113,8 @@ dword_result_t XamUserGetName(dword_t user_index, lpstring_t buffer, const auto& user_name = user_profile->name(); // Real XAM will only copy a maximum of 15 characters out. - size_t copy_length = std::min( - {size_t(15), user_name.size(), static_cast(buffer_len) - 1}); - std::memcpy(buffer, user_name.data(), copy_length); - buffer[copy_length] = '\0'; + xe::string_util::copy_truncating(buffer, user_name, + std::min(buffer_len.value(), uint32_t(15))); return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamUserGetName, kUserProfiles, kImplemented);