Question ChuckNorrisException inaccessible


Est-il possible de construire un extrait de code dans Java cela ferait un hypothétique java.lang.ChuckNorrisException insaisissable?

Les pensées qui viennent à l'esprit utilisent par exemple des intercepteurs ou programmation orientée aspect.


577
2017-12-14 17:05


origine


Réponses:


Je n'ai pas essayé cela, donc je ne sais pas si le JVM limiterait quelque chose comme ça, mais peut-être pourriez-vous compiler le code qui jette ChuckNorrisException, mais à l'exécution fournissent une définition de classe de ChuckNorrisException lequel ne s'étend pas.

METTRE À JOUR:

Ça ne marche pas. Il génère une erreur de vérification:

Exception in thread "main" java.lang.VerifyError: (class: TestThrow, method: ma\
in signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestThrow.  Program will exit.

MISE À JOUR 2:

En fait, vous pouvez obtenir ceci pour fonctionner si vous désactivez le vérificateur de code d'octet! (-Xverify:none)

MISE À JOUR 3:

Pour ceux qui suivent de la maison, voici le script complet:

Créez les classes suivantes:

public class ChuckNorrisException
    extends RuntimeException // <- Comment out this line on second compilation
{
    public ChuckNorrisException() { }
}

public class TestVillain {
    public static void main(String[] args) {
        try {
            throw new ChuckNorrisException();
        }
        catch(Throwable t) {
            System.out.println("Gotcha!");
        }
        finally {
            System.out.println("The end.");
        }
    }
}

Compiler les classes:

javac -cp . TestVillain.java ChuckNorrisException.java

Courir:

java -cp . TestVillain
Gotcha!
The end.

Commentez "extends RuntimeException" et recompiler ChuckNorrisException.java seulement :

javac -cp . ChuckNorrisException.java

Courir:

java -cp . TestVillain
Exception in thread "main" java.lang.VerifyError: (class: TestVillain, method: main signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestVillain.  Program will exit.

Exécuter sans vérification:

java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"

305
2017-12-14 17:27



Après avoir réfléchi à cela, j'ai réussi à créer une exception inaccessible. J'ai choisi de le nommer JulesWinnfieldCependant, plutôt que Chuck, parce que c'est une exception de champignon-nuage-pose-mère. De plus, ce n'est peut-être pas exactement ce que vous aviez en tête, mais cela ne peut certainement pas être compris. Observer:

public static class JulesWinnfield extends Exception
{
    JulesWinnfield()
    {
        System.err.println("Say 'What' again! I dare you! I double dare you!");
        System.exit(25-17); // And you shall know I am the LORD
    }
}


public static void main(String[] args)
{       
    try
    {
        throw new JulesWinnfield();
    } 
    catch(JulesWinnfield jw)
    {
        System.out.println("There's a word for that Jules - a bum");
    }
}

Et voilà! Exception non interceptée.

Sortie:

courir:

Dites 'Quoi encore'! Je te défie! Je double osez-vous!

Java Résultat: 8

BUILD SUCCESSFUL (temps total: 0 secondes)

Quand j'aurai un peu plus de temps, je verrai si je ne peux pas trouver autre chose.

Aussi, vérifiez ceci:

public static class JulesWinnfield extends Exception
{
    JulesWinnfield() throws JulesWinnfield, VincentVega
    {
        throw new VincentVega();
    }
}

public static class VincentVega extends Exception
{
    VincentVega() throws JulesWinnfield, VincentVega
    {
        throw new JulesWinnfield();
    }
}


public static void main(String[] args) throws VincentVega
{

    try
    {
        throw new JulesWinnfield();
    }
    catch(JulesWinnfield jw)
    {

    }
    catch(VincentVega vv)
    {

    }
}

Provoque un débordement de pile - encore une fois, les exceptions restent inchangées.


113
2017-12-15 12:16



Avec une telle exception, il serait évidemment obligatoire d'utiliser un System.exit(Integer.MIN_VALUE); du constructeur parce que c'est ce qui arriverait si vous jetiez une telle exception;)


84
2017-12-14 17:15



Tout code peut attraper Throwable. Donc non, quelle que soit l'exception que vous créez va être une sous-classe de Throwable et sera sujette à être capturée.


45
2017-12-14 17:09



public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}

(Accordé, techniquement cette exception n'est jamais réellement jeté, mais un bon ChuckNorrisException ne peut pas être jeté - il vous jette en premier.)


34
2017-12-15 19:01



Toute exception que vous lancez doit être Throwable, donc elle peut toujours être interceptée. Donc, la réponse est non.

Si vous voulez le rendre difficile à gérer, vous pouvez remplacer les méthodes getCause(), getMessage(), getStackTrace(), toString() jeter un autre java.lang.ChuckNorrisException.


28
2017-12-14 17:17



Ma réponse est basée sur l'idée de @ jtahlborn, mais elle fonctionne pleinement Java programme, qui peut être emballé dans un POT fichier et même déployé sur votre serveur d'applications préféré dans le cadre d'un application Web.

Tout d'abord, définissons ChuckNorrisException classe de sorte qu'il ne plante pas JVM depuis le début (Chuck aime vraiment s'écraser JVMs BTW :)

package chuck;

import java.io.PrintStream;
import java.io.PrintWriter;

public class ChuckNorrisException extends Exception {

    public ChuckNorrisException() {
    }

    @Override
    public Throwable getCause() {
        return null;
    }

    @Override
    public String getMessage() {
        return toString();
    }

    @Override
    public void printStackTrace(PrintWriter s) {
        super.printStackTrace(s);
    }

    @Override
    public void printStackTrace(PrintStream s) {
        super.printStackTrace(s);
    }
}

Maintenant va Expendables classe pour le construire:

package chuck;

import javassist.*;

public class Expendables {

    private static Class clz;

    public static ChuckNorrisException getChuck() {
        try {
            if (clz == null) {
                ClassPool pool = ClassPool.getDefault();
                CtClass cc = pool.get("chuck.ChuckNorrisException");
                cc.setSuperclass(pool.get("java.lang.Object"));
                clz = cc.toClass();
            }
            return (ChuckNorrisException)clz.newInstance();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

Et enfin le Main classe pour botter un peu:

package chuck;

public class Main {

    public void roundhouseKick() throws Exception {
        throw Expendables.getChuck();
    }

    public void foo() {
        try {
            roundhouseKick();
        } catch (Throwable ex) {
            System.out.println("Caught " + ex.toString());
        }
    }

    public static void main(String[] args) {
        try {
            System.out.println("before");
            new Main().foo();
            System.out.println("after");
        } finally {
            System.out.println("finally");
        }
    }
}

Compilez et exécutez-le avec la commande suivante:

java -Xverify:none -cp .:<path_to_javassist-3.9.0.GA.jar> chuck.Main

Vous obtiendrez la sortie suivante:

before
finally

Pas de surprise - c'est un coup de pied circulaire après tout :)


23
2017-12-18 22:56



Dans le constructeur, vous pouvez démarrer un fil qui appelle à plusieurs reprises originalThread.stop (ChuckNorisException.this) 

Le thread pourrait attraper l'exception à plusieurs reprises, mais continuer à le lancer jusqu'à ce qu'il meurt.


15
2017-12-14 20:55



Non. Toutes les exceptions dans Java doivent être sous-classes java.lang.Throwableet bien que ce ne soit pas une bonne pratique, vous pouvez attraper tous les types d'exceptions comme suit:

try {
    //Stuff
} catch ( Throwable T ){
    //Doesn't matter what it was, I caught it.
}

Voir le java.lang.Throwable documentation pour plus d'informations.

Si vous essayez d'éviter exceptions vérifiées (ceux qui doivent être gérés explicitement) alors vous voudrez sous-classer Error, ou RuntimeException.


13
2017-12-14 17:09



Une variante sur le thème est le fait surprenant que vous pouvez jeter des exceptions vérifiées non déclarées à partir du code Java. Comme il n'est pas déclaré dans la signature des méthodes, le compilateur ne vous laissera pas attraper l'exception elle-même, bien que vous puissiez l'attraper comme java.lang.Exception.

Voici une classe d'aide qui vous permet de lancer n'importe quoi, déclaré ou non:

public class SneakyThrow {
  public static RuntimeException sneak(Throwable t) {
    throw SneakyThrow.<RuntimeException> throwGivenThrowable(t);
  }

  private static <T extends Throwable> RuntimeException throwGivenThrowable(Throwable t) throws T {
    throw (T) t;
  }
}

À présent throw SneakyThrow.sneak(new ChuckNorrisException()); lance une exception ChuckNorrisException, mais le compilateur se plaint

try {
  throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}

à propos de la capture d'une exception qui n'est pas levée si ChuckNorrisException est une exception vérifiée.


8
2017-12-22 08:32