All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kohsuke.file_leak_detecter.Main Maven / Gradle / Ivy

The newest version!
package org.kohsuke.file_leak_detecter;

import org.kohsuke.file_leak_detecter.transform.ClassTransformSpec;
import org.kohsuke.file_leak_detecter.transform.CodeGenerator;
import org.kohsuke.file_leak_detecter.transform.MethodAppender;
import org.kohsuke.file_leak_detecter.transform.TransformerImpl;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;

/**
 * @author Kohsuke Kawaguchi
 */
public class Main {
    public static void premain(String agentArguments, Instrumentation instrumentation) throws UnmodifiableClassException, IOException {
        if(agentArguments!=null) {
            if(agentArguments.equals("help")) {
                System.err.println("File leak detecter arguments:");
                System.err.println("  help        - show the help screen.");
                System.err.println("  trace       - log every open/close operation to stderr.");
                System.err.println("  trace=FILE  - log every open/close operation to the given file.");
                System.err.println("  error=FILE  - if 'too many open files' error is detected, send the dump here.");
                System.err.println("                by default it goes to stderr.");
                System.exit(-1);
            }
            if(agentArguments.equals("trace")) {
                Listener.TRACE = System.err;
            }
            if(agentArguments.startsWith("trace=")) {
                Listener.TRACE = new PrintStream(new FileOutputStream(agentArguments.substring(6)));
            }
            if(agentArguments.startsWith("error=")) {
                Listener.ERROR = new PrintStream(new FileOutputStream(agentArguments.substring(6)));
            }
        }

        System.err.println("File leak detecter installed");
        instrumentation.addTransformer(new TransformerImpl(
            newSpec(FileOutputStream.class,"(Ljava/io/File;Z)V"),
            newSpec(FileInputStream.class, "(Ljava/io/File;)V"),
            newSpec(RandomAccessFile.class,"(Ljava/io/File;Ljava/lang/String;)V")
        ),true);
        instrumentation.retransformClasses(
                FileInputStream.class,
                FileOutputStream.class,
                RandomAccessFile.class);

//        // test code
//        for( int i=0; true; i++ ) {
//            FileOutputStream o = new FileOutputStream("target/dummy"+i);
//            o.write("abc".getBytes());
//        }
////        Listener.dump(System.out);
////        o.close();
//
////        System.out.println("after close");
////        Listener.dump(System.out);
    }

    /**
     * Creates {@link ClassTransformSpec} that intercepts
     * a constructor and the close method.
     */
    private static ClassTransformSpec newSpec(final Class c, String constructorDesc) {
        final String binName = c.getName().replace('.', '/');
        return new ClassTransformSpec(binName,
            new MethodAppender("", constructorDesc) {
                @Override
                public MethodVisitor newAdapter(final MethodVisitor base) {
                    return new MethodAdapter(super.newAdapter(base)) {
                        // surround the open/openAppend calls with try/catch block
                        // to intercept "Too many open files" exception
                        @Override
                        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
                            if(owner.equals(binName)
                            && name.startsWith("open")) {
                                CodeGenerator g = new CodeGenerator(base);
                                Label s = new Label(); // start of the try block
                                Label e = new Label();  // end of the try block
                                Label h = new Label();  // handler entry point
                                Label tail = new Label();   // where the execution continue

                                g.visitTryCatchBlock(s,e,h,"java/io/FileNotFoundException");
                                g.visitLabel(s);
                                super.visitMethodInsn(opcode, owner, name, desc);
                                g.visitLabel(e);
                                g._goto(tail);

                                g.visitLabel(h);
                                // [RESULT]
                                // catch(FileNotFoundException e) {
                                //    boolean b = e.getMessage().contains("Too many open files")
                                g.dup();
                                g.invokeVirtual("java/io/FileNotFoundException","getMessage","()Ljava/lang/String;");
                                g.ldc("Too many open files");
                                g.invokeVirtual("java/lang/String","contains","(Ljava/lang/CharSequence;)Z");

                                Label rethrow = new Label();
                                g.ifFalse(rethrow);

                                // too many open files detected
                                g.invokeAppStatic("org.kohsuke.file_leak_detecter.Listener","outOfDescriptors",
                                        new Class[0], new int[0]);

                                // rethrow the FileNotFoundException
                                g.visitLabel(rethrow);
                                g.athrow();

                                // normal execution continutes here
                                g.visitLabel(tail);
                            } else
                                // no processing
                                super.visitMethodInsn(opcode, owner, name, desc);
                        }
                    };
                }

                protected void append(CodeGenerator g) {
                    g.invokeAppStatic("org.kohsuke.file_leak_detecter.Listener","open",
                            new Class[]{Object.class, File.class},
                            new int[]{0,1});
                }
            },
            new MethodAppender("close","()V") {
                protected void append(CodeGenerator g) {
                    g.invokeAppStatic("org.kohsuke.file_leak_detecter.Listener","close",
                            new Class[]{Object.class},
                            new int[]{0});
                }
            }
        );
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy