Исходник Dota-cheat | База под доту 2

Эксперт
Статус
Оффлайн
Регистрация
31 Авг 2018
Сообщения
1,792
Реакции[?]
1,073
Поинты[?]
29K
ну и ты личишь мапу с шема хуитой(не удаляешь при деините ибо она статик инлайн. в общем мораль такова что глобалы в длл не надо юзать. да и ваще нигде не надо.)
std::unordered_map< Hash_t, std::unordered_map< Hash_t, std::uint32_t > > Schema::mapOffsets;
она 2мб весит
с одной стороны похуй но с другой стороны лик есть лик. тут насрал там насрал и уже не очень хорошо получается
Лик? Как только ты выгрузишь дллку - деструктор std::unordered_map затрет все

Длл загружена:
1659835710641.png
Длл выгружена:
1659835724476.png
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
781
Реакции[?]
331
Поинты[?]
63K
Лик? Как только ты выгрузишь дллку - деструктор std::unordered_map затрет все

Длл загружена:
Посмотреть вложение 215701
Длл выгружена:
Посмотреть вложение 215702
от способа инжекта зависит. при некоторых способах инжекта деструктор не будет вызываться у статик инлайн объектов. поэтому и надо аккуратно руками контроллировать их жизнь и смерть(точнее жизнь и смерть оборачивающих объектов, например шема) а не глобалами делать. не все дефолтно инжектят. представь что ты когда-нибудь перейдешь на другой способ инжекта, думая что деструкторы вызываются, а по факту это будет нихуя не так. так что лучше щас пофиксить. глобалы - это иллюзия. ты реально хочешь сказать что твоя mapOffsets это глобальный объект который живёт пока живёт программа? нихуя подобного. он живет пока живёт шема. шема оживает = оживает мапа. шема умирает = умирает мапа. мапа находится В МАСШТАБЕ ШЕМЫ а не В ГЛОБАЛЬНОМ МАСШТАБЕ
 
Эксперт
Статус
Оффлайн
Регистрация
31 Авг 2018
Сообщения
1,792
Реакции[?]
1,073
Поинты[?]
29K
мапа находится В МАСШТАБЕ ШЕМЫ а не В ГЛОБАЛЬНОМ МАСШТАБЕ
Это было бы корректно, если бы схема у меня была объектом, но это просто неймспейс
от способа инжекта зависит.
Деструктор так же не вызовется ни для одного глобального объекта. Если в твоем софте юзается какая-нибудь достаточно крупная либа, например, протобаф - готовься при МануалМапе или чем-то другом терять еще большее количество памяти. Это уже минусы способа инжекта, а не конкретно базы.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
781
Реакции[?]
331
Поинты[?]
63K
Это было бы корректно, если бы схема у меня была объектом, но это просто неймспейс

Деструктор так же не вызовется ни для одного глобального объекта. Если в твоем софте юзается какая-нибудь достаточно крупная либа, например, протобаф - готовься при МануалМапе или чем-то другом терять еще большее количество памяти. Это уже минусы способа инжекта, а не конкретно базы.
так в том то и суть - хули у тебя ОБЪЕКТ сделан НЕЙМСПЕЙСОМ? на лицо все признаки объекта:
1. есть инициализация(Setup у тебя)
2. есть члены(мапа с оффсетами)
3. есть деинициализация(очистка мапы)
в том то и суть что деструктор не вызовется ни для одного глобального объекта => НЕ НАДО ЮЗАТЬ ГЛОБАЛЬНЫЕ ОБЪЕКТЫ. ОСОБЕННО КОГДА ОНИ НИХУЯ НЕ ГЛОБАЛЬНЫЕ. я тебя уверяю что все то что ты хочешь можно спокойно сделать с такой же общедоступностью как у глобала но при этом с очень чётким контролем ресурсов. ты же сам лично сталкивался с проблемой что тебе нужен четкий контроль инита деинита глобального объекта. ты закостылил через глобальный std::optional который несовместим нормально с RAII(руками reset приходится писать). можно спокойно достичь поздней инициализации(через union) и авто(RAII)/ручного(.destroy())(что нужно то и выбираешь по обстоятельствам) деструкта если юзать ОБЪЕКТЫ нормально.
 
Эксперт
Статус
Оффлайн
Регистрация
31 Авг 2018
Сообщения
1,792
Реакции[?]
1,073
Поинты[?]
29K
так в том то и суть - хули у тебя ОБЪЕКТ сделан НЕЙМСПЕЙСОМ?
От того, что я сменю неймспейс на класс в данном случае не изменится буквально ничего, мапа все еще не будет очищаться при выгрузке модуля, загруженного при помощи ManualMap
ты закостылил через глобальный std::optional который несовместим нормально с RAII(руками reset приходится писать)
std::optional такой же объект как и любой другой, как только для опционала наступает смерть - в деструкторе .reset вызывается сам по необходимости
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
781
Реакции[?]
331
Поинты[?]
63K
От того, что я сменю неймспейс на класс в данном случае не изменится буквально ничего, мапа все еще не будет очищаться при выгрузке модуля, загруженного при помощи ManualMap

std::optional такой же объект как и любой другой, как только для опционала наступает смерть - в деструкторе .reset вызывается сам по необходимости
так сделать класс это не просто заменить слово неймспейс на слово класс бро. это чуть больше. это мув хуюв деструкт конструкт раии хуии много чего. в том то и суть что неймспейс это "тупая" хуита. класс это "умная" хуита. у нее есть всякие семантики ктор дтор мув и тд. C++ это C с классами. если ты не юзаешь классы это не С++
про std::optional - я тебе уже сказал, деструктор НЕ вызывается при некоторых способах инжекта. к тому же он ХУЙ ЗНАЕТ КОГДА вызывается(и если он взаимодействует с какими-то другими глобальными объектами, то они уже могут быть потенциально убиты). ты нихуя не контроллируешь.
есть возможность писать код который и с дефолтным инжектом и с любым другим будет ахуенно работать и давать тебе ахуенный контроль над ресурсами. не юзай глобалы и будет счастье. уникальность и общедоступность объекта можно и другими способами осуществить.
почему тебе не нравится совместимость с разными способами инжекта?
ты понимаешь что рано или поздно наступит день когда ты попробуешь другой способ инжекта и обнаружишь что у тебя какого-то хуя что-то не работает и потом обнаружишь что все твои деструкторы не вызываются? так зачем ждать, когда можно сейчас пофиксить?
 
🤡
Пользователь
Статус
Оффлайн
Регистрация
28 Апр 2014
Сообщения
127
Реакции[?]
163
Поинты[?]
21K
СДК плюс минус норм оформлено, но реверсить все еще дохуя и добавлять, ну и крайне рекомендую преодолеть себя и прислушаться к Liberalist. И изучить этот вопрос более подробно для себя. Это будет полезно на будущее. Сейчас он прав во всем сказанном, если сейчас у тебя по твоему сдк не ликает ничего, не крешит, не значит что когда ты будешь продолжать кодить в таком же стиле - не будет момента, что у тебя деструктор ебанет раньше нужного момента и т.п.
Если уж и хочешь делать сдк на паблик, принимай критику и пытайся вникнуть в неё. Если же ты хочешь чисто для себя хуярить, то так и напиши, что тебе не интересна критика и предложения по улучшению сдк.
 
Последнее редактирование:
Эксперт
Статус
Оффлайн
Регистрация
31 Авг 2018
Сообщения
1,792
Реакции[?]
1,073
Поинты[?]
29K
так сделать класс это не просто заменить слово неймспейс на слово класс бро. это чуть больше. это мув хуюв деструкт конструкт раии хуии много чего. в том то и суть что неймспейс это "тупая" хуита. класс это "умная" хуита. у нее есть всякие семантики ктор дтор мув и тд.
МануалМап заставит тебя вручную вызывать деструктор этого класса при анлоаде, поскольку тебе в любом случае придется делать объект этого класса глобальным, чтобы иметь возможность им пользоваться отовсюду. Что мешает тебе так же вручную вызвать деструктор для мапы? Делать этот же объект локальным нету абсолютно смысла, ибо жить он должен во всех потоках игры, где он может использоваться хотя бы гипотетически.
про std::optional - я тебе уже сказал, деструктор НЕ вызывается при некоторых способах инжекта. к тому же он ХУЙ ЗНАЕТ КОГДА вызывается(и если он взаимодействует с какими-то другими глобальными объектами, то они уже могут быть потенциально убиты). ты нихуя не контроллируешь.
Деструктор std::optional вызывается тогда же, когда и все остальные деструкторы, потому что это обычный объект. Не понимаю, о чем ты говоришь.
уникальность и общедоступность объекта можно и другими способами осуществить
Отправлять объект в динамическую память или использовать Singleton - не лучший вариант. В первом случае тебе все еще нужно будет самому контролировать удаление объекта(Даже если он будет внутри std::unique_ptr, поскольку для него деструктор тоже не вызовется), а во втором случае у тебя и вовсе не будет контроля над тем, когда объект удаляется. Палка о двух концах
Если уж и хочешь делать сдк на паблик, принимай критику и пытайся вникнуть в неё.
Так в данном случае я и принимаю критику. То, что я не проследил за инициализацией/выгрузкой имгуя - определенно мой косяк, доберусь до компа - поправлю(либо можете залить Pull Request на гитхаб). Да и сейчас я так же пытаюсь понять, чем в этом случае класс будет лучше пространства имен, но я попросту не вижу логики, так и так получится глобальный объект(максимум - с ограниченной областью видимости), который не будет вызывать свой деструктор во время выгрузке при инжекте через ManualMap
 
Последнее редактирование:
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
781
Реакции[?]
331
Поинты[?]
63K
МануалМап заставит тебя вручную вызывать деструктор этого класса при анлоаде, поскольку тебе в любом случае придется делать объект этого класса глобальным, чтобы иметь возможность им пользоваться отовсюду. Что мешает тебе так же вручную вызвать деструктор для мапы? Делать этот же объект локальным нету абсолютно смысла, ибо жить он должен во всех потоках игры, где он может использоваться хотя бы гипотетически.

Деструктор std::optional вызывается тогда же, когда и все остальные деструкторы, потому что это обычный объект. Не понимаю, о чем ты говоришь.

Отправлять объект в динамическую память или использовать Singleton - не лучший вариант. В первом случае тебе все еще нужно будет самому контроллировать удаление объекта(Даже если он будет внутри std::unique_ptr, поскольку для него деструктор тоже не вызовется), а во втором случае у тебя и вовсе не будет контроля над тем, когда объект удаляется. Палка о двух концах

Так в данном случае я и принимаю критику. То, что я не проследил за инициализацией/выгрузкой имгуя - определенно мой косяк, доберусь до компа - поправлю(либо можете залить Pull Request на гитхаб). Да и сейчас я так же пытаюсь понять, чем в этом случае класс будет лучше пространства имен, но я попросту не вижу логики, так и так получится глобальный объект(максимум - с ограниченной областью видимости), который не будет вызывать свой деструктор во время выгрузке при инжекте через ManualMap
бро ты узко слишком мыслишь. суть глобала в общедоступости данных.
НО общедоступность данных можно реализовать не только через глобальный объект.
руками я нихуя никогда не делаю(если сам этого не хочу), у меня все всегда автоматом, будь то мануалмап или любой другой способ инжекта.
std::optional у тебя(например CTX::Config) это ГЛОБАЛЬНЫЙ ОБЪЕКТ. он при ммапе не будет разъебываться автоматически(как и твоя мапа и прочие глобалы. глобалы конструируются до main и деструктируются после main(точнее в CRT'шных точках входа и выхода которые до и после мейна идут)). при ммапе хуй тебе а не выход CRT.
Singleton - это ахуенная тема. это не какая-то конкретная имплементация. это шаблон, принцип, техника программирования(которая грубо говоря заключается в том что ты создаешь не более чем 1 шт объекта за всю жизнь). этот шаблон можно спокойно осуществить таким способом что у тебя будет ахуительнейший контроль и всё что нужно для счастья. у самого понятия "Singleton" нет никаких изъянов. изъяны есть у имплементаций. если все ахуенно сделать - это имба. вопрос лишь в воображении и твоих нуждах.
про "локальные объекты" - зависит от дизайна. твой дизайн с ними несовместим.
я же предпочитаю такой дизайн, что у меня все ресурсы лежат в моём "инит" треде, который просто держит ресурсы и ожидает деинжекта и после сигнала(ну или в случае исключения) раскручивает стек и разъебывает все ресурсы(= снимает все хуки хуюки и тд).
init:
{
try{
auto hooks = HookSomeShit();
await deinit;
}
catch ... //все дерьмо из try блока удаляется по RAII если вдруг исключение вылетит
}
в итоге у меня невъебически строгий контроль ресурсов - я АБСОЛЮТНО ВСЕ ресурсы(хуки консоли и тд) держу в стеке, в случае исключения или при выходе из чита автоматом все разъебывается засчёт stack unwinding'а. чисто всё локальное у меня. ни один ресурс не сможет убежать никуда. сдохну я = сдохнут все ресурсы. но при этом всё что надо еще и общедоступное(засчёт указателей которые указывают в мой стек).
Singleton состоит из хранилища(память под данные объекта), Create и Destroy.
в моей имплементации Singleton'ы имеют локальное хранилище(= хранятся в стеке "инит" треда. стек треда умирает вместе с тредом, а к тому моменту когда тред умрёт мой чит уже полностью будет мертв все хуки сняты и всё уже мертвое), и имеют контроллер(хуита которая при создании вызывает Create и при смерти вызывает Destroy. то есть RAII обертка на синглтон) и спокойно поддерживают исключения при конструкции с нормальным удалением созданных в процессе проваленной конструкции подресурсов(например пускай я создаю синглтон логгера - сначала создал консоль, потом допустим зафейлился фреопен - консоль освободится автоматом).
общедоступность я сделал просто через глобальный указатель(глобальная переменная)(который указывает на стек). кому нужен доступ к объекту - берут указатель(ну точнее референс) и работают с объектом. так же если кто-то захочет он может чекнуть жив ли синглтон(на случай если он был руками заранее убит например) чекнув указатель на ноль. кому нужны реальные гарантии живого синглтона - тот принимает референс на объект как аргумент(следовательно чтобы вызвать функцию мне сначала надо будет создать синглтон иначе я тупо не смогу вызвать функцию. вместо того чтобы мой инит сам бы брал логгер он просит логгер у того кто вызывает инит тем самым заставляя того кто вызывает инит создать логгер(ну этакое напоминание для меня чтобы я как программист не забыл что нужно создать синглтон)). кто уверен тот напрямую сам синглтон берет.
для синхронизации(чтобы при анхуке презента например не крашило) использую где надо двухступенчатый деинит(хукаю хуйню в мейн треде в таком месте где презент не вызывался бы параллельно(т.е. в месте где мейн тред держит какой-нибудь мьютекс который исключает возможность вызова презента параллельно), отправляю сигнал из этого мейн треда в свой инит тред(а мейн тред ждет ответного сигнала), в инит треде разъебываюсь и отдаю сигнал обратно в мейн тред который потом продолжает свою работу).
никогда руками нихуя не удаляю(если не надо заранее удалить), работает всё с любым способом инжекта.
синглтоны конструируются в самом начале инита в порядке важности(то есть к моменту какойто логики все синглтоны уже сконструированы).
синглтоны удаляются только при выходе из чита(и в ПРАВИЛЬНОМ ПОРЯДКЕ который я сам задал а не в рандомном), а к моменту выхода из чита вся логика(хуки и тд) уже 100% сдохла, и как следствие к мертвому синглтону никто не сможет уже обратиться.
наверняка есть какието дизайны которые еще пизже, я пока еще не придумал ничего мощнее.
 
Нестандартное звание?
Пользователь
Статус
Оффлайн
Регистрация
23 Июл 2021
Сообщения
444
Реакции[?]
81
Поинты[?]
2K
Мамкины Гении, по набежали, что вам не нравиться в бесплатном сдка, который +- читается, я бы был рад, изучить полностью, но не интересуюсь дотой.
Бля дек красава, как и его ник.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
781
Реакции[?]
331
Поинты[?]
63K
Мамкины Гении, по набежали, что вам не нравиться в бесплатном сдка, который +- читается, я бы был рад, изучить полностью, но не интересуюсь дотой.
Бля дек красава, как и его ник.
бро мне все нравится поэтому я и лайкнул оригинальный пост. но есть такое понятие "тестинг". это когда люди или сам автор смотрят тестируют и находят баги и недочёты чтобы автор их пофиксил и повысил свой скилл. это мечта любого нормального разработчика, чтобы твой софт взяли и показали тебе все места где ты ошибся, чтобы ты всё исправил и сделал лучше. софта которую никто не тестит - ебаная хуита с кучей багов о которой просто никто не знает. сам баг это не проблема - все баги фиксятся. вся проблема в том, что ты о багах как правило просто не вкурсе. если никто тебе о твоих багах не скажет или ты сам их не будешь пытаться искать ты так и будешь сидеть с ними. я был бы очень рад если бы мне кто-нибудь сказал что я где-то обосрался(а я много где сру) потому что тогда я бы мог пойти подумать и исправить. если мне никто ничего не скажет то мне самому придётся сидеть и выжидать пока у меня все поломается и потом идти искать причину. для того и существуют всякие сборы статистик, бенчмарки, тестовые сюиты, альфа тестинги логи дебаггеры и прочий шлак - всё для того чтобы обнаруживать и фиксить баги и улучшать продукт. ты бы предпочёл чтобы никто ничего нигде никогда не фиксил? софт это не просто кусок говна который ты 1 раз сделал и забыл про него.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
781
Реакции[?]
331
Поинты[?]
63K
ты кстати не пробовал std::variant вместо std::any юзать?
там не надо свитч кейс каст + внутренний стораж(вариант по размеру как минимум такой же как и самый большой его вид) а не динамик как в any и ебли не будет такой с добавлением
//shitcode VVV
C++:
using Drawable = std::variant<ScreenText, Line, ViewportLine, Box>;
...
std::queue<Drawable> queue{};//мне очередь просто по приколу зашла
...
void AddBox(const Vector3& world_min, const Vector3& world_max, const DirectXColor& color)
    {
        queue.push(Box{ color, world_min, world_max });
    }
...
C++:
std::visit(overloaded_lambda
                {
                    [&](const Line& drawable) {
                        renderer.DrawLine3D(drawable.GetStart(), drawable.GetEnd(), drawable.GetColor(), viewprojection, nearPlane);
                    },
                    [&](const ViewportLine& drawable) {
                        renderer.DrawLine3DViewport(drawable.GetStart(), drawable.GetEnd(), drawable.GetColor(), viewprojection, nearPlane, CameraLookAt);
                    },
                    [&](const Box& drawable) {
                        renderer.DrawBox3DAABB(drawable.GetMin(), drawable.GetMax(), drawable.GetColor(), viewprojection, nearPlane);
                    },
                    [&](const ScreenText& drawable) {
                        renderer.DrawText3D(drawable.GetPos(), drawable.GetColor(), drawable.GetText(), viewprojection, screen_size);
                    }
                }, queue.front());
ну и
C++:
if ( vecSafeDrawData.empty( ) )
            return;

        for ( const auto& objectInfo : vecSafeDrawData )
тут не обязательно чекать empty. цикл и так будет 0 итераций(= нихуя не будет делать) если пустой контейнер. start будет равен end.
ну и конечно же потецниальный лик(не связанный с инжектом) изза отсутствия RAII.
если std::filesystem::path::path кинет(а он спокойно может кинуть. template< class Source > path( const Source& source, format fmt = auto_format ) нету ноексепта)
то до CoTaskMemFree дело не дойдет и ликнется память.
C++:
wchar_t* pwszFontsPath = nullptr;
if ( FAILED( SHGetKnownFolderPath( FOLDERID_Fonts, 0, nullptr, &pwszFontsPath ) ) )
    throw std::runtime_error( "Failed to get fonts directory path." );

const std::filesystem::path pathFonts = pwszFontsPath;
CoTaskMemFree( pwszFontsPath );
 
Эксперт
Статус
Оффлайн
Регистрация
31 Авг 2018
Сообщения
1,792
Реакции[?]
1,073
Поинты[?]
29K
ты кстати не пробовал std::variant вместо std::any юзать?
там не надо свитч кейс каст + внутренний стораж(вариант по размеру как минимум такой же как и самый большой его вид) а не динамик как в any и ебли не будет такой с добавлением
[/CODE]
Когда писал код даже не задумался над std::variant, а зря... Я щас спать ложусь, как проснусь - переделаю под std::variant
потецниальный лик(не связанный с инжектом) изза отсутствия RAII.
если std::filesystem::path::path кинет(а он спокойно может кинуть. template< class Source > path( const Source& source, format fmt = auto_format ) нету ноексепта)
то до CoTaskMemFree дело не дойдет и ликнется память.
За это благодарю, не углядел, буду у компа - закрою этот косяк
 
Пользователь
Статус
Оффлайн
Регистрация
4 Авг 2017
Сообщения
262
Реакции[?]
42
Поинты[?]
3K
Доебались для человека...

Спасибо за базу, мне как новичку понятно почти все, написано читаемо и удобно.


а главное БеСпЛаТнО
 
Эксперт
Статус
Оффлайн
Регистрация
31 Авг 2018
Сообщения
1,792
Реакции[?]
1,073
Поинты[?]
29K
ты кстати не пробовал std::variant вместо std::any юзать?
Сделал

то до CoTaskMemFree дело не дойдет и ликнется память.
C++:
wchar_t* pwszFontsPath = nullptr;
if ( FAILED( SHGetKnownFolderPath( FOLDERID_Fonts, 0, nullptr, &pwszFontsPath ) ) )
throw std::runtime_error( "Failed to get fonts directory path." );

const std::filesystem::path pathFonts = pwszFontsPath;
CoTaskMemFree( pwszFontsPath );
Пофиксил
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
781
Реакции[?]
331
Поинты[?]
63K
Сделал


Пофиксил
вот этот код(/core/helpers/schema.cpp | Line 50)
C++:
for ( int nFieldIndex = 0; nFieldIndex < pClassBinding->GetNumFields( ); nFieldIndex++ )
                {
                    CSchemaField* const pSchemaField = &pClassBinding->GetFields( )[ nFieldIndex ];
                    if ( !pSchemaField )
                        continue;
очень ужасные последствия будет иметь если GetFields вернет nullptr и GetNumFields вернет число больше единицы.
смотри что ты делаешь:
Код:
пусть i от 0 до n:
пусть x = взять [потенциально  нуллптр] и прибавить i * sizeof(CSchemaField)//= i * 32
чекнуть x на ноль, скип если ноль
дереференс x
очевидно, что если подставить сюда 0 то все нормально будет:
Код:
пусть x = взять [потенциально нуллптр] и прибавить 0(в случае нуллптр это будет все так же нуллптр)
чекнуть x на ноль(проваливается чек все нормально), скип
но если поставить сюда 1 то смотри что происходит
Код:
пусть x = взять [потенциально нуллптр] и прибавить 32
чекнуть x на ноль(32 != 0)(чек не проваливается, идёт дальше выполнение)
дереференс
очевидно что будет краш ибо ты будешь считывать с адреса 00'00'00'00'00'00'00'32(собсна пруф:
1659990241700.png
1659990249800.png (0x20 и есть 32)
)
собственно если поставить перед циклом(для теста)
pClassBinding->GetFields() = nullptr;
то можно спокойно получить краш в ебало(как я и сделал)
хотя если бы чек не был таким кривым этот класс бы просто скипнулся.
фикс очевидный(сначала чек а потом уже прибавление)(тестил с pClassBinding->GetFields() = nullptr; и не крашит):
C++:
//на всякий случай еще раз перечитай мб я ошибку допустил я не очень внимательный сегодня VVV
if (auto fields = pClassBinding->GetFields(); fields)
{
    for (int nFieldIndex = 0; nFieldIndex < pClassBinding->GetNumFields(); nFieldIndex++)
    {
        const auto& pSchemaField = fields[nFieldIndex];

        const Hash_t ullFieldHashed = Hash::FNV1A(pSchemaField.m_pszFieldName);

        mapOffsets[ullClassHashed][ullFieldHashed] = pSchemaField.m_nOffset;
    }
}
самое смешное что у меня на самом деле похожий баг(я вообще забыл чекнуть эту хуиту на nullptr когда писал из головы вылетело xD)(ну с другой стороны там и так говнопроект который полностью напичкан говнокодом который я давно мечтаю переписать, так что там и других багов дохуя)
 
Эксперт
Статус
Оффлайн
Регистрация
31 Авг 2018
Сообщения
1,792
Реакции[?]
1,073
Поинты[?]
29K
очень ужасные последствия будет иметь если GetFields вернет nullptr и GetNumFields вернет число больше единицы.
В доте информация по количеству полей и по самим полям заполняется отдельной функцией, я не думаю, что хотя бы в теории, существует сценарий, при котором GetFields окажется nullptr, только если самому не ломать его специально.

Но проверку я все равно добавлю в следующем коммите - в плюсах быть параноиком полезно :)
 
Сверху Снизу