การเข้าถึงแบบสะท้อนแสงที่ผิดกฎหมายคืออะไร


128

มีคำถามมากมายเกี่ยวกับการเข้าถึงแบบสะท้อนแสงที่ผิดกฎหมายใน Java 9

ตอนนี้สิ่งที่ฉันไม่สามารถหาได้เนื่องจาก Google ที่แพร่กระจายออกไปคือผู้คนที่พยายามแก้ไขข้อความแสดงข้อผิดพลาดนั่นคือสิ่งที่การเข้าถึงแบบสะท้อนแสงที่ผิดกฎหมายเป็นจริง

ดังนั้นคำถามของฉันค่อนข้างง่ายคือ:

อะไรกำหนดการเข้าถึงแบบสะท้อนแสงที่ผิดกฎหมายและสถานการณ์ใดที่ทำให้เกิดคำเตือน

ฉันได้รวบรวมแล้วว่ามันมีส่วนเกี่ยวข้องกับหลักการห่อหุ้มที่นำมาใช้ใน Java 9 แต่มันรวมเข้าด้วยกันอย่างไรและสิ่งที่ทำให้เกิดคำเตือนในสถานการณ์ที่ฉันไม่สามารถหาคำอธิบายได้


2
สิ่งนี้อาจสนใจคุณเช่นกัน: jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html
Edwin

คำตอบ:


56

นอกเหนือจากความเข้าใจในการเข้าถึงระหว่างโมดูลและแพ็คเกจตามลำดับ ฉันเชื่อว่าจุดสำคัญของมันอยู่ที่Module System # Relaxed-strong-encapsulationและฉันจะเลือกส่วนที่เกี่ยวข้องกับเชอร์รี่เพื่อลองตอบคำถาม

อะไรกำหนดการเข้าถึงแบบสะท้อนแสงที่ผิดกฎหมายและสถานการณ์ใดที่ทำให้เกิดคำเตือน

เพื่อช่วยในการโอนย้ายไปยัง Java-9 การห่อหุ้มโมดูลที่แน่นหนาสามารถผ่อนคลายได้

  • การใช้งานอาจให้การเข้าถึงแบบคงที่กล่าวคือโดย bytecode ที่คอมไพล์

  • อาจจัดเตรียมวิธีการเรียกใช้ระบบรันไทม์โดยมีแพ็กเกจอย่างน้อยหนึ่งแพ็กเกจของโมดูลอย่างน้อยหนึ่งโมดูลที่เปิดขึ้นเพื่อโค้ดในโมดูลที่ไม่มีชื่อทั้งหมดนั่นคือเพื่อโค้ดบนคลาสพา ธ หากมีการเรียกใช้ระบบรันไทม์ด้วยวิธีนี้และหากทำเช่นนั้นการเรียกใช้ API การสะท้อนบางอย่างจะประสบความสำเร็จมิฉะนั้นจะล้มเหลว

ในกรณีเช่นนี้คุณลงเอยด้วยการเข้าถึงแบบสะท้อนแสงซึ่ง"ผิดกฎหมาย"เนื่องจากในโลกโมดูลาร์ที่บริสุทธิ์คุณไม่ได้ตั้งใจที่จะเข้าถึงเช่นนั้น

มันรวมตัวกันอย่างไรและอะไรทำให้เกิดคำเตือนในสถานการณ์ใด

การผ่อนคลายของการห่อหุ้มนี้มีการควบคุมที่รันไทม์โดยเป็นตัวเลือกที่ปล่อยใหม่--illegal-accessซึ่งเริ่มต้นโดยใน Java9 permitเท่ากับ permitโหมดเพื่อให้แน่ใจ

การดำเนินการเข้าถึงแบบสะท้อนแสงครั้งแรกไปยังแพ็คเกจดังกล่าวทำให้ต้องออกคำเตือน แต่จะไม่มีการออกคำเตือนหลังจากจุดนั้น คำเตือนเดียวนี้อธิบายถึงวิธีการเปิดใช้งานคำเตือนเพิ่มเติม ไม่สามารถระงับคำเตือนนี้ได้

โหมดต่างๆสามารถกำหนดค่าได้ด้วยค่าdebug(ข้อความเช่นเดียวกับ stacktrace สำหรับทุกการเข้าถึงดังกล่าว) warn(ข้อความสำหรับแต่ละการเข้าถึงดังกล่าว) และdeny(ปิดใช้งานการดำเนินการดังกล่าว)


มีบางสิ่งที่ควรแก้ไขข้อบกพร่องและแก้ไขแอปพลิเคชัน ได้แก่ : -

  • เรียกใช้ด้วย--illegal-access=denyเพื่อทำความรู้จักและหลีกเลี่ยงการเปิดแพ็กเกจ ing จากโมดูลหนึ่งไปยังอีกโมดูลหนึ่งโดยไม่มีการประกาศโมดูลรวมถึง directive ( opens) หรือการใช้--add-opensVM arg อย่างชัดเจน
  • การอ้างอิงแบบคงที่จากโค้ดที่คอมไพล์ไปยัง JDK-internal APIs สามารถระบุได้โดยใช้jdepsเครื่องมือพร้อม--jdk-internalsตัวเลือก

ข้อความเตือนที่ออกเมื่อตรวจพบการดำเนินการสะท้อนแสงที่ผิดกฎหมายมีรูปแบบต่อไปนี้:

WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

ที่อยู่:

$PERPETRATOR คือชื่อที่มีคุณสมบัติครบถ้วนของประเภทที่มีรหัสที่เรียกใช้การดำเนินการสะท้อนแสงที่เป็นปัญหาบวกกับแหล่งรหัส (เช่นเส้นทางไฟล์ JAR) ถ้ามีและ

$VICTIM เป็นสตริงที่อธิบายถึงสมาชิกที่ถูกเข้าถึงรวมถึงชื่อแบบเต็มของชนิดการปิดล้อม

คำถามสำหรับคำเตือนตัวอย่างดังกล่าว: = JDK9: เกิดการดำเนินการเข้าถึงแบบสะท้อนแสงที่ผิดกฎหมาย org.python.core.PySystemState

หมายเหตุสุดท้ายและสำคัญในขณะที่พยายามทำให้แน่ใจว่าคุณจะไม่เผชิญกับคำเตือนดังกล่าวและปลอดภัยในอนาคตสิ่งที่คุณต้องทำคือตรวจสอบให้แน่ใจว่าโมดูลของคุณไม่ได้ทำการเข้าถึงแบบสะท้อนแสงที่ผิดกฎหมาย :)


23

มีบทความ Oracle ที่ฉันพบเกี่ยวกับระบบโมดูล Java 9

โดยค่าเริ่มต้นประเภทในโมดูลจะไม่สามารถเข้าถึงโมดูลอื่นได้เว้นแต่จะเป็นประเภทสาธารณะและคุณส่งออกแพ็กเกจ คุณเปิดเผยเฉพาะแพ็คเกจที่คุณต้องการเปิดเผย ด้วย Java 9 สิ่งนี้ยังใช้กับการสะท้อนแสง

ตามที่ระบุไว้ในhttps://stackoverflow.com/a/50251958/134894ความแตกต่างระหว่างAccessibleObject#setAccessibleสำหรับ JDK8 และ JDK9 นั้นมีคำแนะนำ โดยเฉพาะเพิ่ม JDK9

วิธีนี้อาจใช้โดยผู้เรียกในคลาส C เพื่อเปิดใช้งานการเข้าถึงสมาชิกของการประกาศคลาส D หากมีการระงับข้อใดข้อหนึ่งต่อไปนี้:

  • C และ D อยู่ในโมดูลเดียวกัน
  • สมาชิกเป็นแบบสาธารณะและ D เป็นแบบสาธารณะในแพ็กเกจที่โมดูลที่มี D ส่งออกไปยังโมดูลที่มี C เป็นอย่างน้อย
  • สมาชิกได้รับการป้องกันแบบคงที่ D เป็นแบบสาธารณะในแพ็คเกจที่โมดูลที่มี D ส่งออกไปยังโมดูลที่มี C เป็นอย่างน้อยและ C เป็นคลาสย่อยของ D
  • D อยู่ในแพ็กเกจที่โมดูลที่มี D เปิดเป็นอย่างน้อยโมดูลที่มี C แพ็กเกจทั้งหมดในโมดูลที่ไม่มีชื่อและโมดูลเปิดจะเปิดสำหรับโมดูลทั้งหมดดังนั้นวิธีนี้จะประสบความสำเร็จเสมอเมื่อ D อยู่ในโมดูลที่ไม่มีชื่อหรือโมดูลที่เปิดอยู่

ซึ่งเน้นความสำคัญของโมดูลและการส่งออก (ใน Java 9)


2
ดังนั้นถ้าฉันอ่านบทความนั้นการแก้ไขคุณสมบัติส่วนตัวในคลาสที่ส่งออกอย่างถูกต้องจะไม่อยู่ในตาราง คุณสมบัติที่ได้รับการป้องกันและสาธารณะเท่านั้นที่สามารถแก้ไขได้ ตอนนี้ฉันไม่ได้สนใจเกี่ยวกับการส่งออกภายใน java มากนัก แต่มีข้อมูลเพิ่มเติมเกี่ยวกับไลบรารีของบุคคลที่สามซึ่งบางครั้งฉันต้องเข้าถึงตัวแปรส่วนตัวเพื่อตั้งค่าเป็นค่าเฉพาะ นั่นจะเป็นไปไม่ได้อีกต่อไปในโครงร่างนี้หากจะกำหนดตัวเองเป็นโมดูลนั้นถูกต้องหรือไม่?
Tschallacka

1
ฉันไม่มีประสบการณ์โดยตรงกับสิ่งนั้น แต่นั่นจะเป็นความเข้าใจของฉันและอ่านควบคู่ไปกับบทความที่กล่าวถึงที่อื่น ( jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html ) ซึ่งดูเหมือนจะเป็น กรณี. เปิดตัว JVM ของคุณด้วย–illegal-access=permit...
ptomli

1
นั่นจะทำให้สิ่งต่าง ๆ น่าสนใจยิ่งขึ้นโดยพยายามทำให้บางสิ่งทำงานได้ดีขึ้นเมื่อพวกเขาตัดสินใจไปที่โมดูล สนุกสุด ๆ ไปเลย
Tschallacka

1
สำหรับค่าต่างๆของfun
ptomli

ฉันยอมรับคำตอบอื่นเพราะมันให้คำอธิบายที่มากกว่าและเป็นคำตอบสำหรับคำถามมากกว่า แต่น่าเศร้าที่ฉันไม่สามารถยอมรับคำตอบสองคำตอบได้
Tschallacka

13

เพียงดูsetAccessible()วิธีการที่ใช้ในการเข้าถึงprivateฟิลด์และวิธีการ:

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-

ขณะนี้มีเงื่อนไขเพิ่มเติมมากมายสำหรับวิธีนี้ในการทำงาน เหตุผลเดียวที่ไม่ทำลายซอฟต์แวร์รุ่นเก่าเกือบทั้งหมดคือโมดูลที่สร้างขึ้นโดยอัตโนมัติจาก JAR ธรรมดานั้นได้รับอนุญาตอย่างมาก (เปิดและส่งออกทุกอย่างสำหรับทุกคน)


1

หากคุณต้องการใช้ตัวเลือก add-open ต่อไปนี้เป็นคำสั่งเพื่อค้นหาว่าโมดูลใดมีแพ็คเกจ ->

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

ชื่อของโมดูลจะแสดงด้วย @ ในขณะที่ชื่อของแพ็กเกจที่ไม่มีมัน

หมายเหตุ: ทดสอบด้วย JDK 11

สิ่งสำคัญ: เห็นได้ชัดว่าดีกว่าผู้ให้บริการแพ็กเกจไม่ได้ทำการเข้าถึงที่ผิดกฎหมาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.