Skip to content

Commit

Permalink
handle problems at static initialization gracefully
Browse files Browse the repository at this point in the history
  • Loading branch information
lytles@takashi committed Sep 26, 2018
1 parent c38894b commit e9c41be
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 18 deletions.
12 changes: 8 additions & 4 deletions demo/demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,27 @@ echo "classpath: $cp"


yes "" | head
echo "demo unflect for java 8 - 7, 8, 9, 10, 11"
echo "demo using only java 8 features - 7, 8, 9, 10, 11"
for ii in $java7 $java8 $java9 $java10 $java11; do
$ii/bin/java -cp target/classes:$cp demo.Demo8
done

yes "" | head
echo "demo unflect - 9, 10, 11"
echo "demo Permit - 9, 10, 11"
for ii in $java9 $java10 $java11; do
$ii/bin/java -cp target/classes:$cp demo.DemoPermit
done

yes "" | head
echo "demo normal with godmode"
$java9/bin/java -cp target/classes:$cp com.nqzero.permit.Permit demo.DemoNormal

yes "" | head
echo "demo normal without godmode - should fail"
$java9/bin/java -cp target/classes:$cp demo.DemoNormal

yes "" | head
echo "demo normal with godmode"
$java9/bin/java -cp target/classes:$cp com.nqzero.permit.Permit demo.DemoNormal
echo "demo how Permit handles a security manager - should fail gracefully"
$java9/bin/java -Djava.security.manager -cp target/classes:$cp demo.DemoPermit

yes "" | head
11 changes: 10 additions & 1 deletion demo/src/demo/DemoPermit.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,22 @@ static Object logger(boolean expected) {
return obj;
}

void safe() {}

public static void main(String[] args) throws Exception {
int [] vals = new int[10];
int ii = 0;

// check whether Permit initialized first, since this is what a real user might see
// with the security manager, local is null but that's ok since Permit bombs out before seeing it
Method local = null;
try { local = DemoPermit.class.getDeclaredMethod("safe"); }
catch (Throwable ex) {}
setAccessible(local);

RandomAccessFile raf = new RandomAccessFile("/etc/hosts","r");
FileDescriptor fd = raf.getFD();
Field field = FileDescriptor.class.getDeclaredField("fd");
Class ka = AccessibleObject.class;
Method export = Module.class.getDeclaredMethod("implAddOpens",String.class);
setAccessible(export);
Class log = Class.forName("jdk.internal.module.IllegalAccessLogger");
Expand Down
73 changes: 60 additions & 13 deletions src/com/nqzero/permit/Permit.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,26 @@
public class Permit<TT,VV> extends Safer<TT,VV> {
public static final String splitChar = "\\.";

static Permit<AccessibleObject,Boolean> override = build(AccessibleObject.class,"override");
static Exception savedEx;
static Permit<AccessibleObject,Boolean> override;
static {
try { override = build(AccessibleObject.class,"override"); }
catch (Exception ex) { savedEx = ex; }
}


public static void setAccessible(AccessibleObject accessor) {
public static void setAccessible(AccessibleObject accessor) throws InitializationFailed {
if (savedEx != null)
throw new InitializationFailed();
override.putBoolean(accessor,true);
}

public static boolean initSucceeded(boolean rethrow) {
if (savedEx==null)
return true;
if (rethrow)
throw new RuntimeException(savedEx);
return false;
}

public static void unLog() {
try {
Expand All @@ -28,6 +42,8 @@ public static void unLog() {

static String jigsaw = "JigsawImpl";
public static void godMode() throws RuntimeException {
if (savedEx != null)
throw new InitializationFailed();
try {
// this will fail on java 8 and lower
// but load with at least java 9-11
Expand All @@ -36,7 +52,7 @@ public static void godMode() throws RuntimeException {
Method method = klass.getMethod("godMode");
method.invoke(null);
}
catch (NoSuchMethodException ex) { /* expected for java 8 or older */ }
catch (NoSuchMethodError ex) { /* expected for java 8 or older */ }
catch (Throwable ex) {
throw new RuntimeException("jigsaw appears active, but unable to open packages",ex);
}
Expand Down Expand Up @@ -72,6 +88,12 @@ public static <VV> VV getField(Object cl,Meth<VV> meth,String ... names) throws
return null;
}

public static class InitializationFailed extends RuntimeException {
public InitializationFailed() {
super("initialization failed, perhaps you're running with a security manager",savedEx);
}
}

public static class FieldNotFound extends RuntimeException {
String name;
public FieldNotFound(String name,Throwable ex) {
Expand Down Expand Up @@ -113,10 +135,10 @@ public static Field getSuperField(Class klass,String name) {
return null;
}

private static String[] processArgs(String[] args) {
String[] ret = new String[args.length-1];
private static String[] processArgs(String[] args,int start) {
String[] ret = new String[args.length-start];
if (ret.length > 0)
System.arraycopy(args, 1, ret, 0, ret.length);
System.arraycopy(args, start, ret, 0, ret.length);
return ret;
}

Expand All @@ -128,20 +150,45 @@ private static String[] processArgs(String[] args) {
* @throws Exception
*/
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.out.println("usage: java Unflect className [args ...]");
int start = 0;
boolean verbose = false;
if (args[0].equals("-v")) {
start++;
verbose = true;
}

String name = Permit.class.getName();
if (args.length == start) {
System.out.format("\nusage: java %s [-v] className [args ...]\n",name);
System.out.println(" invoke the main method in the named class in god mode with the remaining args");
System.out.println(" ie, run it with all packages in all modules open to all modules");
System.out.println("where options are:");
System.out.println(" -v : verbose, rethrow exceptions when setting god mode");
System.out.println(" args: the remaining args are passed to the named class main method");
System.out.println("");
System.exit(1);
}
godMode();
String className = args[0];
args = processArgs(args);

Exception problem = savedEx;
try {
if (problem==null)
godMode();
}
catch (Exception ex) { problem = ex; }
if (problem != null) {
System.out.println("unable to initialize godMode - cowardly exiting");
System.out.println(" perhaps you have a security manager running");
if (verbose) {
System.out.format(" rethrowing exception:\n\n");
throw problem;
}
System.exit(1);
}
String className = args[start];
args = processArgs(args,start+1);
Class mainClass = Permit.class.getClassLoader().loadClass(className);
Method mainMethod = mainClass.getMethod("main", new Class[]{String[].class});
mainMethod.invoke(null,new Object[] {args});

}


Expand Down

0 comments on commit e9c41be

Please sign in to comment.