From 7845434270524d4c777a6711d2e17ac89eeeeb89 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Mon, 14 Dec 2020 00:14:37 +0100 Subject: Codechange: Don't use cpp_offsetof in the save/load code. Many of the member variables that are used in save/load are inside types that are not standard layout types. Using pointer arithmetics to determine addresses of members inside types that are not standard layout is generally undefined behaviour. If we'd use C++17, it is conditionally supported, which means each compiler may or may not support it. And even then using it for individual array elements is syntactically not supported the the standard offsetof function. Unfortunately, the trickery employed for saving linkgraph settings causes quite some clutter in the settings ini files. --- src/saveload/linkgraph_sl.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'src/saveload/linkgraph_sl.cpp') diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index aa3a2ff4b..a597edfc4 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -53,11 +53,23 @@ const SaveLoad *GetLinkGraphJobDesc() static std::vector saveloads; static const char *prefix = "linkgraph."; + static const SaveLoad job_desc[] = { + SLE_VAR(LinkGraphJob, join_date, SLE_INT32), + SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16), + SLE_END() + }; + + /* The member offset arithmetic below is only valid if the types in question + * are standard layout types. Otherwise, it would be undefined behaviour. */ + static_assert(std::is_standard_layout::value, "LinkGraphSettings needs to be a standard layout type"); + + /* We store the offset of each member of the #LinkGraphSettings in the + * extra data of the saveload struct. Use it together with the address + * of the settings struct inside the job to find the final memory address. */ + static SaveLoadAddrProc * const proc = [](void *b, size_t extra) -> void * { return const_cast(static_cast(reinterpret_cast(std::addressof(static_cast(b)->settings)) + extra)); }; + /* Build the SaveLoad array on first call and don't touch it later on */ if (saveloads.size() == 0) { - size_t offset_gamesettings = cpp_offsetof(GameSettings, linkgraph); - size_t offset_component = cpp_offsetof(LinkGraphJob, settings); - size_t prefixlen = strlen(prefix); int setting = 0; @@ -65,20 +77,12 @@ const SaveLoad *GetLinkGraphJobDesc() while (desc->save.cmd != SL_END) { if (desc->desc.name != nullptr && strncmp(desc->desc.name, prefix, prefixlen) == 0) { SaveLoad sl = desc->save; - char *&address = reinterpret_cast(sl.address); - address -= offset_gamesettings; - address += offset_component; + sl.address_proc = proc; saveloads.push_back(sl); } desc = GetSettingDescription(++setting); } - const SaveLoad job_desc[] = { - SLE_VAR(LinkGraphJob, join_date, SLE_INT32), - SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16), - SLE_END() - }; - int i = 0; do { saveloads.push_back(job_desc[i++]); -- cgit v1.2.3-54-g00ecf