Skip to content

Commit

Permalink
fix dynamic cast
Browse files Browse the repository at this point in the history
  • Loading branch information
altalk23 committed Oct 2, 2023
1 parent 0ed1a41 commit 8dd2e15
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 43 deletions.
42 changes: 16 additions & 26 deletions loader/include/Geode/platform/ItaniumCast.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#pragma once

namespace geode::cast {
using uinthalf_t = uint32_t;
using inthalf_t = int32_t;

struct DummyClass {
virtual ~DummyClass() {}
Expand All @@ -14,25 +12,28 @@ namespace geode::cast {

struct DummyMultipleClass : DummySingleClass, DummyClass2 {};

struct VtableType;

struct ClassTypeinfoType {
void** m_typeinfoVtable;
VtableType* 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];
};
intptr_t m_metadata;

#pragma pack(pop)
uint8_t visibilityFlag() const {
return m_metadata & 0xFF;
}
intptr_t offset() const {
return m_metadata >> 8;
}
};

struct MultipleClassTypeinfoType : ClassTypeinfoType {
uint32_t m_flags;
Expand All @@ -41,7 +42,7 @@ namespace geode::cast {
};

struct VtableTypeinfoType {
inthalf_t m_offset;
intptr_t m_offset;
ClassTypeinfoType* m_typeinfo;
};

Expand All @@ -51,36 +52,25 @@ namespace geode::cast {

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 typeinfoVtableName = static_cast<CompleteVtableType*>(typeinfo->m_typeinfoVtable)->m_typeinfo->m_typeinfoName;
if (std::strcmp(typeinfoVtableName, "N10__cxxabiv120__si_class_type_infoE") == 0) {
auto siTypeinfo = static_cast<SingleClassTypeinfoType const*>(typeinfo);
return traverseTypeinfoFor(ptr, siTypeinfo->m_baseClassTypeinfo, afterIdent);
}
else if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummyMultipleClass)) {
else if (std::strcmp(typeinfoVtableName, "N10__cxxabiv121__vmi_class_type_infoE") == 0) {
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 optionPtr = reinterpret_cast<std::byte*>(ptr) + entry.offset();
auto ret = traverseTypeinfoFor(optionPtr, entry.m_baseClassTypeinfo, afterIdent);
if (ret != nullptr) return ret;
}
Expand Down
8 changes: 1 addition & 7 deletions loader/include/Geode/platform/android.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <dlfcn.h>
#include "ItaniumCast.hpp"

namespace geode {
struct PlatformInfo {
Expand All @@ -12,10 +13,3 @@ namespace geode::base {
/*GEODE_NOINLINE inline*/ uintptr_t get();
}

namespace geode::cast {
template <class After, class Before>
After typeinfo_cast(Before ptr) {
// yall have symbols smh
return dynamic_cast<After>(ptr);
}
}
21 changes: 11 additions & 10 deletions loader/src/hooks/DynamicCastFix.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
#include <Geode/DefaultInclude.hpp>

#ifdef GEODE_IS_MACOS
#include <Geode/loader/Mod.hpp>

using namespace geode::prelude;

#include <Geode/loader/Mod.hpp>
#include <Geode/modify/Modify.hpp>

$execute {
// this replaces the call to __dynamic_cast with a call to our own
// this is needed because the transitions in cocos uses dynamic cast to check
// layers, which fail on user layers due to typeinfo not matching
(void)Mod::get()->patch(
reinterpret_cast<void*>(base::get() + 0x603948), toByteArray(&cast::typeinfoCastInternal)
);
}

#endif
#if defined(GEODE_IS_MACOS)
(void)Mod::get()->patch(
reinterpret_cast<void*>(base::get() + 0x603948), toByteArray(&cast::typeinfoCastInternal)
);
#elif defined(GEODE_IS_ANDROID)
(void)Mod::get()->addHook(reinterpret_cast<void*>(base::get() + 0x519a8c), &cast::typeinfoCastInternal, "__dynamic_cast");
#endif


}

0 comments on commit 8dd2e15

Please sign in to comment.