mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-06 09:39:55 +00:00
Add savestate data validity asserts
This commit is contained in:
parent
475191cf7f
commit
f696107c90
@ -2641,9 +2641,10 @@ void thread_base::exec()
|
|||||||
|
|
||||||
sig_log.fatal("Thread terminated due to fatal error: %s", reason);
|
sig_log.fatal("Thread terminated due to fatal error: %s", reason);
|
||||||
|
|
||||||
|
logs::listener::sync_all();
|
||||||
|
|
||||||
if (IsDebuggerPresent())
|
if (IsDebuggerPresent())
|
||||||
{
|
{
|
||||||
logs::listener::sync_all();
|
|
||||||
utils::trap();
|
utils::trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ constexpr auto* g_fxo = &g_fixed_typemap;
|
|||||||
|
|
||||||
enum class thread_state : u32;
|
enum class thread_state : u32;
|
||||||
|
|
||||||
|
extern u16 serial_breathe_and_tag(utils::serial& ar, std::string_view name, bool tag_bit);
|
||||||
|
|
||||||
// Helper namespace
|
// Helper namespace
|
||||||
namespace id_manager
|
namespace id_manager
|
||||||
{
|
{
|
||||||
@ -270,16 +272,22 @@ namespace id_manager
|
|||||||
{
|
{
|
||||||
vec.resize(T::id_count);
|
vec.resize(T::id_count);
|
||||||
|
|
||||||
u32 i = ar.pop<u32>();
|
usz highest = 0;
|
||||||
|
|
||||||
ensure(i <= T::id_count);
|
while (true)
|
||||||
|
|
||||||
while (--i != umax)
|
|
||||||
{
|
{
|
||||||
// ID, type hash
|
const u16 tag = serial_breathe_and_tag(ar, g_fxo->get_name<id_map<T>>(), false);
|
||||||
const u32 id = ar;
|
|
||||||
|
|
||||||
const u128 type_init_pos = u128{u32{ar}} << 64 | std::bit_cast<u64>(T::savestate_init_pos);
|
if (tag >> 15)
|
||||||
|
{
|
||||||
|
// End
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID, type hash
|
||||||
|
const u32 id = ar.pop<u32>();
|
||||||
|
|
||||||
|
const u128 type_init_pos = u128{ar.pop<u32>()} << 64 | std::bit_cast<u64>(T::savestate_init_pos);
|
||||||
const typeinfo* info = nullptr;
|
const typeinfo* info = nullptr;
|
||||||
|
|
||||||
// Search load functions for the one of this type (see make_typeinfo() for explenation about key composition reasoning)
|
// Search load functions for the one of this type (see make_typeinfo() for explenation about key composition reasoning)
|
||||||
@ -298,22 +306,21 @@ namespace id_manager
|
|||||||
// Simulate construction semantics (idm::last_id() value)
|
// Simulate construction semantics (idm::last_id() value)
|
||||||
g_id = id;
|
g_id = id;
|
||||||
|
|
||||||
auto& obj = vec[get_index(id, info->base, info->step, info->count, info->invl_range)];
|
const usz object_index = get_index(id, info->base, info->step, info->count, info->invl_range);
|
||||||
|
auto& obj = ::at32(vec, object_index);
|
||||||
ensure(!obj.second);
|
ensure(!obj.second);
|
||||||
|
|
||||||
|
highest = std::max<usz>(highest, object_index + 1);
|
||||||
|
|
||||||
obj.first = id_key(id, static_cast<u32>(static_cast<u64>(type_init_pos >> 64)));
|
obj.first = id_key(id, static_cast<u32>(static_cast<u64>(type_init_pos >> 64)));
|
||||||
obj.second = info->load(ar);
|
obj.second = info->load(ar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec.resize(highest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void save(utils::serial& ar) requires IdmSavable<T>
|
void save(utils::serial& ar) requires IdmSavable<T>
|
||||||
{
|
{
|
||||||
u32 obj_count = 0;
|
|
||||||
usz obj_count_offs = ar.pos;
|
|
||||||
|
|
||||||
// To be patched at the end of the function
|
|
||||||
ar(obj_count);
|
|
||||||
|
|
||||||
for (const auto& p : vec)
|
for (const auto& p : vec)
|
||||||
{
|
{
|
||||||
if (!p.second) continue;
|
if (!p.second) continue;
|
||||||
@ -333,20 +340,24 @@ namespace id_manager
|
|||||||
// Save each object with needed information
|
// Save each object with needed information
|
||||||
if (info && info->savable(p.second.get()))
|
if (info && info->savable(p.second.get()))
|
||||||
{
|
{
|
||||||
|
// Create a tag for each object
|
||||||
|
serial_breathe_and_tag(ar, g_fxo->get_name<id_map<T>>(), false);
|
||||||
|
|
||||||
ar(p.first.value(), p.first.type());
|
ar(p.first.value(), p.first.type());
|
||||||
info->save(ar, p.second.get());
|
info->save(ar, p.second.get());
|
||||||
obj_count++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch object count
|
// End sequence with tag bit set
|
||||||
ar.patch_raw_data(obj_count_offs, &obj_count, sizeof(obj_count));
|
serial_breathe_and_tag(ar, g_fxo->get_name<id_map<T>>(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
id_map& operator=(thread_state state) noexcept requires (std::is_assignable_v<T&, thread_state>)
|
id_map& operator=(thread_state state) noexcept requires (std::is_assignable_v<T&, thread_state>)
|
||||||
{
|
{
|
||||||
if (private_copy.empty())
|
if (private_copy.size() != vec.size())
|
||||||
{
|
{
|
||||||
|
private_copy.clear();
|
||||||
|
|
||||||
reader_lock lock(g_mutex);
|
reader_lock lock(g_mutex);
|
||||||
|
|
||||||
// Save all entries
|
// Save all entries
|
||||||
|
@ -296,14 +296,37 @@ bool load_and_check_reserved(utils::serial& ar, usz size)
|
|||||||
|
|
||||||
namespace stx
|
namespace stx
|
||||||
{
|
{
|
||||||
extern void serial_breathe(utils::serial& ar)
|
extern u16 serial_breathe_and_tag(utils::serial& ar, std::string_view name, bool tag_bit)
|
||||||
{
|
{
|
||||||
|
thread_local std::string_view s_tls_object_name = "none";
|
||||||
|
|
||||||
|
constexpr u16 data_mask = 0x7fff;
|
||||||
|
|
||||||
|
if (ar.m_file_handler && ar.m_file_handler->is_null())
|
||||||
|
{
|
||||||
|
return (tag_bit ? data_mask + 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 tag = static_cast<u16>((static_cast<u16>(ar.pos / 2) & data_mask) | (tag_bit ? data_mask + 1 : 0));
|
||||||
|
u16 saved = tag;
|
||||||
|
ar(saved);
|
||||||
|
|
||||||
|
sys_log.trace("serial_breathe_and_tag(): %s, object: '%s', next-object: '%s', expected/tag: 0x%x == 0x%x", ar, s_tls_object_name, name, tag, saved);
|
||||||
|
|
||||||
|
if ((saved ^ tag) & data_mask)
|
||||||
|
{
|
||||||
|
ensure(!ar.is_writing());
|
||||||
|
fmt::throw_exception("serial_breathe_and_tag(): %s, object: '%s', next-object: '%s', expected/tag: 0x%x != 0x%x,", ar, s_tls_object_name, name, tag, saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_tls_object_name = name;
|
||||||
ar.breathe();
|
ar.breathe();
|
||||||
|
return saved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSVC bug workaround, see above similar case
|
// MSVC bug workaround, see above similar case
|
||||||
extern void serial_breathe(utils::serial& ar)
|
extern u16 serial_breathe_and_tag(utils::serial& ar, std::string_view name, bool tag_bit)
|
||||||
{
|
{
|
||||||
::stx::serial_breathe(ar);
|
return ::stx::serial_breathe_and_tag(ar, name, tag_bit);
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,17 @@ enum class thread_state : u32;
|
|||||||
|
|
||||||
extern thread_local std::string_view g_tls_serialize_name;
|
extern thread_local std::string_view g_tls_serialize_name;
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
struct serial;
|
||||||
|
}
|
||||||
|
|
||||||
namespace stx
|
namespace stx
|
||||||
{
|
{
|
||||||
struct launch_retainer{};
|
struct launch_retainer{};
|
||||||
|
|
||||||
|
extern u16 serial_breathe_and_tag(utils::serial& ar, std::string_view name, bool tag_bit);
|
||||||
|
|
||||||
// Simplified typemap with exactly one object of each used type, non-moveable. Initialized on init(). Destroyed on clear().
|
// Simplified typemap with exactly one object of each used type, non-moveable. Initialized on init(). Destroyed on clear().
|
||||||
template <typename Tag /*Tag should be unique*/, u32 Size = 0, u32 Align = (Size ? 64 : __STDCPP_DEFAULT_NEW_ALIGNMENT__)>
|
template <typename Tag /*Tag should be unique*/, u32 Size = 0, u32 Align = (Size ? 64 : __STDCPP_DEFAULT_NEW_ALIGNMENT__)>
|
||||||
class alignas(Align) manual_typemap
|
class alignas(Align) manual_typemap
|
||||||
@ -67,6 +74,7 @@ namespace stx
|
|||||||
void(*thread_op)(void* ptr, thread_state) noexcept = nullptr;
|
void(*thread_op)(void* ptr, thread_state) noexcept = nullptr;
|
||||||
void(*save)(void* ptr, utils::serial&) noexcept = nullptr;
|
void(*save)(void* ptr, utils::serial&) noexcept = nullptr;
|
||||||
void(*destroy)(void* ptr) noexcept = nullptr;
|
void(*destroy)(void* ptr) noexcept = nullptr;
|
||||||
|
bool is_trivial_and_nonsavable = false;
|
||||||
std::string_view name;
|
std::string_view name;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -143,7 +151,7 @@ namespace stx
|
|||||||
{
|
{
|
||||||
static_assert(!std::is_copy_assignable_v<T> && !std::is_copy_constructible_v<T>, "Please make sure the object cannot be accidentally copied.");
|
static_assert(!std::is_copy_assignable_v<T> && !std::is_copy_constructible_v<T>, "Please make sure the object cannot be accidentally copied.");
|
||||||
|
|
||||||
typeinfo r;
|
typeinfo r{};
|
||||||
r.create = &call_ctor<T>;
|
r.create = &call_ctor<T>;
|
||||||
r.destroy = &call_dtor<T>;
|
r.destroy = &call_dtor<T>;
|
||||||
|
|
||||||
@ -156,6 +164,9 @@ namespace stx
|
|||||||
{
|
{
|
||||||
r.save = &call_save<T>;
|
r.save = &call_save<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.is_trivial_and_nonsavable = std::is_trivially_default_constructible_v<T> && !r.save;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
constexpr std::string_view name = parse_type(__FUNCSIG__);
|
constexpr std::string_view name = parse_type(__FUNCSIG__);
|
||||||
#else
|
#else
|
||||||
@ -237,7 +248,8 @@ namespace stx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use unique_ptr to reduce header dependencies in this commonly used header
|
// Use unique_ptr to reduce header dependencies in this commonly used header
|
||||||
const auto order = std::make_unique<std::pair<double, const type_info<typeinfo>*>[]>(stx::typelist<typeinfo>().count());
|
const usz type_count = stx::typelist<typeinfo>().count();
|
||||||
|
const auto order = std::make_unique<std::pair<double, const type_info<typeinfo>*>[]>(type_count);
|
||||||
|
|
||||||
usz pos = 0;
|
usz pos = 0;
|
||||||
for (const auto& type : stx::typelist<typeinfo>())
|
for (const auto& type : stx::typelist<typeinfo>())
|
||||||
@ -245,14 +257,19 @@ namespace stx
|
|||||||
order[pos++] = {type.init_pos(), std::addressof(type)};
|
order[pos++] = {type.init_pos(), std::addressof(type)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stable_sort(order.get(), order.get() + stx::typelist<typeinfo>().count(), [](auto a, auto b)
|
std::stable_sort(order.get(), order.get() + type_count, [](auto& a, auto& b)
|
||||||
{
|
{
|
||||||
|
if (a.second->is_trivial_and_nonsavable && !b.second->is_trivial_and_nonsavable)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return a.first < b.first;
|
return a.first < b.first;
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto info_before = m_info;
|
const auto info_before = m_info;
|
||||||
|
|
||||||
for (pos = 0; pos < stx::typelist<typeinfo>().count(); pos++)
|
for (pos = 0; pos < type_count; pos++)
|
||||||
{
|
{
|
||||||
const auto& type = *order[pos].second;
|
const auto& type = *order[pos].second;
|
||||||
|
|
||||||
@ -271,10 +288,9 @@ namespace stx
|
|||||||
*m_info++ = &type;
|
*m_info++ = &type;
|
||||||
m_init[id] = true;
|
m_init[id] = true;
|
||||||
|
|
||||||
if (ar)
|
if (ar && type.save)
|
||||||
{
|
{
|
||||||
extern void serial_breathe(utils::serial& ar);
|
serial_breathe_and_tag(*ar, type.name, false);
|
||||||
serial_breathe(*ar);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,10 +388,13 @@ namespace stx
|
|||||||
// Save data in forward order
|
// Save data in forward order
|
||||||
for (u32 i = _max; i; i--)
|
for (u32 i = _max; i; i--)
|
||||||
{
|
{
|
||||||
if (auto save = (*std::prev(m_info, i))->save)
|
const auto info = (*std::prev(m_info, i));
|
||||||
|
|
||||||
|
if (auto save = info->save)
|
||||||
{
|
{
|
||||||
save(*std::prev(m_order, i), ar);
|
save(*std::prev(m_order, i), ar);
|
||||||
ar.breathe();
|
|
||||||
|
serial_breathe_and_tag(ar, info->name, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,6 +433,8 @@ namespace stx
|
|||||||
|
|
||||||
As* obj = nullptr;
|
As* obj = nullptr;
|
||||||
|
|
||||||
|
const auto type_info = &stx::typedata<typeinfo, std::decay_t<T>, std::decay_t<As>>();
|
||||||
|
|
||||||
g_tls_serialize_name = get_name<T, As>();
|
g_tls_serialize_name = get_name<T, As>();
|
||||||
|
|
||||||
if constexpr (Size != 0)
|
if constexpr (Size != 0)
|
||||||
@ -425,10 +446,16 @@ namespace stx
|
|||||||
obj = new (m_list + stx::typeoffset<typeinfo, std::decay_t<T>>()) std::decay_t<As>(std::forward<Args>(args)...);
|
obj = new (m_list + stx::typeoffset<typeinfo, std::decay_t<T>>()) std::decay_t<As>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr ((std::is_same_v<std::remove_cvref_t<Args>, utils::serial> || ...))
|
||||||
|
{
|
||||||
|
ensure(type_info->save);
|
||||||
|
serial_breathe_and_tag(std::get<0>(std::tie(args...)), get_name<T, As>(), false);
|
||||||
|
}
|
||||||
|
|
||||||
g_tls_serialize_name = {};
|
g_tls_serialize_name = {};
|
||||||
|
|
||||||
*m_order++ = obj;
|
*m_order++ = obj;
|
||||||
*m_info++ = &stx::typedata<typeinfo, std::decay_t<T>, std::decay_t<As>>();
|
*m_info++ = type_info;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user