Spuckwaffel / UEDumper

The most powerful Unreal Engine Dumper and Editor for UE 4.19 - 5.3
MIT License
735 stars 140 forks source link

Fix CoreUObject having a maxsize of zero causing incorrect missing member sizing of subclasses #55

Closed Hex0ffset closed 6 months ago

Hex0ffset commented 6 months ago

When generating an SDK, there's a scenario whereby maxSize of /Script/CoreUObject.Object can be zero. This leads to a situation whereby we add the missing member on the assumption that CoreUObject has a zero size/no members, resulting in a bugged SDK due to excess padding (e.g. members may be offset by 0x30 bytes for example).

For example, beforehand we had a UWorld like this in Back4Blood's SDK:

/// Class /Script/Engine.World
/// Size: 0x0708 (0x000030 - 0x000738)
class UWorld : public UObject
{ 
public:
    unsigned char                                      UnknownData00_3[0x38];
    class ULevel*                                      PersistentLevel;

whereas now with the fix, it's instead:

/// Class /Script/Engine.World
/// Size: 0x0708 (0x000030 - 0x000738)
class UWorld : public UObject
{ 
public:
    unsigned char                                      UnknownData00_3[0x10]
    class ULevel*                                      PersistentLevel;
Spuckwaffel commented 6 months ago

good idea, unfortunately a few commits ago i added this in purpose, logic why i even have maxSize prop can be found in EngineCore::finishPackages L 1133 or so. This is because the reflections system inheritedsize is incorrect sometimes (please don't ask my where, there were so many cases where the reflection system said a class has a 8 byte padding but inherited classes said has actual members defined where the the padding would be so we go though all inherited classes of a classes to check the real actual "maxsize". To fix the issue you stated it would probably be good to check if the maxSize pro is valid and if not we fall back and rely on the inheritedSize

Spuckwaffel commented 6 months ago

for (const auto& struc : package.combinedStructsAndClasses)
        {
            for (auto& name : struc->superNames)
            {
                const auto info = getInfoOfObject(name);
                if (!info || !info->valid)
                    continue;
                //get the super struct
                auto superStruc = static_cast<EngineStructs::Struct*>(info->target);
                //add the super struct as a super
                struc->supers.push_back(superStruc);
                //if they arent in the same package, add the supers package as dependency
                if (superStruc->owningPackage->index != package.index)
                    package.dependencyPackages.insert(superStruc->owningPackage);
                //add the current struct to the list of super of others of the super
                superStruc->superOfOthers.push_back(struc);
                //now if our current struct has defined members, we check the size of the super and possibly reduce the maxSize
                //because of trailing and padding, we choose the lowest member
                if (struc->definedMembers.size() > 0)
                {
                    const auto& firstMember = struc->definedMembers[0];
                    if (firstMember.offset < superStruc->maxSize)
                    {
                        superStruc->maxSize = firstMember.offset;
                    }
                }
            }

here is the mentioned code snippet. Comments should explain it