truy cập phản chiếu bất hợp pháp là gì


126

Có rất nhiều câu hỏi xung quanh việc truy cập phản chiếu bất hợp pháp trong Java 9.

Bây giờ, điều tôi không thể tìm thấy bởi vì tất cả những gì Google phát hiện ra là mọi người đang cố gắng giải quyết các thông báo lỗi, truy cập phản ánh bất hợp pháp thực sự là gì.

Vì vậy, câu hỏi của tôi khá đơn giản là:

Điều gì xác định một truy cập phản chiếu bất hợp pháp và những trường hợp nào kích hoạt cảnh báo?

Tôi đã thu thập được rằng nó có liên quan gì đó đến các nguyên tắc đóng gói đã được giới thiệu trong Java 9, nhưng cách tất cả kết nối với nhau và điều gì kích hoạt cảnh báo trong tình huống mà tôi không thể tìm ra lời giải thích.


2
điều này có thể bạn cũng quan tâm: jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html
Edwin

Câu trả lời:


54

Ngoài sự hiểu biết về các truy cập giữa các mô-đun và các gói tương ứng của chúng. Tôi tin rằng mấu chốt của nó nằm ở Hệ thống mô-đun # Thư giãn-mạnh-đóng gói và tôi sẽ chỉ chọn những phần có liên quan của nó để thử và trả lời câu hỏi.

Điều gì xác định một truy cập phản chiếu bất hợp pháp và những trường hợp nào kích hoạt cảnh báo?

Để hỗ trợ việc di chuyển sang Java-9, việc đóng gói mạnh mẽ các mô-đun có thể được nới lỏng.

  • Việc triển khai có thể cung cấp quyền truy cập tĩnh , tức là bằng mã bytecode đã được biên dịch.

  • Có thể cung cấp một phương tiện để gọi hệ thống thời gian chạy của nó với một hoặc nhiều gói của một hoặc nhiều mô-đun của nó được mở để mã trong tất cả các mô-đun chưa được đặt tên , tức là mã trên classpath. Nếu hệ thống thời gian chạy được gọi theo cách này và nếu bằng cách này, một số lệnh gọi của các API phản chiếu thành công nếu không thì chúng sẽ không thành công.

Trong những trường hợp như vậy, bạn thực sự đã thực hiện một truy cập phản chiếu"bất hợp pháp" vì trong một thế giới mô-đun thuần túy, bạn không có ý định thực hiện những truy cập như vậy.

Làm thế nào tất cả kết hợp với nhau và điều gì kích hoạt cảnh báo trong trường hợp nào?

Việc nới lỏng đóng gói này được kiểm soát trong thời gian chạy bởi một tùy chọn trình khởi chạy mới --illegal-accessmà theo mặc định trong Java9 bằng permit. Các permitĐảm bảo chế độ

Thao tác truy cập phản chiếu đầu tiên đối với bất kỳ gói nào như vậy gây ra cảnh báo được đưa ra, nhưng không có cảnh báo nào được đưa ra sau thời điểm đó. Cảnh báo duy nhất này mô tả cách bật các cảnh báo khác. Cảnh báo này không thể bị dập tắt.

Các chế độ có thể được cấu hình với các giá trị debug(thông báo cũng như ngăn xếp cho mỗi lần truy cập như vậy), warn(thông báo cho mỗi lần truy cập như vậy) và deny(vô hiệu hóa các hoạt động đó).


Một số điều cần gỡ lỗi và sửa chữa trên các ứng dụng sẽ là: -

  • Chạy nó với --illegal-access=denyđể biết và tránh mở các gói ing từ mô-đun này sang mô-đun khác mà không có khai báo mô-đun bao gồm chỉ thị như vậy ( opens) hoặc sử dụng rõ ràng --add-opensVM arg.
  • Các tham chiếu tĩnh từ mã đã biên dịch tới các API nội bộ JDK có thể được xác định bằng cách sử dụng jdepscông cụ với --jdk-internalstùy chọn

Thông báo cảnh báo được đưa ra khi phát hiện hoạt động truy cập phản chiếu bất hợp pháp có dạng sau:

WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

Ở đâu:

$PERPETRATOR là tên đủ điều kiện của loại chứa mã đã gọi hoạt động phản chiếu được đề cập cùng với nguồn mã (tức là đường dẫn tệp JAR), nếu có, và

$VICTIM là một chuỗi mô tả thành viên đang được truy cập, bao gồm tên đủ điều kiện của loại bao quanh

Câu hỏi cho một cảnh báo mẫu như vậy: = JDK9: Đã xảy ra hoạt động truy cập phản chiếu bất hợp pháp. org.python.core.PySystemState

Lưu ý cuối cùng và quan trọng, trong khi cố gắng đảm bảo rằng bạn không gặp phải những cảnh báo như vậy và an toàn trong tương lai, tất cả những gì bạn cần làm là đảm bảo các mô-đun của bạn không thực hiện những truy cập phản chiếu bất hợp pháp đó. :)


21

Có một bài báo của Oracle tôi tìm thấy liên quan đến hệ thống mô-đun Java 9

Theo mặc định, một loại trong mô-đun không thể truy cập được đối với các mô-đun khác trừ khi đó là loại công khai và bạn xuất gói của nó. Bạn chỉ phơi bày những gói bạn muốn phơi bày. Với Java 9, điều này cũng áp dụng cho phản xạ.

Như đã chỉ ra trong https://stackoverflow.com/a/50251958/134894 , sự khác biệt giữa AccessibleObject#setAccessiblecho JDK8 và JDK9 là mang tính hướng dẫn. Cụ thể, JDK9 đã thêm

Phương thức này có thể được sử dụng bởi người gọi trong lớp C để cho phép truy cập vào thành viên khai báo lớp D nếu có bất kỳ trường hợp nào sau đây:

  • C và D nằm trong cùng một môđun.
  • Thành viên là công khai và D là công khai trong một gói mà mô-đun chứa D xuất sang ít nhất mô-đun chứa C.
  • Thành viên được bảo vệ tĩnh, D là công khai trong một gói mà mô-đun chứa D xuất sang ít nhất mô-đun chứa C và C là một lớp con của D.
  • D nằm trong một gói mà mô-đun chứa D mở cho ít nhất mô-đun chứa C. Tất cả các gói trong mô-đun chưa đặt tên và đang mở đều mở cho tất cả các mô-đun và do đó phương pháp này luôn thành công khi D ở trong một mô-đun mở hoặc không có tên.

trong đó nêu bật tầm quan trọng của các mô-đun và việc xuất chúng (trong Java 9)


2
Vì vậy, nếu tôi đọc bài viết đó, việc sửa đổi chính xác các thuộc tính private trong các lớp đã xuất là điều không cần bàn cãi. Chỉ các thuộc tính được bảo vệ và công khai mới có thể được sửa đổi. Bây giờ tôi không quan tâm nhiều đến việc xuất nội bộ của java, mà quan tâm nhiều hơn đến các thư viện của bên thứ ba, nơi đôi khi tôi cần quyền truy cập vào một biến private để được đặt thành một giá trị cụ thể. Điều đó sẽ không thể xảy ra nữa trong lược đồ này nếu nó tự định nghĩa là một mô-đun, có đúng không?
Tschallacka

1
Tôi không có kinh nghiệm trực tiếp về điều đó, nhưng đó là sự hiểu biết của tôi và đọc cùng với bài viết được đề cập ở nơi khác ( jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html ) có vẻ như trường hợp. Khởi chạy JVM của bạn với –illegal-access=permit...
ptomli

1
Điều đó sẽ khiến mọi thứ trở nên thú vị hơn khi cố gắng làm cho mọi thứ hoạt động cho một số thứ khi họ quyết định chuyển sang cách mô-đun. Thời gian siêu vui vẻ phía trước.
Tschallacka

1
Đối với các giá trị khác nhau củafun
ptomli

Tôi chấp nhận câu trả lời khác vì nó cung cấp một lời giải thích nhiều hơn và là một câu trả lời cho câu hỏi nhưng đáng buồn là tôi không thể chấp nhận hai câu trả lời.
Tschallacka

13

Chỉ cần nhìn vào setAccessible()phương thức được sử dụng để truy cập privatecác trường và phương thức:

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-

Bây giờ có rất nhiều điều kiện cần thiết để phương pháp này hoạt động. Lý do duy nhất khiến nó không phá vỡ hầu hết các phần mềm cũ là các mô-đun được tạo tự động từ các JAR đơn giản rất dễ sử dụng (mở và xuất mọi thứ cho mọi người).


1

Nếu bạn muốn sử dụng tùy chọn add-open, đây là lệnh để tìm mô-đun nào cung cấp gói nào ->

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

tên của mô-đun sẽ được hiển thị với @ trong khi tên của các gói không có nó

LƯU Ý: đã thử nghiệm với JDK 11

QUAN TRỌNG: rõ ràng là tốt hơn so với việc nhà cung cấp gói không thực hiện việc truy cập bất hợp pháp

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.