Einschränkungen

Eine .dex-Datei ist das Transportformat für Dalvik-Bytecode. Es gibt bestimmte syntaktische und semantische Einschränkungen, damit eine Datei eine gültige .dex-Datei ist. Außerdem ist eine Laufzeit erforderlich, die nur gültige .dex-Dateien unterstützt.

Allgemeine Einschränkungen für die Integrität von .dex-Dateien

Allgemeine Integritätseinschränkungen beziehen sich auf die größere Struktur einer .dex-Datei, wie im .dex-Format ausführlich beschrieben.

ID Beschreibung
G1 Die magic-Nummer der .dex-Datei muss dex\n035\0 für Version 35 oder ähnlich für spätere Versionen sein.
G2 Die Prüfsumme muss eine Adler-32-Prüfsumme des gesamten Dateiinhalts sein, mit Ausnahme der Felder magic und checksum.
G3 Die Signatur muss ein SHA-1-Hash des gesamten Dateiinhalts mit Ausnahme von magic, checksum und signature sein.
G4

file_size muss mit der tatsächlichen Dateigröße in Byte übereinstimmen. (Version 40 oder älter)

Das file_size muss auf die nächste Überschrift im Container oder auf das Ende der physischen Datei (des Containers) verweisen. Wenn er auf den nächsten Header verweist, muss die Dateigröße auf 4 Byte ausgerichtet sein. Die Summe aller file_size-Felder muss container_size betragen. (Version 41 oder höher)

G5

header_size muss den Wert 0x70 haben (Version 40 oder älter)

header_size muss den Wert 0x78 haben (Version 41 oder höher)

G6 endian_tag muss entweder den Wert ENDIAN_CONSTANT oder REVERSE_ENDIAN_CONSTANT haben.
G7

Für die Abschnitte link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs und data müssen die Felder offset und size entweder beide den Wert 0 haben oder beide einen anderen Wert. In diesem Fall muss der Offset auf vier Byte ausgerichtet sein.

Die Felder offset und size müssen sich im Container befinden und sich auf Daten beziehen, die sich nach dem Header befinden, der sie definiert. (Version 41 oder höher)

G8 Alle Offset-Felder in der Kopfzeile mit Ausnahme von map_off müssen auf vier Byte ausgerichtet sein.
G9 Das Feld map_off muss entweder null sein oder auf den Datenabschnitt verweisen. In diesem Fall muss der Abschnitt data vorhanden sein.
G10 Die Abschnitte link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs und data dürfen sich nicht überschneiden oder den Header überlagern.
G11 Wenn eine Zuordnung vorhanden ist, muss jeder Zuordnungseintrag einen gültigen Typ haben. Jeder Typ darf höchstens einmal vorkommen.
G12 Wenn eine Map vorhanden ist, muss jeder Map-Eintrag einen nicht nullwertigen Offset und eine nicht nullwertige Größe haben. Der Offset muss auf den entsprechenden Abschnitt der Datei verweisen (d.h. ein string_id_item muss auf den Abschnitt string_ids verweisen) und die explizite oder implizite Größe des Elements muss mit dem tatsächlichen Inhalt und der Größe des Abschnitts übereinstimmen.
G13 Wenn eine Zuordnung vorhanden ist, muss der Offset des Zuordnungseintrags n+1 größer oder gleich dem Offset des Zuordnungseintrags n plus than size of map entry n sein. Das bedeutet, dass sich Einträge nicht überschneiden dürfen und in absteigender Reihenfolge sortiert sein müssen.
G14 Die folgenden Arten von Einträgen müssen einen auf vier Byte ausgerichteten Offset haben: string_id_item, type_id_item, proto_id_item, field_id_item, method_id_item, class_def_item, type_list, code_item und annotations_directory_item.
G15

Für jede string_id_item muss das Feld string_data_off einen gültigen Verweis auf den Abschnitt data enthalten. (Version 40 oder älter)

Für jede string_id_item muss das Feld string_data_off ein Offset innerhalb des Containers und nach allen Headern sein, die es transitiv verwenden. (Version 41 oder höher)

Für den referenzierten string_data_item muss das Feld data einen gültigen MUTF-8-String enthalten und utf16_size muss der decodierten Länge des Strings entsprechen.

G16 Für jeden type_id_item muss das Feld descriptor_idx eine gültige Referenz auf die Liste string_ids enthalten. Der referenzierte String muss ein gültiger Typdeskriptor sein.
G17 Für jeden proto_id_item muss das Feld shorty_idx eine gültige Referenz auf die Liste string_ids enthalten. Der referenzierte String muss ein gültiger Shorty-Beschreibungsstring sein. Außerdem muss das Feld return_type_idx ein gültiger Index in den Abschnitt type_ids sein und das Feld parameters_off muss entweder null oder ein gültiger Offset sein, der auf den Abschnitt data verweist. Wenn der Wert ungleich null ist, darf die Parameterliste keine ungültigen Einträge enthalten.
G18 Für jede field_id_item müssen sowohl die Felder class_idx als auch type_idx gültige Indizes in der Liste type_ids sein. Der Eintrag, auf den class_idx verweist, muss kein Arrayreferenztyp sein. Außerdem muss das Feld name_idx ein gültiger Verweis auf den Abschnitt string_ids sein und der Inhalt des referenzierten Eintrags muss der MemberName-Spezifikation entsprechen.
G19 Für jede method_id_item muss das Feld class_idx ein gültiger Index in den Abschnitt type_ids sein und der referenzierte Eintrag darf kein Arraytyp sein. Das Feld proto_id muss eine gültige Referenz auf die Liste proto_ids sein. Das Feld name_idx muss ein gültiger Verweis auf den Abschnitt string_ids sein und der Inhalt des referenzierten Eintrags muss der MemberName-Spezifikation entsprechen.
G20 Für jede field_id_item muss das Feld class_idx ein gültiger Index in der Liste type_ids sein. Der referenzierte Eintrag darf kein Array-Referenztyp sein.

Statische Bytecodeeinschränkungen

Statische Einschränkungen sind Einschränkungen für einzelne Elemente des Bytecodes. Sie können in der Regel ohne Kontroll- oder Datenflussanalysemethoden geprüft werden.

ID Beschreibung
A1 Das insns-Array darf nicht leer sein.
A2 Der erste Opcode im insns-Array muss den Index 0 haben.
A3 Das insns-Array darf nur gültige Dalvik-Opcodes enthalten.
A4 Der Index von Anweisung n+1 muss dem Index von Anweisung n plus der Länge von Anweisung n entsprechen, wobei mögliche Operanden berücksichtigt werden.
A5 Die letzte Anweisung im insns-Array muss am Index insns_size-1 enden.
A6 Alle goto- und if-<kind>-Ziele müssen Opcodes innerhalb derselben Methode sein.
A7 Alle Ziele einer packed-switch-Anweisung müssen Opcodes innerhalb derselben Methode sein. Größe und Liste der Ziele müssen übereinstimmen.
A8 Alle Ziele einer sparse-switch-Anweisung müssen Opcodes innerhalb derselben Methode sein. Die entsprechende Tabelle muss konsistent sein und von niedrig nach hoch sortiert sein.
A9 Der B-Operand der Anweisungen const-string und const-string/jumbo muss ein gültiger Index in den Stringkonstantenpool sein.
A10 Der C-Operand der Anweisungen iget<kind> und iput<kind> muss ein gültiger Index in den Feldkonstantenpool sein. Der referenzierte Eintrag muss ein Instanzfeld sein.
A11 Der C-Operand der Anweisungen sget<kind> und sput<kind> muss ein gültiger Index in den Feldkonstantenpool sein. Der referenzierte Eintrag muss ein statisches Feld sein.
A12 Der C-Operand der Anweisungen invoke-virtual, invoke-super, invoke-direct und invoke-static muss ein gültiger Index in den Methodenkonstantenpool sein.
A13 Der B-Operand der Anweisungen invoke-virtual/range, invoke-super/range, invoke-direct/range und invoke-static/range muss ein gültiger Index in den Methodenkonstantenpool sein.
A14 Eine Methode, deren Name mit „<“ beginnt, darf nur implizit von der VM aufgerufen werden, nicht durch Code, der aus einer .dex-Datei stammt. Die einzige Ausnahme ist der Instanzinitialisierer, der von invoke-direct aufgerufen werden kann.
A15 Der C-Operand der invoke-interface-Anweisung muss ein gültiger Index in den Methodenkonstantenpool sein. Der referenzierte method_id muss zu einer Schnittstelle (nicht zu einer Klasse) gehören.
A16 Der B-Operand der invoke-interface/range-Anweisung muss ein gültiger Index in den Methodenkonstantenpool sein. Der referenzierte method_id muss zu einer Schnittstelle gehören (nicht zu einer Klasse).
A17 Der B-Operand der Anweisungen const-class, check-cast, new-instance und filled-new-array/range muss ein gültiger Index in den Typkonstantenpool sein.
A18 Der C-Operand der Anweisungen instance-of, new-array und filled-new-array muss ein gültiger Index in den Typkonstantenpool sein.
A19 Die Dimensionen eines Arrays, das mit einer new-array-Anweisung erstellt wurde, müssen kleiner als 256 sein.
A20 Die new-Anweisung darf sich nicht auf Arrayklassen, Schnittstellen oder abstrakte Klassen beziehen.
A21 Der Typ, auf den eine new-array-Anweisung verweist, muss ein gültiger Nicht-Referenztyp sein.
A22 Alle Register, auf die eine Anweisung in einer einzelnen Breite (nicht paarweise) verweist, müssen für die aktuelle Methode gültig sein. Das bedeutet, dass ihre Indizes nicht negativ und kleiner als registers_size sein dürfen.
A23 Alle Register, auf die eine Anweisung in doppelter Breite (Paare) verweist, müssen für die aktuelle Methode gültig sein. Die Indizes dürfen also nicht negativ und kleiner als registers_size-1 sein.
A24 Der method_id-Operand der Anweisungen invoke-virtual und invoke-direct muss zu einer Klasse (nicht zu einer Schnittstelle) gehören. In Dex-Dateien vor Version 037 gilt das auch für invoke-super- und invoke-static-Anweisungen.
A25 Der method_id-Operand der Anweisungen invoke-virtual/range und invoke-direct/range muss zu einer Klasse (nicht zu einer Schnittstelle) gehören. In Dex-Dateien vor Version 037 muss dies auch für invoke-super/range- und invoke-static/range-Anweisungen gelten.

Strukturelle Bytecode-Einschränkungen

Strukturelle Einschränkungen sind Einschränkungen für Beziehungen zwischen mehreren Elementen des Bytecodes. Sie können in der Regel nicht ohne Kontroll- oder Datenflussanalysetechniken geprüft werden.

ID Beschreibung
B1 Die Anzahl und die Typen der Argumente (Register und unmittelbare Werte) müssen immer mit der Anweisung übereinstimmen.
B2 Registerpaare dürfen niemals getrennt werden.
B3 Ein Register (oder Paar) muss zuerst zugewiesen werden, bevor es gelesen werden kann.
B4 Eine invoke-direct-Anweisung darf nur einen Instanzinitialisierer oder eine Methode in der aktuellen Klasse oder in einer ihrer übergeordneten Klassen aufrufen.
B5 Ein Instanzinitialisierer darf nur auf einer nicht initialisierten Instanz aufgerufen werden.
B6 Instanzmethoden können nur auf bereits initialisierten Instanzen aufgerufen und auf Instanzfelder nur auf bereits initialisierten Instanzen zugegriffen werden.
B7 Ein Register, das das Ergebnis einer new-instance-Anweisung enthält, darf nicht verwendet werden, wenn dieselbe new-instance-Anweisung noch einmal ausgeführt wird, bevor die Instanz initialisiert wird.
B8 Ein Instanzinitialisierer muss einen anderen Instanzinitialisierer (derselben Klasse oder übergeordneten Klasse) aufrufen, bevor auf Instanzmitglieder zugegriffen werden kann. Ausnahmen sind nicht vererbte Instanzfelder, die zugewiesen werden können, bevor ein anderer Initialisator und die Object-Klasse allgemein aufgerufen werden.
B9 Alle tatsächlichen Methodenargumente müssen mit ihren jeweiligen formellen Argumenten kompatibel sein.
B10 Bei jedem Aufruf einer Instanzmethode muss die tatsächliche Instanz mit der in der Anweisung angegebenen Klasse oder Schnittstelle kompatibel sein.
B11 Eine return<kind>-Anweisung muss mit dem Rückgabetyp der Methode übereinstimmen.
B12 Beim Zugriff auf geschützte Mitglieder einer Superklasse muss der tatsächliche Typ der Instanz, auf die zugegriffen wird, entweder die aktuelle Klasse oder eine ihrer Unterklassen sein.
B13 Der Typ eines Werts, der in einem statischen Feld gespeichert wird, muss mit dem Typ des Felds übereinstimmen oder in diesen konvertiert werden können.
B14 Der Typ eines in einem Feld gespeicherten Werts muss mit dem Typ des Felds übereinstimmen oder in diesen konvertiert werden können.
B15 Der Typ jedes in einem Array gespeicherten Werts muss mit dem Komponententyp des Arrays kompatibel sein.
B16 Der A-Operand einer throw-Anweisung muss mit java.lang.Throwable kompatibel sein.
B17 Die letzte erreichbare Anweisung einer Methode muss entweder eine rückwärtsgerichtete goto- oder Verzweigungsanweisung, eine return- oder eine throw-Anweisung sein. Es darf nicht möglich sein, das insns-Array unten zu lassen.
B18 Die nicht zugewiesene Hälfte eines früheren Registerpaars kann erst gelesen werden (wird als ungültig betrachtet), wenn sie durch eine andere Anweisung neu zugewiesen wurde.
B19 Vor einer move-result<kind>-Anweisung muss im insns-Array unmittelbar eine invoke-<kind>-Anweisung stehen. Die einzige Ausnahme ist die Anweisung move-result-object, vor der auch eine Anweisung filled-new-array stehen kann.
B20 Einer move-result<kind>-Anweisung muss im tatsächlichen Kontrollfluss unmittelbar eine übereinstimmende return-<kind>-Anweisung vorausgehen. Es darf nicht zu ihr gesprungen werden. Die einzige Ausnahme ist die Anweisung move-result-object, der auch eine Anweisung filled-new-array vorangestellt werden kann.
B21 Eine move-exception-Anweisung darf nur als erste Anweisung in einem Ausnahme-Handler erscheinen.
B22 Die Pseudoanweisungen packed-switch-data, sparse-switch-data und fill-array-data dürfen nicht über die Ablaufsteuerung erreichbar sein.