155 votes

Comment faites-vous planter un JVM?

Je lisais un livre sur les compétences en programmation dans lequel l'auteur demande à l'interviewé, "Comment faites-vous planter un JVM?" Je pensais que vous pourriez le faire en écrivant une boucle for infinie qui finirait par utiliser toute la mémoire.

Quelqu'un a une idée?

1 votes

0 votes

stackoverflow.com/questions/30072883/… "Si j'utilise JDK1.8_40 ou plus récent (Oracle ou OpenJDK font la même chose), le code suivant avec un redimensionnement de la boîte de dialogue fera planter l'application (essayé sous Windows 7, x64, JDK 64 bits)" - Le code ne fait que 40 lignes, et il provoque un plantage réel du JVM.

179voto

ralfs Points 1166

Je ne qualifierais pas le déclenchement d'une OutOfMemoryError ou d'un StackOverflowError comme un crash. Ce ne sont que des exceptions normales. Pour vraiment crasher une VM, il existe 3 façons :

  1. Utiliser JNI et crasher dans le code natif.
  2. Si aucun gestionnaire de sécurité n'est installé, vous pouvez utiliser la réflexion pour crasher la VM. Cela dépend de la VM, mais en général une VM stocke plusieurs pointeurs vers des ressources natives dans des champs privés (par exemple, un pointeur vers l'objet de thread natif est stocké dans un champ long dans java.lang.Thread). Il suffit de les modifier via la réflexion et la VM crashera tôt ou tard.
  3. Toutes les VM ont des bugs, il suffit donc d'en déclencher un.

Pour la dernière méthode, voici un exemple succinct qui fera planter une VM Sun Hotspot de manière assez agréable :

public class Crash {
    public static void main(String[] args) {
        Object[] o = null;

        while (true) {
            o = new Object[] {o};
        }
    }
}

Cela entraîne un débordement de pile dans le GC, donc vous n'obtiendrez pas de StackOverflowError mais un véritable crash incluant un fichier hs_err*.

9 votes

Wow ! Cela fait planter Sun Java 5, Sun Java 6 et OpenJDK 6 (sur Ubuntu 9.04) sans fichier hs_err* mais seulement un "Segmentation fault!" ...

1 votes

System.exit() est un moyen beaucoup plus simple de faire planter un JVM (sauf si un gestionnaire de sécurité est installé)

4 votes

Ne sais pas quand c'était corrigé, mais je viens juste de tester en 1.7.0_09 et tout va bien. Juste obtenu le résultat attendu: Exception in thread "main"java.lang.OutOfMemoryError: Java heap space at CrashJVM.main(CrashJVM.java:7)

127voto

Dan Dyer Points 30082

JNI. En fait, avec JNI, le plantage est le mode de fonctionnement par défaut. Vous devez travailler extra dur pour éviter qu'il plante.

5 votes

Peut-être que les concepteurs de JNI avaient entendu parler de logiciel crash-only, mais n'avaient pas tout à fait saisi l'idée.

64voto

Dave Griffiths Points 688

Utilisez ceci :

import sun.misc.Unsafe;

public class Crash {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    public static void crash() {
        unsafe.putAddress(0, 0);
    }
    public static void main(String[] args) {
        crash();
    }
}

Cette classe doit être sur le chemin de classe de démarrage car elle utilise du code de confiance, donc exécutez comme ceci :

java -Xbootclasspath/p:. Crash

MODIFICATION: Version simplifiée avec la suggestion de pushy:

Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);

16 votes

Au lieu d'utiliser -Xbootclasspath, vous pouvez aussi simplement faire ceci : Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null ); Ça a très bien fonctionné pour moi.

0 votes

Non sûr est, par définition, "non sûr". C'est un peu tricher.

2 votes

Confirmé qui fonctionne en utilisant le tour de getDeclaredField dans JDK 8u131 sur Linux x64, y compris la production de hs_err_pid*.log à partir d'un SIGSEGV.

36voto

Caffeine Coma Points 10544

Je suis venu ici car j'ai également rencontré cette question dans The Passionate Programmer, de Chad Fowler. Pour ceux qui n'ont pas accès à une copie, la question est posée comme un genre de filtre/test pour les candidats passant un entretien pour un poste nécessitant des "vraiment bons programmeurs Java".

Plus précisément, il demande :

Comment écririez-vous un programme, en pur Java, qui ferait planter la Machine Virtuelle Java ?

J'ai programmé en Java pendant plus de 15 ans, et j'ai trouvé cette question à la fois déconcertante et injuste. Comme d'autres l'ont souligné, Java, en tant que langage géré, est spécifiquement conçu pour ne pas planter. Bien sûr, il y a toujours des bugs JVM, mais :

  1. Après plus de 15 ans de JRE en production, c'est rare.
  2. Tous ces bugs sont susceptibles d'être corrigés dans la prochaine version, alors quelle est la probabilité, pour vous en tant que programmeur, de rencontrer et de vous rappeler les détails des problèmes actuels du JRE ?

Comme d'autres l'ont mentionné, du code natif via JNI est un moyen sûr de faire planter un JRE. Mais l'auteur a spécifiquement mentionné en pur Java, donc c'est exclu.

Une autre option serait de nourrir au JRE des octets bidons ; il est assez simple de déverser des données binaires corrompues dans un fichier .class, et de demander au JRE de l'exécuter :

$ echo 'bidon bidon bidon' > bidon.class
$ java bidon
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1668440432 in class file bidon

Est-ce que cela compte ? Je veux dire que le JRE lui-même n'a pas planté ; il a correctement détecté le code bidon, l'a signalé et s'est arrêté.

Cela nous laisse avec les types de solutions les plus évidents tels que faire planter la pile via la récursion, épuiser la mémoire heap via les allocations d'objets, ou simplement lancer RuntimeException. Mais cela fait juste sortir le JRE avec une StackOverflowError ou une exception similaire, ce qui, encore une fois n'est pas vraiment un crash.

Alors que reste-t-il ? J'aimerais vraiment entendre ce que l'auteur avait vraiment en tête comme solution correcte.

Mise à jour : Chad Fowler a répondu ici.

PS : c'est par ailleurs un excellent livre. Je l'ai pris pour me soutenir moralement en apprenant Ruby.

1 votes

De telles questions d'entretien servent de tests de concordance pour les développeurs Java qui ont suffisamment d'expérience pour 1) avoir été témoins de (nombreux) plantages de la JVM et 2) avoir tiré des conclusions ou, mieux encore, en tant qu'experts (autoproclamés) en Java ont essayé de comprendre les raisons sous-jacentes d'un plantage. Chad Fowler déclare également dans son livre que les programmeurs Java autoproclamés "ne peuvent même pas trouver la mauvaise réponse", c'est-à-dire qu'ils n'ont pas essayé de réfléchir à toute une classe de problèmes potentiels. En fin de compte, cette question est un préalable à "Comment éviter les plantages de la JVM?" ce qui est bien sûr encore mieux de savoir.

1 votes

Je chercherais des personnes qui répondent simplement (comme la plupart ici l'ont fait) "débordent la pile", system.exit(), ou d'autres arrêts "normaux" car ils ne comprennent pas vraiment la JVM ou le mot "plantage". Reconnaître (comme vous l'avez fait) que c'est très anormal est un bon moyen d'identifier un programmeur plus avancé. Je suis d'accord avec votre première déclaration, je trouverais que c'est une excellente et totalement juste question à poser ou à se poser - celles sans réponses concrètes sont toujours les meilleures.

0 votes

En retard à la fête, mais une approche par bytecode semble raisonnable : si vous pouvez gérer pour nourrir de code JITTER la machine virtuelle, vous pouvez certainement la planter en bidouillant avec les registres ou des trucs comme ça

20voto

Rob Mayhew Points 675

Ce code va faire planter le JVM de manière désagréable

import sun.dc.pr.PathDasher; 

public class Crash
{
     public static void main(String[] args)
     {    
        PathDasher dasher = new PathDasher(null) ;
     }
}

1 votes

Obtenir une erreur de compilation lors de l'utilisation de JDK 1.7 avec ce code: Restriction d'accès: Le type PathDasher n'est pas accessible en raison d'une restriction sur la bibliothèque requise C:\Program Files\Java\jdk1.7.0_51\jre\lib\rt.jar

7 votes

Cela génère une InternalError dans JDK 1.8. La JVM ne plante plus.

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