mirror of
https://github.com/geode-sdk/geode.git
synced 2025-02-18 09:10:17 -05:00
fix macos crash on opening (typeinfo_cast nullptr)
This commit is contained in:
parent
5dfef0c352
commit
d024dbb858
5 changed files with 133 additions and 229 deletions
|
@ -1156,9 +1156,9 @@ class EditorPauseLayer : CCBlockLayer, FLAlertLayerProtocol {
|
||||||
void doResetUnused() = win 0x165070;
|
void doResetUnused() = win 0x165070;
|
||||||
|
|
||||||
bool m_saved;
|
bool m_saved;
|
||||||
PAD = mac 0x8, win 0x4;
|
PAD = mac 0x4, win 0x4;
|
||||||
CCMenuItemSpriteExtra* m_button0;
|
CCMenuItemSpriteExtra* m_guidelinesOffButton;
|
||||||
CCMenuItemSpriteExtra* m_button1;
|
CCMenuItemSpriteExtra* m_guidelinesOnButton;
|
||||||
LevelEditorLayer* m_editorLayer;
|
LevelEditorLayer* m_editorLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
127
loader/include/Geode/platform/ItaniumCast.hpp
Normal file
127
loader/include/Geode/platform/ItaniumCast.hpp
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace geode::cast {
|
||||||
|
using uinthalf_t = uint32_t;
|
||||||
|
using inthalf_t = int32_t;
|
||||||
|
|
||||||
|
struct DummyClass {
|
||||||
|
virtual ~DummyClass() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DummySingleClass : DummyClass {};
|
||||||
|
|
||||||
|
struct DummyClass2 {};
|
||||||
|
|
||||||
|
struct DummyMultipleClass : DummySingleClass, DummyClass2 {};
|
||||||
|
|
||||||
|
struct ClassTypeinfoType {
|
||||||
|
void** m_typeinfoVtable;
|
||||||
|
char const* m_typeinfoName;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SingleClassTypeinfoType : ClassTypeinfoType {
|
||||||
|
ClassTypeinfoType* m_baseClassTypeinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
struct MultipleClassSingleEntryType {
|
||||||
|
ClassTypeinfoType* m_baseClassTypeinfo;
|
||||||
|
uint8_t m_visibilityFlag;
|
||||||
|
inthalf_t m_offset;
|
||||||
|
uint8_t m_padding[sizeof(inthalf_t) - 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct MultipleClassTypeinfoType : ClassTypeinfoType {
|
||||||
|
uint32_t m_flags;
|
||||||
|
uint32_t m_numBaseClass;
|
||||||
|
MultipleClassSingleEntryType m_baseClasses[0x100];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VtableTypeinfoType {
|
||||||
|
inthalf_t m_offset;
|
||||||
|
ClassTypeinfoType* m_typeinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VtableType {
|
||||||
|
void* m_vtable[0x100];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompleteVtableType : VtableTypeinfoType, VtableType {};
|
||||||
|
|
||||||
|
inline void** typeinfoVtableOf(void* ptr) {
|
||||||
|
auto vftable = *reinterpret_cast<VtableType**>(ptr);
|
||||||
|
|
||||||
|
auto typeinfoPtr =
|
||||||
|
static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable));
|
||||||
|
|
||||||
|
return typeinfoPtr->m_typeinfo->m_typeinfoVtable;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* traverseTypeinfoFor(
|
||||||
|
void* ptr, ClassTypeinfoType const* typeinfo, char const* afterIdent
|
||||||
|
) {
|
||||||
|
DummySingleClass dummySingleClass;
|
||||||
|
DummyMultipleClass dummyMultipleClass;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto optionIdent = typeinfo->m_typeinfoName;
|
||||||
|
if (std::strcmp(optionIdent, afterIdent) == 0) {
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummySingleClass)) {
|
||||||
|
auto siTypeinfo = static_cast<SingleClassTypeinfoType const*>(typeinfo);
|
||||||
|
return traverseTypeinfoFor(ptr, siTypeinfo->m_baseClassTypeinfo, afterIdent);
|
||||||
|
}
|
||||||
|
else if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummyMultipleClass)) {
|
||||||
|
auto vmiTypeinfo = static_cast<MultipleClassTypeinfoType const*>(typeinfo);
|
||||||
|
for (int i = 0; i < vmiTypeinfo->m_numBaseClass; ++i) {
|
||||||
|
auto& entry = vmiTypeinfo->m_baseClasses[i];
|
||||||
|
auto optionPtr = reinterpret_cast<std::byte*>(ptr) + entry.m_offset;
|
||||||
|
auto ret = traverseTypeinfoFor(optionPtr, entry.m_baseClassTypeinfo, afterIdent);
|
||||||
|
if (ret != nullptr) return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* typeinfoCastInternal(void* ptr, ClassTypeinfoType const* beforeTypeinfo, ClassTypeinfoType const* afterTypeinfo, size_t hint) {
|
||||||
|
// we're not using either because uhhh idk
|
||||||
|
// hint is for diamond inheritance iirc which is never
|
||||||
|
// used in gd, so should be pretty safe to ignore
|
||||||
|
if (!ptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)beforeTypeinfo;
|
||||||
|
(void)hint;
|
||||||
|
|
||||||
|
auto vftable = *reinterpret_cast<VtableType**>(ptr);
|
||||||
|
auto dataPointer = static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable));
|
||||||
|
auto typeinfo = dataPointer->m_typeinfo;
|
||||||
|
auto basePtr = static_cast<std::byte*>(ptr) + dataPointer->m_offset;
|
||||||
|
|
||||||
|
auto afterIdent = afterTypeinfo->m_typeinfoName;
|
||||||
|
|
||||||
|
return traverseTypeinfoFor(basePtr, typeinfo, afterIdent);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class After, class Before>
|
||||||
|
inline After typeinfo_cast(Before ptr) {
|
||||||
|
static_assert(
|
||||||
|
std::is_polymorphic_v<std::remove_pointer_t<Before>> && std::is_polymorphic_v<std::remove_pointer_t<After>>,
|
||||||
|
"Input is not a polymorphic type"
|
||||||
|
);
|
||||||
|
if (!ptr) {
|
||||||
|
return static_cast<After>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto beforeTypeinfo = reinterpret_cast<ClassTypeinfoType const*>(&typeid(std::remove_pointer_t<Before>));
|
||||||
|
auto afterTypeinfo = reinterpret_cast<ClassTypeinfoType const*>(&typeid(std::remove_pointer_t<After>));
|
||||||
|
return static_cast<After>(typeinfoCastInternal(ptr, beforeTypeinfo, afterTypeinfo, 0));
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
#include "ItaniumCast.hpp"
|
||||||
|
|
||||||
namespace geode {
|
namespace geode {
|
||||||
using dylib_t = void*;
|
using dylib_t = void*;
|
||||||
|
@ -23,110 +24,3 @@ namespace geode::base {
|
||||||
extern "C" inline uintptr_t _geode_ios_base() {
|
extern "C" inline uintptr_t _geode_ios_base() {
|
||||||
return geode::base::get();
|
return geode::base::get();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace geode::cast {
|
|
||||||
using uinthalf_t = uint32_t;
|
|
||||||
using inthalf_t = int32_t;
|
|
||||||
|
|
||||||
struct DummyClass {
|
|
||||||
virtual ~DummyClass() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DummySingleClass : DummyClass {};
|
|
||||||
|
|
||||||
struct DummyClass2 {};
|
|
||||||
|
|
||||||
struct DummyMultipleClass : DummySingleClass, DummyClass2 {};
|
|
||||||
|
|
||||||
struct ClassTypeinfoType {
|
|
||||||
void** m_typeinfoVtable;
|
|
||||||
char const* m_typeinfoName;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SingleClassTypeinfoType : ClassTypeinfoType {
|
|
||||||
ClassTypeinfoType* m_baseClassTypeinfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
|
|
||||||
struct MultipleClassSingleEntryType {
|
|
||||||
ClassTypeinfoType* m_baseClassTypeinfo;
|
|
||||||
uint8_t m_visibilityFlag;
|
|
||||||
inthalf_t m_offset;
|
|
||||||
uint8_t m_padding[sizeof(inthalf_t) - 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
struct MultipleClassTypeinfoType : ClassTypeinfoType {
|
|
||||||
uint32_t m_flags;
|
|
||||||
uint32_t m_numBaseClass;
|
|
||||||
MultipleClassSingleEntryType m_baseClasses[0x100];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VtableTypeinfoType {
|
|
||||||
inthalf_t m_offset;
|
|
||||||
ClassTypeinfoType* m_typeinfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VtableType {
|
|
||||||
void* m_vtable[0x100];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CompleteVtableType : VtableTypeinfoType, VtableType {};
|
|
||||||
|
|
||||||
inline void** typeinfoVtableOf(void* ptr) {
|
|
||||||
auto vftable = *reinterpret_cast<VtableType**>(ptr);
|
|
||||||
|
|
||||||
auto typeinfoPtr =
|
|
||||||
static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable));
|
|
||||||
|
|
||||||
return typeinfoPtr->m_typeinfo->m_typeinfoVtable;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* traverseTypeinfoFor(
|
|
||||||
void* ptr, ClassTypeinfoType* typeinfo, char const* afterIdent
|
|
||||||
) {
|
|
||||||
DummySingleClass dummySingleClass;
|
|
||||||
DummyMultipleClass dummyMultipleClass;
|
|
||||||
|
|
||||||
{
|
|
||||||
auto optionIdent = typeinfo->m_typeinfoName;
|
|
||||||
if (std::strcmp(optionIdent, afterIdent) == 0) {
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummySingleClass)) {
|
|
||||||
auto siTypeinfo = static_cast<SingleClassTypeinfoType*>(typeinfo);
|
|
||||||
return traverseTypeinfoFor(ptr, siTypeinfo->m_baseClassTypeinfo, afterIdent);
|
|
||||||
}
|
|
||||||
else if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummyMultipleClass)) {
|
|
||||||
auto vmiTypeinfo = static_cast<MultipleClassTypeinfoType*>(typeinfo);
|
|
||||||
for (int i = 0; i < vmiTypeinfo->m_numBaseClass; ++i) {
|
|
||||||
auto& entry = vmiTypeinfo->m_baseClasses[i];
|
|
||||||
auto optionPtr = reinterpret_cast<std::byte*>(ptr) + entry.m_offset;
|
|
||||||
auto ret = traverseTypeinfoFor(optionPtr, entry.m_baseClassTypeinfo, afterIdent);
|
|
||||||
if (ret != nullptr) return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class After, class Before>
|
|
||||||
inline After typeinfo_cast(Before ptr) {
|
|
||||||
static_assert(
|
|
||||||
std::is_polymorphic_v<std::remove_pointer_t<Before>>, "Input is not a polymorphic type"
|
|
||||||
);
|
|
||||||
auto basePtr = dynamic_cast<void*>(ptr);
|
|
||||||
auto vftable = *reinterpret_cast<VtableType**>(basePtr);
|
|
||||||
auto typeinfo =
|
|
||||||
static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable))->m_typeinfo;
|
|
||||||
|
|
||||||
auto afterTypeinfo =
|
|
||||||
reinterpret_cast<ClassTypeinfoType const*>(&typeid(std::remove_pointer_t<After>));
|
|
||||||
auto afterIdent = afterTypeinfo->m_typeinfoName;
|
|
||||||
|
|
||||||
return static_cast<After>(traverseTypeinfoFor(basePtr, typeinfo, afterIdent));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
#include "ItaniumCast.hpp"
|
||||||
|
|
||||||
namespace geode {
|
namespace geode {
|
||||||
using dylib_t = void*;
|
using dylib_t = void*;
|
||||||
|
@ -19,121 +20,3 @@ namespace geode::base {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace geode::cast {
|
|
||||||
using uinthalf_t = uint32_t;
|
|
||||||
using inthalf_t = int32_t;
|
|
||||||
|
|
||||||
struct DummyClass {
|
|
||||||
virtual ~DummyClass() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DummySingleClass : DummyClass {};
|
|
||||||
|
|
||||||
struct DummyClass2 {};
|
|
||||||
|
|
||||||
struct DummyMultipleClass : DummySingleClass, DummyClass2 {};
|
|
||||||
|
|
||||||
struct ClassTypeinfoType {
|
|
||||||
void** m_typeinfoVtable;
|
|
||||||
char const* m_typeinfoName;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SingleClassTypeinfoType : ClassTypeinfoType {
|
|
||||||
ClassTypeinfoType* m_baseClassTypeinfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
|
|
||||||
struct MultipleClassSingleEntryType {
|
|
||||||
ClassTypeinfoType* m_baseClassTypeinfo;
|
|
||||||
uint8_t m_visibilityFlag;
|
|
||||||
inthalf_t m_offset;
|
|
||||||
uint8_t m_padding[sizeof(inthalf_t) - 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
struct MultipleClassTypeinfoType : ClassTypeinfoType {
|
|
||||||
uint32_t m_flags;
|
|
||||||
uint32_t m_numBaseClass;
|
|
||||||
MultipleClassSingleEntryType m_baseClasses[0x100];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VtableTypeinfoType {
|
|
||||||
inthalf_t m_offset;
|
|
||||||
ClassTypeinfoType* m_typeinfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VtableType {
|
|
||||||
void* m_vtable[0x100];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CompleteVtableType : VtableTypeinfoType, VtableType {};
|
|
||||||
|
|
||||||
inline void** typeinfoVtableOf(void* ptr) {
|
|
||||||
auto vftable = *reinterpret_cast<VtableType**>(ptr);
|
|
||||||
|
|
||||||
auto typeinfoPtr =
|
|
||||||
static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable));
|
|
||||||
|
|
||||||
return typeinfoPtr->m_typeinfo->m_typeinfoVtable;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* traverseTypeinfoFor(
|
|
||||||
void* ptr, ClassTypeinfoType const* typeinfo, char const* afterIdent
|
|
||||||
) {
|
|
||||||
DummySingleClass dummySingleClass;
|
|
||||||
DummyMultipleClass dummyMultipleClass;
|
|
||||||
|
|
||||||
{
|
|
||||||
auto optionIdent = typeinfo->m_typeinfoName;
|
|
||||||
if (std::strcmp(optionIdent, afterIdent) == 0) {
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummySingleClass)) {
|
|
||||||
auto siTypeinfo = static_cast<SingleClassTypeinfoType const*>(typeinfo);
|
|
||||||
return traverseTypeinfoFor(ptr, siTypeinfo->m_baseClassTypeinfo, afterIdent);
|
|
||||||
}
|
|
||||||
else if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummyMultipleClass)) {
|
|
||||||
auto vmiTypeinfo = static_cast<MultipleClassTypeinfoType const*>(typeinfo);
|
|
||||||
for (int i = 0; i < vmiTypeinfo->m_numBaseClass; ++i) {
|
|
||||||
auto& entry = vmiTypeinfo->m_baseClasses[i];
|
|
||||||
auto optionPtr = reinterpret_cast<std::byte*>(ptr) + entry.m_offset;
|
|
||||||
auto ret = traverseTypeinfoFor(optionPtr, entry.m_baseClassTypeinfo, afterIdent);
|
|
||||||
if (ret != nullptr) return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* typeinfoCastInternal(void* ptr, ClassTypeinfoType const* beforeTypeinfo, ClassTypeinfoType const* afterTypeinfo, size_t hint) {
|
|
||||||
// we're not using either because uhhh idk
|
|
||||||
// hint is for diamond inheritance iirc which is never
|
|
||||||
// used in gd, so should be pretty safe to ignore
|
|
||||||
(void)beforeTypeinfo;
|
|
||||||
(void)hint;
|
|
||||||
|
|
||||||
auto vftable = *reinterpret_cast<VtableType**>(ptr);
|
|
||||||
auto dataPointer = static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable));
|
|
||||||
auto typeinfo = dataPointer->m_typeinfo;
|
|
||||||
auto basePtr = static_cast<std::byte*>(ptr) + dataPointer->m_offset;
|
|
||||||
|
|
||||||
auto afterIdent = afterTypeinfo->m_typeinfoName;
|
|
||||||
|
|
||||||
return traverseTypeinfoFor(basePtr, typeinfo, afterIdent);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class After, class Before>
|
|
||||||
inline After typeinfo_cast(Before ptr) {
|
|
||||||
static_assert(
|
|
||||||
std::is_polymorphic_v<std::remove_pointer_t<Before>> && std::is_polymorphic_v<std::remove_pointer_t<After>>,
|
|
||||||
"Input is not a polymorphic type"
|
|
||||||
);
|
|
||||||
auto beforeTypeinfo = reinterpret_cast<ClassTypeinfoType const*>(&typeid(std::remove_pointer_t<Before>));
|
|
||||||
auto afterTypeinfo = reinterpret_cast<ClassTypeinfoType const*>(&typeid(std::remove_pointer_t<After>));
|
|
||||||
return static_cast<After>(typeinfoCastInternal(ptr, beforeTypeinfo, afterTypeinfo, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -135,7 +135,7 @@ static Result<> flattenGithubRepo(ghc::filesystem::path const& dir) {
|
||||||
// github zipballs have a folder at root, but we already have our
|
// github zipballs have a folder at root, but we already have our
|
||||||
// own folder for that so let's just bring everything from that
|
// own folder for that so let's just bring everything from that
|
||||||
// folder to ours
|
// folder to ours
|
||||||
GEODE_UNWRAP_INTO(auto files, file::listFiles(dir));
|
GEODE_UNWRAP_INTO(auto files, file::readDirectory(dir));
|
||||||
try {
|
try {
|
||||||
// only flatten if there is only one file and it's a directory
|
// only flatten if there is only one file and it's a directory
|
||||||
if (files.size() == 1 && ghc::filesystem::is_directory(files[0])) {
|
if (files.size() == 1 && ghc::filesystem::is_directory(files[0])) {
|
||||||
|
|
Loading…
Reference in a new issue