Ograniczenia

Plik .dex to format transportu dla kodu bajtowego Dalvik. Aby plik był prawidłowym plikiem .dex, musi spełniać określone ograniczenia składni i semantyki, a czas wykonywania musi obsługiwać tylko prawidłowe pliki .dex.

Ogólne ograniczenia integralności pliku .dex

Ogólne ograniczenia integralności dotyczą szerszej struktury pliku .dex, jak opisano szczegółowo w pliku .dex.

Identyfikator Opis
G1 Numer magic pliku .dex musi być dex\n035\0 w przypadku wersji 35 lub podobny w przypadku nowszych wersji.
G2 Suma kontrolna musi być sumą kontrolną Adlera-32 całej zawartości pliku (z wyjątkiem pól magicchecksum).
G3 Podpis musi być skrótem SHA-1 całej zawartości pliku z wyjątkiem magic, checksumsignature.
G4

Wartość file_size musi być zgodna z rzeczywistym rozmiarem pliku w bajtach. (w wersji 40 lub starszej)

Wartość file_size musi wskazywać na następny nagłówek w kontenerze lub na koniec fizycznego pliku (kontenera). Jeśli wskazuje on na następny nagłówek, rozmiar pliku musi być wyrównany do 4 bajtów. Suma wszystkich pól file_size musi być równa container_size. (w wersji 41 lub nowszej)

G5

Wartość header_size musi wynosić: 0x70 (wersja 40 lub starsza)

Wartość parametru header_size musi wynosić 0x78 (wersja 41 lub nowsza)

G6 W polu endian_tag musi być wartość:ENDIAN_CONSTANT lub REVERSE_ENDIAN_CONSTANT
G7

W przypadku pól link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs i data pola offsetsize muszą być równe 0 lub niezerowe. W tym drugim przypadku przesunięcie musi być wyrównane co 4 bajty.

Pola offsetsize muszą znajdować się w kontenerze i odwoływać się do danych, które znajdują się po nagłówku, który je definiuje. (w wersji 41 lub nowszej)

G8 Wszystkie pola przesunięcia w nagłówku (z wyjątkiem pola map_off) muszą być wyrównane co 4 bajty.
G9 Pole map_off musi zawierać wartość 0 lub wskazywać sekcję danych. W tym drugim przypadku musi istnieć sekcja data.
G10 Sekcje link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs i data nie mogą na siebie nachodzić ani zachodzić na nagłówek.
G11 Jeśli mapa istnieje, każdy wpis mapy musi mieć prawidłowy typ. Każdy typ może się pojawić maksymalnie raz.
G12 Jeśli mapa istnieje, każdy jej wpis musi mieć niezerową wartość przesunięcia i rozmiaru. Odsunięcie musi wskazywać na odpowiednią sekcję pliku (tzn. string_id_item musi wskazywać na sekcję string_ids), a rozmiar elementu (wyrażony wprost lub domyślnie) musi odpowiadać rzeczywistej zawartości i rozmiarowi sekcji.
G13 Jeśli mapa istnieje, przesunięcie pozycji mapy n+1 musi być większe lub równe przesunięciu pozycji mapy n plus than size of map entry n. Oznacza to, że wpisy nie mogą się pokrywać, a uporządkowanie musi być od najniższej do najwyższej wartości.
G14 Te typy wpisów muszą mieć przesunięcie wyrównane do 4 bajtów: string_id_item, type_id_item, proto_id_item, field_id_item, method_id_item, class_def_item, type_list, code_item, annotations_directory_item.
G15

W przypadku każdego string_id_item pole string_data_off musi zawierać prawidłowy element odniesienia do sekcji data. (w wersji 40 lub starszej)

W przypadku każdego string_id_item pole string_data_off musi być przesuniętym w kontenerze i po dowolnym nagłówku, który go wykorzystuje. (w wersji 41 lub nowszej)

W przypadku odwołania do pola string_data_item pole data musi zawierać prawidłowy ciąg znaków w formacie MUTF-8, a pole utf16_size musi odpowiadać zakodowanej długości ciągu znaków.

G16 W przypadku każdego elementu type_id_item pole descriptor_idx musi zawierać prawidłowe odwołanie do listy string_ids. Odwołujący się ciąg musi być prawidłowym opisem typu.
G17 W przypadku każdego elementu proto_id_item pole shorty_idx musi zawierać prawidłowe odwołanie do listy string_ids. Odwołujący się ciąg musi być prawidłowym opisem shorty. Ponadto pole return_type_idx musi być prawidłowym indeksem w sekcji type_ids, a pole parameters_off musi zawierać wartość zero lub prawidłowy przesunięcie wskazujące sekcję data. Jeśli wartość jest niezerowa, lista parametrów nie może zawierać żadnych pustych wpisów.
G18 W przypadku każdego elementu field_id_item pola class_idxtype_idx muszą być prawidłowymi indeksami na liście type_ids. Wpis, do którego odwołuje się class_idx, musi być typem odniesienia innego niż tablica. Dodatkowo pole name_idx musi być prawidłowym odwołaniem do sekcji string_ids, a zawartość odwołania musi być zgodna ze specyfikacją MemberName.
G19 W przypadku każdego elementu method_id_item pole class_idx musi być prawidłowym indeksem w sekcji type_ids, a odwołujący się do niego wpis musi być typem odniesienia innego niż tablica. Pole proto_id musi być prawidłowym odwołaniem do listy proto_ids. Pole name_idx musi być prawidłowym odwołaniem do sekcji string_ids, a zawartość odwołanego wpisu musi być zgodna ze specyfikacją MemberName.
G20 W przypadku każdego elementu field_id_item pole class_idx musi być prawidłowym indeksem na liście type_ids. Odwołujący się wpis musi być typem niebędącym tablicą.

Statyczne ograniczenia kodu bajtowego

Ograniczenia statyczne to ograniczenia dotyczące poszczególnych elementów kodu bajtowego. Zwykle można je sprawdzić bez stosowania technik kontroli czy analizy przepływu danych.

Identyfikator Opis
A1 Tablica insns nie może być pusta.
A2 Pierwszy kod operacji w tablicy insns musi mieć indeks 0.
A3 Tablica insns musi zawierać tylko prawidłowe instrukcje Dalvik.
A4 Indeks instrukcji n+1 musi być równy indeksowi instrukcji n plus długość instrukcji n, biorąc pod uwagę możliwe operandy.
A5 Ostatnia instrukcja w tablicy insns musi kończyć się na indeksie insns_size-1.
A6 Wszystkie wartości docelowe gotoif-<kind> muszą być instrukcjami w ramach tej samej metody.
A7 Wszystkie cele instrukcji packed-switch muszą być instrukcjami w ramach tej samej metody. Rozmiar i lista docelów muszą być spójne.
A8 Wszystkie cele instrukcji sparse-switch muszą być instrukcjami w ramach tej samej metody. Odpowiednia tabela musi być spójna i posortowana od najniższej do najwyższej wartości.
A9 Operand B instrukcji const-stringconst-string/jumbo musi być prawidłowym indeksem w pulie stałych ciągu znaków.
A10 Operand C instrukcji iget<kind>iput<kind> musi być prawidłowym indeksem w polu puli stałych. Odwołujący się wpis musi reprezentować pole instancji.
A11 Operand C instrukcji sget<kind>sput<kind> musi być prawidłowym indeksem w polu puli stałych. Odwołujący się wpis musi reprezentować statyczne pole.
A12 Operand C instrukcji invoke-virtual, invoke-super, invoke-directinvoke-static musi być prawidłowym indeksem w stałej puli metody.
A13 Operand B instrukcji invoke-virtual/range, invoke-super/range, invoke-direct/rangeinvoke-static/range musi być prawidłowym indeksem w stałej puli metody.
A14 Metoda, której nazwa zaczyna się od „<”, może być wywoływana tylko niejawnie przez maszynę wirtualną, a nie przez kod pochodzący z pliku .dex. Jedynym wyjątkiem jest inicjalizator instancji, który może być wywoływany przez invoke-direct.
A15 Operand C instrukcji invoke-interface musi być prawidłowym indeksem w stałej puli metody. Odwołujący się method_id musi należeć do interfejsu (a nie klasy).
A16 Operand B instrukcji invoke-interface/range musi być prawidłowym indeksem w stałej puli metody. Odwołujący się element method_id musi należeć do interfejsu (a nie klasy).
A17 Operand B w instrukcjach const-class, check-cast, new-instance i filled-new-array/range musi być prawidłowym indeksem w puli stałych typu.
A18 Operand C instrukcji instance-of, new-arrayfilled-new-array musi być prawidłowym indeksem w stałej puli typów.
A19 Wymiary tablicy utworzonej za pomocą instrukcji new-array muszą być mniejsze niż 256.
A20 Instrukcja new nie może się odwoływać do klas tablic, interfejsów ani klas abstrakcyjnych.
A21 Typ, do którego odwołuje się instrukcja new-array, musi być prawidłowym typem nieodwołującym się do innego typu.
A22 Wszystkie rejestry, do których odwołuje się instrukcja w sposób jednoliniowy (nieparowy), muszą być prawidłowe w przypadku bieżącej metody. Oznacza to, że ich indeksy muszą być nieujemne i mniejsze niż registers_size.
A23 Wszystkie rejestry, do których odwołuje się instrukcja w podwójnej szerokości (para), muszą być prawidłowe w przypadku bieżącej metody. Oznacza to, że ich indeksy muszą być nieujemne i mniejsze niż registers_size-1.
24A Operand method_id instrukcji invoke-virtualinvoke-direct musi należeć do klasy (a nie interfejsu). W plikach Dex starszych niż wersja 037 instrukcje invoke-superinvoke-static muszą być takie same.
A25 Operand method_id instrukcji invoke-virtual/rangeinvoke-direct/range musi należeć do klasy (a nie interfejsu). W plikach Dex starszych niż wersja 037 instrukcje invoke-super/rangeinvoke-static/range muszą być takie same.

Ograniczenia dotyczące struktury kodu bajtowego

Ograniczenia strukturalne to ograniczenia dotyczące relacji między kilkoma elementami kodu bajtowego. Zwykle nie można ich sprawdzić bez użycia technik kontroli lub analizy przepływu danych.

Identyfikator Opis
B1 Liczba i typy argumentów (rejestry i wartości natychmiastowe) muszą zawsze być zgodne z instrukcją.
B2 Pary rejestrów nie mogą być rozdzielane.
B3 Zanim rejestr (lub para) zostanie odczytany, musi zostać przypisany.
B4 Instrukcja invoke-direct musi wywoływać konstruktor wystąpienia lub metodę tylko w bieżącej klasie lub jednej z jej nadklas.
B5 Inicjalizator instancji musi być wywoływany tylko w przypadku niezainicjalizowanej instancji.
B6 Metody instancji mogą być wywoływane tylko w przypadku pól instancji, a do pól instancji można uzyskać dostęp tylko w przypadku już zainicjowanych instancji.
B7 Nie można używać rejestru, który zawiera wynik instrukcji new-instance, jeśli ta sama instrukcja new-instance zostanie ponownie wykonana przed zainicjowaniem instancji.
B8 Inicjalizator instancji musi wywołać inny inicjalizator instancji (tą samą klasę lub superklasę), zanim będzie można uzyskać dostęp do dowolnych elementów instancji. Wyjątki to nieodziedziczone pola instancji, które można przypisać przed wywołaniem innego inicjalizatora oraz klasy Object w ogóle.
B9 Wszystkie rzeczywiste argumenty metody muszą być zgodne z odpowiednimi argumentami formalnymi.
B10 W przypadku każdego wywołania metody instancji rzeczywista instancja musi być przypisana do klasy lub interfejsu określonego w instrukcji.
B11 Instrukcja return<kind> musi być zgodna z typem zwracanym metody.
B12 Podczas uzyskiwania dostępu do chronionych elementów superklasy rzeczywisty typ wystąpienia, do którego uzyskujesz dostęp, musi być bieżącą klasą lub jedną z jej podklas.
B13 Typ wartości przechowywanej w polu statycznym musi być zgodny z typem przypisania lub musi być możliwy do konwersji na typ pola.
B14 Typ wartości przechowywanej w polu musi być zgodny z typem pola lub musi być możliwy do konwersji na typ pola.
B15 Typ każdej wartości przechowywanej w tablicy musi być zgodny z typem komponentu tablicy.
B16 Operand A instrukcji throw musi być zgodny z instrukcją java.lang.Throwable.
B17 Ostatnia instrukcja metody, do której można dotrzeć, musi być instrukcją goto lub gałęzi return, return lub throw. Nie można pozostawić tablicy insns na dole.
B18 Nieprzypisana połowa pary rejestrów może nie być odczytywana (jest uznawana za nieważną), dopóki nie zostanie ponownie przypisana przez inną instrukcję.
B19 Instrukcja move-result<kind> musi być bezpośrednio poprzedzona (w tablicy insns) instrukcją invoke-<kind>. Jedynym wyjątkiem jest instrukcja move-result-object, która może być poprzedzona instrukcją filled-new-array.
B20 Instrukcja move-result<kind> musi być bezpośrednio (w ramach rzeczywistego przepływu sterowania) poprzedzona instrukcją return-<kind> (nie może być do niej przeskakiwana). Jedynym wyjątkiem jest instrukcja move-result-object, która może być poprzedzona instrukcją filled-new-array.
B21 Instrukcja move-exception musi występować tylko jako pierwsza instrukcja w obiekcie wyjątku.
B22 Pseudoinstrukcje packed-switch-data, sparse-switch-datafill-array-data nie mogą być dostępne dla sterowania przepływem.