openjdk.ruOpenJDK на русском

JEP 176: Mechanical Checking of Caller-Sensitive Methods

Машинная проверка caller-sensitive-методов

AuthorsJohn Rose, Christian Thalinger, Mandy Chung
ОтветственныйJohn Rose
ТипFeature
ОбластьJDK
СтатусClosed / Delivered
Выпуск8
Обсуждениеcore dash libs dash dev at openjdk dot java dot net
ТрудоёмкостьS
РецензентыAlan Bateman, Sean Mullan
ОдобренBrian Goetz
Создан2013/02/05 20:00
Обновлён2017/10/17 22:53
Задача8046166

Аннотация

Повысить безопасность реализации дескрипторов методов (method handles) в JDK: заменить существующий вручную поддерживаемый список caller-sensitive-методов (методов, поведение которых зависит от вызывающего класса) механизмом, который точно определяет такие методы и позволяет надёжно находить вызывающих их.

Что не является целью

Предлагаемая аннотация @CallerSensitive может пригодиться для других видов анализа или аудита, но такая работа выходит за рамки этого JEP.

Также не ставится цель предоставить публичный API для несистемного кода.

Описание

Caller-sensitive-метод меняет своё поведение в зависимости от класса, который его непосредственно вызвал. Класс вызывающего он определяет, вызывая метод sun.reflect.Reflection.getCallerClass.

Большинство caller-sensitive-методов так или иначе действуют как агент вызывающего. При вызове через рефлексию такие методы нужно обрабатывать особым образом, чтобы метод getCallerClass возвращал класс фактического вызывающего, а не какой-либо класс самого механизма рефлексии. Логика этого основана на поиске совпадений по вручную поддерживаемому списку caller-sensitive-методов, а такой подход ненадёжен и труден в сопровождении.

Чтобы улучшить ситуацию, мы пометим все caller-sensitive-методы в JDK внутренней аннотацией @sun.reflect.CallerSensitive. JVM будет отслеживать эту аннотацию и, опционально, обеспечивать инвариант: метод sun.reflect.Reflection.getCallerClass может сообщить, кто вызвал метод, только если этот метод помечен данной аннотацией. При разрешении MemberName JVM будет устанавливать новый бит caller-sensitive, а метод java.lang.invoke.MethodHandleNatives.isCallerSensitive с пакетным доступом будет доработан так, чтобы запрашивать этот бит напрямую, а не сверяться со списком имён методов.

Аннотация @CallerSensitive может пригодиться и для других целей, например для отслеживания появления новых caller-sensitive-методов или для аналогичной специальной обработки в методе sun.reflect.misc.MethodUtil.invoke.

В JDK есть два места, где методы просматривают фреймы стека дальше своих непосредственных вызывающих. Чтобы надёжно обеспечить проверку caller-sensitive, мы предлагаем следующие изменения:

  • Объявить метод SecurityManager.checkMemberAccess устаревшим, чтобы в будущем выпуске изменить его так, что он будет безусловно выбрасывать исключение. Метод checkMemberAccess требует, чтобы фрейм вызывающего находился на глубине стека четыре, а это хрупкое требование, которое трудно обеспечить.

  • Изменить java.util.logging.Logger так, чтобы он не обходил стек в поисках пакета ресурсов (resource bundle). Этот обход стека задумывался как временная мера, позволяющая контейнерам перейти на использование загрузчика классов контекста. В спецификации уже указано, что он будет удалён в будущем выпуске.

Альтернативы

Добавить аннотацию @CallerSensitive, как описано выше, но использовать её только для проверки вручную поддерживаемого списка методов. Этот вариант был бы улучшением, но проверка аннотации во время выполнения надёжнее.

Тестирование

Существующие наборы тестов хорошо подойдут в качестве позитивных тестов для этой возможности. Нужны новые негативные тесты, выявляющие caller-sensitive-методы, которые не помечены должным образом.

Риски и допущения

Есть небольшой риск, что это изменение вызовет побочные эффекты. Мы предполагаем, что уже запланированное обширное тестирование JDK 8 выявит любые такие проблемы.

Влияние

  • Производительность: мы ожидаем пренебрежимо малого влияния на производительность. JVM уже разбирает аннотации методов, доступные во время выполнения, для JSR 292, и проверка будет относительно дешёвой по сравнению с затратной операцией обхода стека.

  • Совместимость: приложения, которые зависят от обхода стека в классе Logger, перестанут работать.