Inaccesibil în caracteristicile lingvistice ale bytecode-ului java

După ce am lucrat mult timp cu Java bytecode și am efectuat niște cercetări în acest domeniu, vreau să împărtășesc concluziile pe care le-am făcut.







Rularea în constructorul de coduri înainte de a apela un superconstructor sau constructor auxiliar

În limbajul de programare Java ca (în continuare - JPL, din limbajul de programare Java), apel la super-() sau acest lucru () trebuie să fie prima declarație în constructor, dar în Java bytecode (în continuare - JBC, din Codul Byte Java) nu este. Puteți adăuga cod la aceste provocări, în cazul în care sunt îndeplinite următoarele condiții:

  • un alt constructor este numit în continuare;
  • nu este cauzată de o condiție;
  • Înainte de a apela constructorul, câmpurile nu sunt citite și metodele obiectului construit nu sunt apelate. De aici vine următoarea întrebare.

Lucrul cu câmpurile entității înainte de a apela super () sau this ()

Înainte de a șasea versiune în Java, a existat următorul exploit, care a permis să facă cele de mai sus:

Acum, în JPL, o astfel de lucrare cu câmpuri este imposibilă, dar este încă posibil să folosiți JBC.

Selectarea constructorului numit (înainte de Java 7u23)

Java nu permite crearea de astfel de constructori:

Cu toate acestea, înainte de Java 7u23, verificatorul HotSpot VM a ignorat această verificare. Acum este fix.

Crearea unei clase fără constructor deloc

În JPL, acest lucru nu este posibil - cel puțin un constructor, dar întotdeauna moștenit. Folosind JBC, puteți face imposibilă crearea unei instanțe a clasei, chiar dacă folosiți reflecția (deși sun.misc.unsafe încă vă permite să faceți acest lucru).

Crearea metodelor cu aceleași semnături, dar cu diferite tipuri de returnare

În JPL, metodele sunt identificate prin numele și setul de parametri, iar în JBC, metodele sunt de asemenea returnate.

Apelarea excepțiilor verificate fără a specifica aruncarea sau încercarea de construire. captură

Verificând dacă toate excepțiile verificate sunt prinse (sau arătate cu aruncări), execută compilatorul, nu depinde de Java Runtime sau JBC.

Utilizarea invocării metodei dinamice în afara expresiilor lambda

Așa-numitul apel din metodă dinamică poate fi folosit pentru orice, nu doar pentru expresiile lambda. Utilizarea lui permite, de exemplu, schimbarea logicii programului în timpul executării. Multe limbi de programare dinamice bazate pe JBC s-au îmbunătățit datorită acestei instrucțiuni. În JBC, puteți utiliza și expresii lambda în Java 7 atunci când compilatorul nu poate gestiona apelurile din metoda dinamică și JVM ar putea.







Utilizarea identificatorilor care sunt în mod normal interzise

Ați vrut să adăugați un spațiu sau o pauză de linie în numele metodei dvs.? Creați-vă JBC și aveți o depanare de succes! Doar caracterele ".", ";", "[" Și "/" sunt interzise. În plus, dacă metoda nu este apelată sau . numele lui nu poate conține caracterele "<» и «>“.

Redirecționarea câmpurilor finale, parametrii finali și acest lucru

Parametrul final din JBC nu există și orice parametru, inclusiv acest (în indexul zeroth), poate fi modificat. Câmpul constant poate fi de asemenea schimbat dacă a fost deja definit în constructor (acest lucru nu este necesar pentru câmpurile statice).

Apelarea metodei din null

În JBC, puteți apela orice metodă non-statică în null. și va funcționa bine dacă nu o numește.

Folosind constructori și inițiatori, ca și cum acestea ar fi metode

În JBC, constructorii și inițiatorii nu se deosebesc de metodele, singurul lucru este că trebuie să aibă nume și respectiv, astfel încât JVM să poată verifica dacă un constructor solicită un alt constructor valabil.

Un apel din metoda non-virtuală din aceeași clasă

În JPL, apelul către noul Bar :: foo () va apela întotdeauna excepția Runtime. Nu puteți face metoda Foo :: foo () întotdeauna să apeleze bar () din clasa sa. Dar puteți implementa acest comportament pe JBC utilizând opcodul INVOKESPECIAL. care este de obicei folosit pentru a apela metode părinte.

Atribuirea unui meta-atribut arbitrar

În JPL, puteți adăuga adnotări numai la câmpuri, metode și clase. În JBC, puteți încorpora orice informație în clasă. Cu toate acestea, pentru utilizarea lui va trebui să îl extrageți singur, fără a se baza pe mecanismul de încărcare a clasei Java.

Overflow și definirea implicită a valorilor octeților. scurt. char și boolean

Din punct de vedere tehnic, în interiorul bytecode există numai tipuri int. float. lung și dublu. ceea ce oferă posibilitatea multor operațiuni inacceptabile pentru JPL.

Bloc recursiv de captură

În Java bytecode, puteți face ceva de genul

Apelarea oricărei "metode implicite"

În JBC, puteți apela metoda implicită, chiar dacă a fost redefinită.

Apelarea metodei părinte dintr-un alt obiect decât acesta

În JPL, puteți apela doar metodele celui mai apropiat părinte sau metode implicite de interfață. În JBC, codul de acest fel este posibil:

Accesul la membrii sintetici

În bytecode, membrii sintetici pot fi accesați direct.

Este valabil și pentru câmpurile, metodele și clasele sintetice.

Adăugarea de informații incorecte despre medicamentele generice

Informațiile despre generice sunt stocate în clasă ca șiruri de caractere. Verificatorul nu verifică în niciun fel, astfel încât să puteți asigura că următoarele afirmații sunt adevărate:

Apelarea metodei inexistente și crasarea JVM

Puteți apela orice metodă în orice instanță. De obicei, verificatorul recunoaște acest lucru, dar am observat că, uneori, când numiți o metodă pe un element de matrice, unele versiuni ale JVM nu recunosc că nu există. Aceasta, desigur, este o posibilitate dubioasă, dar cu ajutorul codului care a trecut prin javac. nu puteți face acest lucru sigur. Desigur, atunci când JVM ajunge la acest punct, este prăbușit.







Trimiteți-le prietenilor: