2011-02-01 8 views
9

Para mi asombro y horror, acabo de encontrar la línea System.exit(1); en una biblioteca que uso. Estoy planeando ponerme en contacto con los autores de la biblioteca y preguntar qué ofrece, pero mientras tanto, ¿hay alguna forma de evitar que la biblioteca mate mi código (y, lo que es peor, matar la aplicación usando mi código)?Captura una instrucción de salida de una biblioteca

Quizás forzar de algún modo a la biblioteca a arrojar un SecurityException, que veo que exit(int) puede arrojar?

Respuesta

13

Solo hay una forma que conozco, y es codificar SecurityManager que no permite el uso de System.exit.

public class MySecurityMgr extends SecurityManager { 
    ... 

    @Override 
    public void checkExit(int status) { 
      throw new RuntimeException(Integer.toString(status)); 
    } 
} 
4

Sí, se puede instalar un SecurityManager que anula checkExit.

He encontrado esto particularmente útil para el código de prueba unitaria para asegurarme de que el código probado no salga con 0, lo que indica un éxito espúreo antes de que las pruebas tengan la oportunidad de completarse.

Esto no servirá de nada si el SecurityException termina matando algo de hilo esencial normalmente duradero.

4

Creo que su única opción (salvo golpear al autor con toallas húmedas hasta que vuelva a escribir el maldito asunto) sería cambiar el código de bytes de la biblioteca.

El enfoque bonito es utilizar AspectJ con el tiempo de carga que se teje al cargar la biblioteca, la opción fea es usar una herramienta como asm para eliminar o cambiar la llamada al método.

Aquí es un aspecto AspectJ que desvía las llamadas a System.exit():

public aspect SystemExitEvader{ 

    pointcut systemExitCall() : call(* java.lang.System.exit(*)); 

    void around() : systemExitCall(){ 
     System.out.println("Call to System.exit() attempted"); 
     // note: there is no call to proceed() 
    } 

} 

OK, he visto las otras respuestas sobre SecurityManagers y estoy de acuerdo que es probablemente el camino a seguir, pero voy a dejar mi respuesta aquí como una alternativa.

3

gestor de seguridad que sí puede hacer el truco

// install security manager to avoid System.exit() call from lib 
SecurityManager  previousSecurityManager = System.getSecurityManager(); 
final SecurityManager securityManager   = new SecurityManager() { 
    @Override public void checkPermission(final Permission permission) { 
     if (permission.getName() != null && permission.getName().startsWith("exitVM")) { 
     throw new SecurityException(); 
     } 
    } 
    }; 
System.setSecurityManager(securityManager); 

try { 
    // Call here your lib code 
} catch (SecurityException e) { 
    // Say hi to your favorite creator of closed source software that includes System.exit() in his code. 
} finally { 
    System.setSecurityManager(previousSecurityManager); 
} 
Cuestiones relacionadas