CME is Bad

Модификация для отладки исключений, связанных с одновременным изменением данных (Concurrent Modification Exceptions) и выходом за пределы допустимого диапазона индексов (Index Out of Bounds Exceptions).

21,29k

Быстрое задание

Как далеко вы сможете убежать, прежде чем вас поймают толпы?

CME is Bad

Резюме

Игроки и разработчики модпаков иногда сталкиваются с вылетами игры из-за `ConcurrentModificationExceptions` (CME) и `IndexOutOfBoundsExceptions` (IOOBE), которые предоставляют только трассировку стека текущего потока, и сложно определить, какой мод их вызывает. Вот один из сбоев, вызванный SimpleReloadInstance в Forge версии 1.20.1:

CME от SimpleReloadInstance

Вот для чего и разработан этот мод. Игроки, которые установят этот мод и правильно добавят javaagent в аргумент JVM, получат полный лог истории изменений определенной коллекции:

журнал этого мода

Применение

Сначала добавьте этот jar-файл в папку mods.

Во-вторых, отредактируйте аргумент виртуальной машины Java в вашем лаунчере. Добавьте `-javaagent:mods/CMESuckMyDuck-`. .jar= ; ; ; `.

Наконец, запустите игру, поиграйте и дождитесь сбоя.

Использование в других проектах на Java

Этот мод можно использовать не только для отладки Minecraft, но и для отладки других Java-проектов. Аналогично Minecraft. Единственное отличие заключается в том, что вам нужно добавить gson и asm.jar в classpath (`-cp`) перед javaagent, а также добавить наш `CMESuckMyDuck- Добавить `.jar` в classpath после javaagent.

аргументы

Полное имя класса, содержащего контейнер, который вы хотите отслеживать. Используйте `` вместо `.` (также известный как внутреннее имя класса).

Имя поля контейнера в целевом классе, который вы хотите отслеживать. Для Forge используйте имя SRG. Для Fabric используйте имя промежуточного контейнера. Для NeoForge используйте официальное имя.

В настоящее время мы поддерживаем только три контейнера: `List`, `Set`, `Map`. Этот аргумент указывает тип отслеживаемого контейнера.

`static` или `nonstatic`. Этот аргумент указывает, является ли контейнер статическим или нестатическим полем.

Как получить и

Начнём с примера.

Для начала взгляните на трассировку стека CME/IOOBE:

Замените это описанием.

Во-вторых, изучите исходный код SoundEngine и определите, в каком контейнере возникла эта проблема:

Замените это описанием.

Теперь мы знаем, что нам следует отслеживать карту `field_217942_m` (`instanceToChannel` в `SoundEngine`). Продолжайте.

В-третьих, установите этот мод и добавьте "`-javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/client/audio/SoundEngine;field_217942_m;Map;nonstatic`" в аргумент виртуальной машины Java. Перезапустите игру и дождитесь следующего сбоя.

Наконец, откройте файл `CMESuckMyDuck.log`, и вы увидите, какой поток и какой модификатор одновременно внесли изменения в контейнер.

Примеры (аргументы JVM)

Исключение ConcurrentModificationException от SoundEngine в среде Forge 1.16.5

`-javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/client/audio/SoundEngine;field_217942_m;Map;nonstatic`

Исключение ConcurrentModificationException при использовании PotionBrewing в среде Forge 1.20.1

`-javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/world/item/alchemy/PotionBrewing;f_43494_;List;static`

Исключение ArrayIndexOutOfBoundsException из Zeta mod

`-javaagent:CMESuckMyDuck-1.0.0.jar=org/violetmoon/zetaimplforge/event/ForgeZetaEventBus;convertedHandlers;Map;nonstatic`

Другие варианты

Уровень журнала

Используйте системное свойство `-Dcme_suck_my_duck.log_level=` ` для установки пользовательского уровня логирования.

Значение по умолчанию — 1, что означает отсутствие отладочных сообщений в журнале.

Пользователи могут установить значение 0 для вывода отладочных сообщений, что не рекомендуется — функции запросов, такие как Map#get, Set#containsAll, также будут записываться в лог при значении 0, что значительно увеличит размер файла.

Версия API ASM (v1.0.2+)

Для обеспечения совместимости с последней версией Minecraft этот мод скомпилирован с использованием ассемблерного кода версии 9.7. Для более старых версий Minecraft (например, 1.12.2) операции на уровне API, такие как ASM_9, не могут быть применены, поэтому игрокам необходимо использовать `-Dcme_suck_my_duck.asm_api_version=`. ` для изменения совместимости версий ASM API. Например, для версии игры 1.12.2: `-Dcme_suck_my_duck.asm_api_version=5`.

Максимальное количество записей в файле (v1.0.3+)

Поскольку мы заметили, что при сбое последние несколько операций в журнале гораздо важнее предыдущих, наш мод после версии 1.0.3 использует стратегию постраничной навигации, и в конце сохраняются только две последние страницы. Количество записей в журнале на каждой странице (то есть количество стеков вызовов операций) фиксировано, значение по умолчанию — 500. Игроки могут использовать `-Dcme_suck_my_duck.file_max_entries=` ` для изменения максимального количества элементов на странице.

Белый список конструкторов (v1.0.3+)

Иногда контейнер определенного класса используется во многих местах (например, CompoundTag#tags). Прямое использование этого модификатора приведет к слишком длинному логу или замене допустимого содержимого последующими операциями. Поэтому игроки могут указать дополнительный белый список конструкторов для отслеживания соответствующего контейнера в соответствующем классе конкретного модуля. По умолчанию он пуст, то есть белого списка нет. Игроки могут использовать `-Dcme_suck_my_duck.whitelist_constructor_stacktrace=` ` для его указания. Если какая-либо строка в трассировке стека, где создается контейнер, содержит содержимое строки белого списка, контейнер будет отслеживаться; в противном случае, контейнер не будет отслеживаться, что значительно упрощает информацию в логах.

Преобразование в потокобезопасный режим (v1.0.4+)

Используйте системное свойство `-Dcme_suck_my_duck.transform_to_thread_safe=true`, чтобы преобразовать поле в потокобезопасный контейнер.

Это НЕ рекомендуется, если только вам не нравится медленная работа и вы не хотите исправлять проблему.

Метод инъекции (v1.0.4+)

Используйте системное свойство `-Dcme_suck_my_duck.inject_method=true` для переключения в режим инъекции.

Если задано, следует использовать `-javaagent:CMESuckMyDuck-`. .jar= ; И всякий раз, когда вызывается этот метод, вы будете получать трассировку стека в лог-файлах.

Игнорировать потоки (v1.0.5+)

Используйте системное свойство `-Dcme_suck_my_duck.ignore_threads=` ; ; ;...` для игнорирования потока, который, как ожидается, будет изменять данный контейнер (или вызывать данный метод). Например, `-Dcme_suck_my_duck.ignore_threads="Server thread"`.

Прекратите запись логов на ранней стадии (v1.0.7+)

Используйте системное свойство `-Dcme_suck_my_duck.stop_logging_if_exception_created=false`, чтобы остановить запись логов в случае возникновения критической ошибки.

Программа обновления идентификаторов трассировки (v1.0.8+)

Используйте системное свойство `-Dcme_suck_my_duck.trace_id_updater=` ; ` для обновления идентификатора трассировки при вызове указанного метода. Это может быть полезно в режиме внедрения.

Мониторинг локальных переменных (версия 1.1.0+)

Используйте системное свойство `-Dcme_suck_my_duck.local_var_index=` ` для мониторинга локальной переменной по заданному индексу в данном методе.

Если задано, следует использовать `-javaagent:CMESuckMyDuck-`. .jar= ; ; Кстати, индекс может быть повторно использован различными локальными переменными. Поэтому вам, возможно, придётся использовать `-Dcme_suck_my_duck.match_local_index=`. ` для указания порядкового номера ASTORE операция, указывающая, какую локальную переменную следует отслеживать.

Заключение

Мне нравится есть утку по-пекински. Это так вкусно!

Фото Полины Танкилевич: https://www.pexels.com/photo/close-up-photo-of-savory-peking-duck-dish-on-a-ceramic-bowl-5848604/

ОБЪЯВЛЕНИЯ
RU — Russian