61 votes

Que pouvez-vous jeter en Java?

La sagesse conventionnelle dit que vous ne pouvez lancer des objets qui s'étendent Throwable en Java, mais est-il possible de désactiver le bytecode verifier et obtenir Java pour compiler et exécuter le code qui lance des objets arbitraires ou même des primitives?

J'ai regardé la JVM athrow et il apparaîtra à la première objref sur l'opérande de la pile; mais ne serait-il vérifier si les points de référence à un Throwable au moment de l'exécution?

73voto

John Kugelman Points 108754

Cela dépend de votre JVM. Selon la spécification de la machine virtuelle Java c'est un comportement indéfini si l'objet n'est pas Throwable.

Le objectref doit être de type référence et doit se référer à un objet qui est une instance de la classe Throwable ou d'une sous-classe de Throwable.

Dans la section 6.1, "Le Sens de "Doit"":

Si certaines contraintes (un "must" ou "ne doit pas") dans une instruction description n'est pas satisfait au moment de l'exécution, le comportement de la machine virtuelle Java n'est pas défini.

J'ai écrit un programme de test à l'aide de l' Jasmin assembleur qui fait l'équivalent d' throw new Object(). La Java HotSpot Server VM jette un VerifyError:

# cat Athrow.j 
.source Athrow.j
.class public Athrow
.super java/lang/Object

.method public <init>()V
    aload_0
    invokenonvirtual java/lang/Object/<init>()V
    return
.end method

.method public static main([Ljava/lang/String;)V
    .limit stack 2

    new java/lang/Object
    dup
    invokenonvirtual java/lang/Object/<init>()V
    athrow

    return
.end method

# java -jar jasmin.jar Athrow.j 
Generated: Athrow.class

# java Athrow
Exception in thread "main" java.lang.VerifyError: (class: Athrow, method: main signature: ([Ljava/lang/String;)V) Can only throw Throwable objects

La désactivation du bytecode verifier permet à l' athrow d'exécuter et de la JVM semble se bloquer lorsqu'il essaie d'imprimer l'exception de détails. Comparer ces deux programmes, le premier qui jette un Exception, la seconde qui est au-dessus de programme de test qui jette un Object. Remarquez comment il se ferme au moyen d'une copie d'écran:

# java -Xverify:none examples/Uncaught
Exception in thread "main" java.lang.Exception
        at examples.Uncaught.main(Uncaught.j)
# java -Xverify:none Athrow
Exception in thread "main" #

Bien sûr, la désactivation du bytecode verifier est dangereux. La VM est une bonne écrite de supposer que le bytecode de la vérification a été effectuée et n'a donc pas à typecheck instruction des opérandes. Attention: le comportement non défini que vous appelez lorsque vous contourner de vérification de bytecode est un peu comme le comportement non défini dans les programmes C; rien du tout peut arriver, y compris les démons volant de votre nez.

8voto

soc Points 10868

Comme mentionné dans la réponse de Jean, vous pouvez désactiver la vérification de la passation de la classe sur le bootclasspath devrait aussi fonctionner ), de charger et d'exécuter une classe de jeter un non-Throwable classe avec succès.

Étonnamment, il ne doit pas nécessairement conduire à un crash!

Tant que vous ne l'appelez pas Throwable méthodes implicitement ou explicitement, tout fonctionne parfaitement bien:

.source ThrowObject.j
.class public ThrowObject
.super java/lang/Object

.method public <init>()V
    aload_0
    invokenonvirtual java/lang/Object/<init>()V
    return
.end method

.method public static main([Ljava/lang/String;)V

    new java/lang/Object
    dup
    invokenonvirtual java/lang/Object/<init>()V

  BeforeThrow:
    athrow

  AfterThrow:

    return

  CatchThrow:

    getstatic java/lang/System/out Ljava/io/PrintStream;
    ldc "Thrown and catched Object successfully!"
    invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V
    return

  .catch all from BeforeThrow to AfterThrow using CatchThrow
.end method

Résultat:

% java -Xverify:none ThrowObject
Thrown and catched Object successfully!

5voto

aioobe Points 158466

[...] désactiver le bytecode verifier [...]

Le pseudo-code de vérification fait partie de la JVM spec, donc si vous désactivez cette (ou de trafiquer avec la JVM dans d'autres moyens), vous pouvez, en fonction de la mise en œuvre, à peu près tout faire (y compris en lançant des primitives etc) je suppose.

Citation de la spécification de la JVM:

Le objectref doit être de type référence et doit se référer à un objet qui est une instance de la classe Throwable ou d'une sous-classe de Throwable.

I. e., votre question peut être interprété comme "Si une JVM s'écarte de la norme, peut-il faire des choses bizarres, comme lancer primitivs" et la réponse est évidemment "oui".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X