extract gnustl empty string from CCString

no more hardcoded addresses in android!!
This commit is contained in:
matcool 2024-01-16 16:54:33 -03:00
parent 925e72535d
commit 806499c8f4
4 changed files with 57 additions and 15 deletions

View file

@ -51,7 +51,13 @@ public:
/**
* @lua NA
*/
#ifndef GEODE_IS_ANDROID
inline CCString() : m_sString("") {}
#else
// Make sure its imported because of gd::string stuff,
// check android/main.cpp for more info
CCString();
#endif
/**
* @lua NA
*/

View file

@ -1,23 +1,15 @@
#include <Geode/c++stl/gdstdlib.hpp>
#include "../../c++stl/string-impl.hpp"
#include "internalString.hpp"
#if defined(GEODE_IS_ANDROID32)
static auto constexpr NEW_SYM = "_Znwj";
static constexpr uintptr_t STRING_EMPTY = 0xaa1c48 - 0x10000 - 0xc; // the internal struct size
#elif defined(GEODE_IS_ANDROID64)
static auto constexpr NEW_SYM = "_Znwm";
static constexpr uintptr_t STRING_EMPTY = 0x12d8568 - 0x100000 - 0x18; // the internal struct size
#endif
static auto constexpr DELETE_SYM = "_ZdlPv";
// 2.2 addition
// zmx please fix this
static void* getLibHandle() {
static void* handle = dlopen("libcocos2dcpp.so", RTLD_LAZY | RTLD_NOLOAD);
return handle;
@ -54,13 +46,41 @@ void gd::operatorDelete(void* ptr) {
return fnPtr(ptr);
}
namespace geode::stl {
static inline auto emptyInternalString() {
return reinterpret_cast<StringData::Internal*>(
geode::base::get() + STRING_EMPTY + sizeof(StringData::Internal)
);
}
using namespace geode::stl;
void* g_ourInternalString = nullptr;
static auto& emptyInternalString() {
static StringData::Internal* ptr = [] {
StringData::Internal internal;
internal.m_size = 0;
internal.m_capacity = 0;
// make our empty internal string different from gd's
internal.m_refcount = 1'000'000'000;
// use char* so we can do easy pointer arithmetic with it
auto* buffer = static_cast<char*>(gd::operatorNew(sizeof(internal) + 1));
std::memcpy(buffer, &internal, sizeof(internal));
buffer[sizeof(internal)] = 0;
g_ourInternalString = reinterpret_cast<void*>(buffer);
return reinterpret_cast<StringData::Internal*>(buffer + sizeof(internal));
}();
return ptr;
}
void setEmptyInternalString(gd::string* str) {
auto* internal = *reinterpret_cast<StringData::Internal**>(str);
// make sure its empty
if (internal[-1].m_size == 0 && internal[-1].m_capacity == 0 && internal[-1].m_refcount == 0) {
emptyInternalString() = internal;
if (g_ourInternalString != nullptr) {
gd::operatorDelete(g_ourInternalString);
g_ourInternalString = nullptr;
}
}
}
namespace geode::stl {
void StringImpl::setEmpty() {
data.m_data = emptyInternalString();
}

View file

@ -0,0 +1,5 @@
#pragma once
#include <Geode/c++stl/string.hpp>
void setEmptyInternalString(gd::string* str);

View file

@ -2,6 +2,9 @@
#include "../load.hpp"
#include <jni.h>
#include "internalString.hpp"
using namespace geode::prelude;
// idk where to put this
#include <EGL/egl.h>
@ -21,6 +24,14 @@ extern "C" [[gnu::visibility("default")]] jint JNI_OnLoad(JavaVM* vm, void* rese
geode::log::warn("Failed to remove update directory: {}", ec.message());
}
{
// Epic hack: get the empty internal string from CCString
// avoid ::create as to not call autorelease
auto* cc = new CCString();
setEmptyInternalString(&cc->m_sString);
delete cc;
}
geodeEntry(nullptr);
return JNI_VERSION_1_6;
}