co to jest nielegalny dostęp odblaskowy

126

Istnieje wiele pytań dotyczących nielegalnego dostępu odblaskowego w Javie 9.

To, czego nie mogę znaleźć, ponieważ Google wypluwa tylko ludzi próbujących obejść komunikaty o błędach, to właśnie jest nielegalny dostęp odblaskowy.

Moje pytanie jest dość proste:

Co definiuje nielegalny dostęp odblaskowy i jakie okoliczności powodują ostrzeżenie?

Doszedłem do wniosku, że ma to coś wspólnego z zasadami hermetyzacji, które zostały wprowadzone w Javie 9, ale jak to wszystko się łączy i co powoduje ostrzeżenie, w którym scenariuszu nie mogę znaleźć wyjaśnienia.

Tschallacka
źródło
2
to również może Cię zainteresować: jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html
Edwin

Odpowiedzi:

54

Oprócz zrozumienia dostępów między modułami i ich odpowiednich pakietów. Uważam, że sedno tego leży w systemie modułowym # Relaxed-strong-encapsulation i wybrałbym tylko odpowiednie części, aby spróbować odpowiedzieć na pytanie.

Co definiuje nielegalny dostęp odblaskowy i jakie okoliczności powodują ostrzeżenie?

Aby ułatwić migrację do Java-9, można złagodzić silną enkapsulację modułów.

  • Implementacja może zapewniać dostęp statyczny , tj. Poprzez skompilowany kod bajtowy.

  • Może zapewnić sposób wywołania swojego systemu wykonawczego z jednym lub większą liczbą pakietów jednego lub więcej jego modułów otwartych na kod we wszystkich nienazwanych modułach , tj. Na kod w ścieżce klas. Jeśli system czasu wykonywania jest wywoływany w ten sposób i jeśli to zrobi, niektóre wywołania interfejsów API odbicia zakończą się powodzeniem tam, gdzie w przeciwnym razie zakończyłyby się niepowodzeniem.

W takich przypadkach faktycznie kończyło się na utworzeniu dostępu refleksyjnego, który jest „nielegalny”, ponieważ w czysto modularnym świecie nie miałeś takiego dostępu.

Jak to wszystko się układa i co powoduje ostrzeżenie w jakim scenariuszu?

To złagodzenie enkapsulacji jest kontrolowane w czasie wykonywania przez nową opcję programu uruchamiającego, --illegal-accessktóra domyślnie w Java9 jest równa permit. Te permit, zapewnia tryb

Pierwsza operacja dostępu odblaskowego do takiego opakowania powoduje wydanie ostrzeżenia, ale po tym czasie żadne ostrzeżenia nie są emitowane. To pojedyncze ostrzeżenie opisuje, jak włączyć dalsze ostrzeżenia. Tego ostrzeżenia nie można pominąć.

Tryby można konfigurować za pomocą wartości debug(komunikat, jak również śledzenie stosu dla każdego takiego dostępu), warn(komunikat dla każdego takiego dostępu) i deny(wyłącza takie operacje).


Niewiele rzeczy do debugowania i naprawiania w aplikacjach to: -

  • Uruchom go z, --illegal-access=denyaby poznać i uniknąć otwierania pakietów z jednego modułu do drugiego bez deklaracji modułu zawierającej taką dyrektywę ( opens) lub jawnego użycia --add-opensargumentu VM.
  • Statyczne odniesienia ze skompilowanego kodu do wewnętrznych interfejsów API JDK można zidentyfikować za pomocą jdepsnarzędzia z --jdk-internalsopcją

Komunikat ostrzegawczy generowany w przypadku wykrycia nielegalnej operacji dostępu odblaskowego ma następującą postać:

WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

gdzie:

$PERPETRATOR jest w pełni kwalifikowaną nazwą typu zawierającą kod, który wywołał daną operację refleksyjną oraz źródło kodu (tj. ścieżkę do pliku JAR), jeśli jest dostępne, oraz

$VICTIM jest ciągiem opisującym element członkowski, do którego uzyskiwany jest dostęp, w tym w pełni kwalifikowaną nazwą otaczającego typu

Pytania do takiego przykładowego ostrzeżenia: = JDK9: Wystąpiła nielegalna operacja dostępu odblaskowego. org.python.core.PySystemState

Ostatnia i ważna uwaga, próbując upewnić się, że nie napotkasz takich ostrzeżeń i będziesz bezpieczny w przyszłości, wszystko, co musisz zrobić, to upewnić się, że twoje moduły nie wykonują tych nielegalnych odblaskowych wejść. :)

Naman
źródło
21

Znalazłem artykuł Oracle dotyczący systemu modułów Java 9

Domyślnie typ w module nie jest dostępny dla innych modułów, chyba że jest to typ publiczny i wyeksportujesz jego pakiet. Ujawniasz tylko te pakiety, które chcesz ujawnić. W Javie 9 dotyczy to również odbicia.

Jak wskazano na https://stackoverflow.com/a/50251958/134894 , różnice między AccessibleObject#setAccessibleJDK8 i JDK9 są pouczające. W szczególności dodano JDK9

Ta metoda może być używana przez obiekt wywołujący w klasie C, aby umożliwić dostęp do elementu członkowskiego deklarującego klasę D, jeśli którykolwiek z następujących blokad:

  • C i D są w tym samym module.
  • Członek jest publiczny, a D jest publiczny w pakiecie, który moduł zawierający D eksportuje przynajmniej do modułu zawierającego C.
  • Element członkowski jest chroniony statycznie, D jest publiczny w pakiecie, którego moduł zawierający D eksportuje co najmniej do modułu zawierającego C, a C jest podklasą D.
  • D znajduje się w pakiecie, który moduł zawierający D otwiera się przynajmniej na moduł zawierający C. Wszystkie pakiety w nienazwanych i otwartych modułach są otwarte dla wszystkich modułów, więc ta metoda zawsze kończy się sukcesem, gdy D jest w nienazwanym lub otwartym module.

który podkreśla znaczenie modułów i ich eksport (w Javie 9)

ptomli
źródło
2
Więc jeśli przeczytam ten artykuł, poprawne modyfikowanie właściwości prywatnych w eksportowanych klasach jest nie na miejscu. Modyfikować można tylko właściwości chronione i publiczne. Teraz nie obchodzi mnie zbytnio wewnętrzne eksporty Java, ale bardziej biblioteki zewnętrzne, w których czasami potrzebuję dostępu do zmiennej prywatnej, aby ustawić określoną wartość. Nie byłoby to już możliwe w tym schemacie, gdyby zdefiniował się jako moduł, czy to prawda?
Tschallacka
1
Nie mam bezpośredniego doświadczenia z tym, ale tak rozumiem i przeczytałem obok artykułu wymienionego w innym miejscu ( jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html ), który wydaje się być walizka. Uruchom swoją –illegal-access=permit
maszynę
1
Cóż, to uczyni rzeczy bardziej interesującymi, próbując sprawić, by niektóre rzeczy działały, gdy zdecydują się przejść na drogę modułową. Przed nami super zabawa.
Tschallacka
1
Dla różnych wartościfun
ptomli
Przyjąłem drugą odpowiedź, ponieważ zawierała więcej wyjaśnień i była bardziej odpowiedzią na pytanie, ale niestety nie mogę przyjąć dwóch odpowiedzi.
Tschallacka
13

Wystarczy spojrzeć na setAccessible()metodę używaną do uzyskiwania dostępu do privatepól i metod:

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

https://docs.oracle.com/javase/9/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

Teraz potrzeba dużo więcej warunków, aby ta metoda działała. Jedynym powodem, dla którego nie psuje prawie całego starszego oprogramowania, jest to, że moduły generowane automatycznie ze zwykłych plików JAR są bardzo liberalne (otwieraj i eksportuj wszystko dla wszystkich).

user158037
źródło
1

Jeśli chcesz przejść z opcją add-open, oto polecenie, aby znaleźć moduł zapewniający który pakiet ->

java --list-modules | tr @ " " | awk '{ print $1 }' | xargs -n1 java -d

nazwa modułu będzie wyświetlana z @, a nazwy pakietów bez niego

UWAGA: testowano z JDK 11

WAŻNE: oczywiście lepiej niż dostawca pakietu nie robi nielegalnego dostępu

Carlos Saltos
źródło