• Я зарабатываю 100 000 RUB / месяц на этом сайте!

    А знаешь как? Я всего-лишь публикую (создаю темы), а админ мне платит. Трачу деньги на мороженое, робуксы и сервера в Minecraft. А ещё на паль из Китая. 

    Хочешь так же? Пиши и узнавай условия: https://t.me/alex_redact
    Реклама: https://t.me/yougame_official

Вопрос [Java] Вопрос касательно планирования архитектуры библиотеки, уязвимых мест и неопределенного поведения при явном кривом использовании функционала

Модератор раздела «Создание читов Minecraft»
Модератор
Модератор
Статус
Оффлайн
Регистрация
5 Июн 2025
Сообщения
555
Реакции
30
Драсте, я уже довольно долго работаю над большим фреймворком пересекающимся с нативными библиотеками, и всё чаще и чаще возникает вопрос касательно неопределенного поведения библиотеки при использовании её "абы как". Что-бы было чуть понятнее - приведу пример:
К примеру у нас есть библиотека для работы которой нужно создавать контекст, но есть какой-то объект который требует для своей работы контекст, но из-за специфики этого объекта и его поведения полностью предостеречь от кривого поведения при исчезновении контекста не получится.

Как пример, представим что это пул объектов(NativeObject) которые создаются в самом контексте, можно при создании пула проверить есть ли контекст, при получении объекта(obtain) и отсутствии свободных оных(NativeObject) в пуле(при создании пулом нового объекта через контекст) можно сделать проверку на существование контекста, но при этом если контекст в моменте теряется, пул сам по себе не пропадает, NativeObject закрепленные за пулом так-же не пропадают (максимум - можно освободить нативные ресурсы NativeObject которыми владеет пул, но это сильно осложнит реализацию самого NativeObject).

При освобождении без проверки контекста можно сильно наебаться и крашнуть JVM нативным вызовом, что не есть хорошо, с проверкой - метод бесполезен. Т.е. при пропаже контекста фактически весь пул становится мусорным объектом который не может функционировать, это тоже не хорошо, но поскольку вкинуть пул в пакет к контексту(в имплементацию а не как доп. функционал из коробки) нельзя(потому-что имплементация фактически закрытая за исключением 1-2 методов) - я в целом хрен знает что с этим можно придумать.

Казалось бы не делает ничего free() и obtain() - ну пусть и не делают, но мне это тоже как-то не внушает доверие что такое можно считать за нормальное поведение кода, поэтому собсна вопрос и запостил, что-бы понять где еще рамки нормы можно натянуть на глобус, а где - тотальный треш

Пример кода:
Проблема:
Expand Collapse Copy
class NativeObjectPool {
    List<NativeObject> obtainedObjects;
    List<NativeObject> freeObjects;

    ExamplePool(int size) {
        checkContext();
        obtainedObjects = new List<>(size);
        freeObjects = new List<>(size);
    }

    NativeObject obtain() {
        // Если есть свободный объект
        if (freeObjects.size() > 0) {
            NativeObject obj = freeObjects.remove(0);
            obtainedObjects.add(obj);
            return obj;
        }
        
        // Если свободных объектов нет и нужно его создать
        if (!checkSize()) {
            return null; // превышен лимит размера
        }
        
        checkContext(); // Проверяем существование контекста
        NativeObject obj = Context.instance().createNativeObject();
        obtainedObjects.add(obj);
        return obj;
    }
    
    void free(@NotNull NativeObject obj) {
        // Проблема тут, проверить контекст мы можем, но что делать если нам вернули такой объект без контекста?
        // Если вызвать метод NativeObject#reset() мы можем получить JVM-краш из-за отсутствия нативного контекста
        // Просто игнорировать?...
        
        if (contextExists() && obtainedSources.contains(obj)) {
            obtainedSources.remove(obj);
            obj.reset();
            freeSources.add(obj);
        }
    }

    boolean checkSize() { ... }
}

far release.jpg
 
Ку

В двух словах:
VM крашить нельзя. "Молча ничего не делать" тоже не то, а то заморочишься с багами.
чё надо, это - явно инвалидировать пул при разрушении контекста и кидать исключения при обращении к нему.


NativeObjectPool при создании регистрируется в Context, при Context.destroy() он получает invalidate(), все методы проверяют valid.

Вместо игнорирования вызовов или краша JVM, можешь вводить состояние инвалидности

Код:
Expand Collapse Copy
class NativeObjectPool {
    private boolean valid = true;

    void invalidate() {
        valid = false;
        // можно ещё подчистить внутренние структуры
        obtainedObjects.clear();
        freeObjects.clear();
    }

    NativeObject obtain() {
        if (!valid) {
            throw new IllegalStateException("Pool is invalid (context destroyed)");
        }
        ...
    }

    void free(NativeObject obj) {
        if (!valid) {
            throw new IllegalStateException("Pool is invalid (context destroyed)");
        }
        ...
    }
}
 
NativeObjectPool при создании регистрируется в Context, при Context.destroy() он получает invalidate(), все методы проверяют valid.
У меня в этом и загвоздка. Всю структуру можно представить как 3 отдельных модуля, где первый - абстрактное апи/модель, 2 - стандартная имплементация, 3 - platform-specific имплементация

Сам по себе Context это API, но под капотом он PlatformContext из platform-specific имплементации, а вот NativeObjectPool - из стандартной имплементации. Я стараюсь придерживаться еще того, что-бы не перемешивать их туда сюда и каждый модуль не зависил от другого(за исключением зависимости от API), из-за этого такое не прокатит скорее всего. У меня только как мысль пришёл в пример какой-то несвязанный механизм по типу добавления в Context метода с интерфейсом для регистрации любых объектов требующих инвалидацию, и при уничтожении контекста он просто вызывает все объекты которые само-"зарегались", в общем список коллбэков какой-то

Может быть как-то иначе можно всё это провернут?..
 
Назад
Сверху Снизу