diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index d1660cef23..c68fb546eb 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -1698,7 +1698,7 @@ error_code cellDiscGameGetBootDiscInfo(vm::ptr getP } // Always sets 0 at first dword - *utils::bless>(getParam->titleId + 0) = 0; + write_to_ptr(getParam->titleId, 0); // This is also called by non-disc games, see NPUB90029 static const std::string dir = "/dev_bdvd/PS3_GAME"s; diff --git a/rpcs3/Emu/Cell/Modules/cellGifDec.cpp b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp index ab59d81c7e..09d7edf8d2 100644 --- a/rpcs3/Emu/Cell/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp @@ -296,8 +296,8 @@ error_code cellGifDecReadHeader(vm::ptr mainHandle, vm::ptr>(buffer + 0) != 0x47494638u || - (*utils::bless>(buffer + 4) != 0x6139u && *utils::bless>(buffer + 4) != 0x6137u)) // Error: The first 6 bytes are not a valid GIF signature + if (read_from_ptr>(buffer + 0) != 0x47494638u || + (read_from_ptr>(buffer + 4) != 0x6139u && read_from_ptr>(buffer + 4) != 0x6137u)) // Error: The first 6 bytes are not a valid GIF signature { return CELL_GIFDEC_ERROR_STREAM_FORMAT; // Surprisingly there is no error code related with headerss } diff --git a/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp index 75e25a82b3..d1a5ac002d 100644 --- a/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp @@ -150,8 +150,8 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr>(buffer.get() + 0) != 0xE0FFD8FF || // Error: Not a valid SOI header - *utils::bless(buffer.get() + 6) != "JFIF"_u32) // Error: Not a valid JFIF string + if (read_from_ptr>(buffer.get() + 0) != 0xE0FFD8FF || // Error: Not a valid SOI header + read_from_ptr(buffer.get() + 6) != "JFIF"_u32) // Error: Not a valid JFIF string { return CELL_JPGDEC_ERROR_HEADER; } diff --git a/rpcs3/Emu/Io/Skylander.cpp b/rpcs3/Emu/Io/Skylander.cpp index 57494a5b1c..0e123639a3 100644 --- a/rpcs3/Emu/Io/Skylander.cpp +++ b/rpcs3/Emu/Io/Skylander.cpp @@ -92,10 +92,10 @@ void sky_portal::get_status(u8* reply_buf) } std::memset(reply_buf, 0, 0x20); - reply_buf[0] = 0x53; - *utils::bless>(reply_buf + 1) = status; - reply_buf[5] = interrupt_counter++; - reply_buf[6] = 0x01; + reply_buf[0] = 0x53; + write_to_ptr>(reply_buf, 1, status); + reply_buf[5] = interrupt_counter++; + reply_buf[6] = 0x01; } void sky_portal::query_block(u8 sky_num, u8 block, u8* reply_buf) @@ -159,7 +159,7 @@ u8 sky_portal::load_skylander(u8* buf, fs::file in_file) { std::lock_guard lock(sky_mutex); - u32 sky_serial = *utils::bless>(buf); + u32 sky_serial = read_from_ptr>(buf); u8 found_slot = 0xFF; // mimics spot retaining on the portal diff --git a/rpcs3/Emu/NP/np_handler.cpp b/rpcs3/Emu/NP/np_handler.cpp index 88c5c2c21f..cf9941f08e 100644 --- a/rpcs3/Emu/NP/np_handler.cpp +++ b/rpcs3/Emu/NP/np_handler.cpp @@ -192,9 +192,9 @@ namespace np } ticket_data tdata{}; - const auto* ptr = data() + index; - tdata.id = *reinterpret_cast*>(ptr); - tdata.len = *reinterpret_cast*>(ptr + 2); + const auto* ptr = data() + index; + tdata.id = read_from_ptr>(ptr); + tdata.len = read_from_ptr>(ptr + 2); const auto* data_ptr = data() + index + 4; auto check_size = [&](std::size_t expected) -> bool @@ -219,7 +219,7 @@ namespace np { return std::nullopt; } - tdata.data.data_u32 = *reinterpret_cast*>(data_ptr); + tdata.data.data_u32 = read_from_ptr>(data_ptr); break; case 2: case 7: @@ -227,7 +227,7 @@ namespace np { return std::nullopt; } - tdata.data.data_u64 = *reinterpret_cast*>(data_ptr); + tdata.data.data_u64 = read_from_ptr>(data_ptr); break; case 4: case 8: @@ -277,14 +277,14 @@ namespace np return; } - version = *reinterpret_cast*>(data()); + version = read_from_ptr>(data()); if (version != 0x21010000) { ticket_log.error("Invalid version: 0x%08x", version); return; } - u32 given_size = *reinterpret_cast*>(data() + 4); + u32 given_size = read_from_ptr>(data() + 4); if ((given_size + 8) != size()) { ticket_log.error("Size mismatch (gs: %d vs s: %d)", given_size, size()); @@ -471,7 +471,7 @@ namespace np return; } - local_ip_addr = *reinterpret_cast(host->h_addr_list[0]); + local_ip_addr = read_from_ptr(host->h_addr_list[0]); // Set public address to local discovered address for now, may be updated later from RPCN socket public_ip_addr = local_ip_addr; diff --git a/rpcs3/Emu/NP/np_notifications.cpp b/rpcs3/Emu/NP/np_notifications.cpp index 37ef91daa7..532c1454f9 100644 --- a/rpcs3/Emu/NP/np_notifications.cpp +++ b/rpcs3/Emu/NP/np_notifications.cpp @@ -206,10 +206,10 @@ namespace np return; } - const u64 room_id = reinterpret_cast&>(data[0]); - const u16 member_id = reinterpret_cast&>(data[8]); - const u16 port_p2p = reinterpret_cast&>(data[10]); - const u32 addr_p2p = reinterpret_cast&>(data[12]); + const u64 room_id = read_from_ptr>(data); + const u16 member_id = read_from_ptr>(data, 8); + const u16 port_p2p = read_from_ptr>(data, 10); + const u32 addr_p2p = read_from_ptr>(data, 12); rpcn_log.notice("Received notification to connect to member(%d) of room(%d): %s:%d", member_id, room_id, ip_to_string(addr_p2p), port_p2p); diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index 0126c17022..94a0864a87 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -705,8 +705,7 @@ namespace rsx std::vector marker(range.length() + sizeof(overrun_cookie_value), 0); // Tag end - u32* overrun_test_ptr = utils::bless(marker.data() + range.length()); - *overrun_test_ptr = overrun_cookie_value; + write_to_ptr(marker, range.length(), overrun_cookie_value); u32 removed_count = 0; @@ -717,10 +716,10 @@ namespace rsx while (length >= 8) { - auto& value = *utils::bless(dst_ptr); + const u64 value = read_from_ptr(dst_ptr); const u64 block_mask = ~value; // If the value is not all 1s, set valid to true mask |= block_mask; - value = umax; + write_to_ptr(dst_ptr, umax); dst_ptr += 8; length -= 8; @@ -728,10 +727,10 @@ namespace rsx if (length >= 4) { - auto& value = *utils::bless(dst_ptr); + const u32 value = read_from_ptr(dst_ptr); const u32 block_mask = ~value; mask |= block_mask; - value = umax; + write_to_ptr(dst_ptr, umax); dst_ptr += 4; length -= 4; @@ -739,10 +738,10 @@ namespace rsx if (length >= 2) { - auto& value = *utils::bless(dst_ptr); + const u16 value = read_from_ptr(dst_ptr); const u16 block_mask = ~value; mask |= block_mask; - value = umax; + write_to_ptr(dst_ptr, umax); dst_ptr += 2; length -= 2; @@ -750,10 +749,10 @@ namespace rsx if (length) { - auto& value = *dst_ptr; + const u8 value = *dst_ptr; const u8 block_mask = ~value; mask |= block_mask; - value = umax; + *dst_ptr = umax; } return !!mask; @@ -824,7 +823,7 @@ namespace rsx rsx_log.notice("rsx::surface_cache::check_for_duplicates_fallback analysed %u overlapping sections and removed %u", ::size32(sections), removed_count); // Verify no OOB - ensure(*overrun_test_ptr == overrun_cookie_value); + ensure(read_from_ptr(marker, range.length()) == overrun_cookie_value); } protected: diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index 494c1ab592..0c8da2b983 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -468,14 +468,14 @@ void ds3_pad_handler::get_extended_info(const pad_ensemble& binding) #ifdef _WIN32 // Official Sony Windows DS3 driver seems to do the same modification of this value as the ps3 - pad->m_sensors[0].m_value = *utils::bless>(&ds3dev->padData[41 + DS3_HID_OFFSET]); + pad->m_sensors[0].m_value = read_from_ptr>(ds3dev->padData, 41 + DS3_HID_OFFSET); #else // When getting raw values from the device this adjustement is needed - pad->m_sensors[0].m_value = 512 - (*utils::bless>(&ds3dev->padData[41]) - 512); + pad->m_sensors[0].m_value = 512 - (read_from_ptr>(ds3dev->padData, 41 + DS3_HID_OFFSET) - 512); #endif - pad->m_sensors[1].m_value = *utils::bless>(&ds3dev->padData[45 + DS3_HID_OFFSET]); - pad->m_sensors[2].m_value = *utils::bless>(&ds3dev->padData[43 + DS3_HID_OFFSET]); - pad->m_sensors[3].m_value = *utils::bless>(&ds3dev->padData[47 + DS3_HID_OFFSET]); + pad->m_sensors[1].m_value = read_from_ptr>(ds3dev->padData, 45 + DS3_HID_OFFSET); + pad->m_sensors[2].m_value = read_from_ptr>(ds3dev->padData, 43 + DS3_HID_OFFSET); + pad->m_sensors[3].m_value = read_from_ptr>(ds3dev->padData, 47 + DS3_HID_OFFSET); // Those are formulas used to adjust sensor values in sys_hid code but I couldn't find all the vars. //auto polish_value = [](s32 value, s32 dword_0x0, s32 dword_0x4, s32 dword_0x8, s32 dword_0xC, s32 dword_0x18, s32 dword_0x1C) -> u16 diff --git a/rpcs3/util/types.hpp b/rpcs3/util/types.hpp index eb8cbdac10..2edc9fd414 100644 --- a/rpcs3/util/types.hpp +++ b/rpcs3/util/types.hpp @@ -1184,6 +1184,40 @@ namespace stx }; } +// Read object of type T from raw pointer, array, string, vector, or any contiguous container +template +constexpr T read_from_ptr(U&& array, usz pos = 0) +{ + // TODO: ensure array element types are trivial + static_assert(sizeof(T) % sizeof(array[0]) == 0); + std::decay_t buf[sizeof(T) / sizeof(array[0])]; + if (!std::is_constant_evaluated()) + std::memcpy(+buf, &array[pos], sizeof(buf)); + else + for (usz i = 0; i < pos; buf[i] = array[pos + i], i++); + return std::bit_cast(buf); +} + +template +constexpr void write_to_ptr(U&& array, usz pos, const T& value) +{ + static_assert(sizeof(T) % sizeof(array[0]) == 0); + if (!std::is_constant_evaluated()) + std::memcpy(&array[pos], &value, sizeof(value)); + else + ensure(!"Unimplemented"); +} + +template +constexpr void write_to_ptr(U&& array, const T& value) +{ + static_assert(sizeof(T) % sizeof(array[0]) == 0); + if (!std::is_constant_evaluated()) + std::memcpy(&array[0], &value, sizeof(value)); + else + ensure(!"Unimplemented"); +} + namespace utils { struct serial;