-1

I am writing an apk analysis program. I cannot go deep into details because it's research material. However, the point is that from time to time when I execute the analysis routine, I get the following message:

Exception: java.lang.NullPointerException thrown from the UncaughtExceptionHandler in thread "main"

This happens if I do not override the UncaughtExceptionHandler and also if I do, as you'll see from the code below. Since there is no stacktrace data I cannot know where that exception is coming from and what its cause really is.

I hope you can help me...

This is only the main code. There are three main operation that I have to execute. In order not to disclose particular information, I renamed them to A, B and C

public class MainScannerSequential {
public static void main(String[] args) throws ParserConfigurationException, IOException, InterruptedException {
    final File target = new File(args[1]);
    final File result = new File(args[2]);
    final Options options = new Options(args);

    silentMode = options.contains("-s");
    noA = options.contains("-nl");
    noC = options.contains("-ne");

    aStrategy = Factory.createA();
    bScanner = Factory.createB();
    cDetector = Factory.createcC();

    examinedFiles = new PersistentFileList(Globals.EXAMINED_FILES_LIST_FILE);

    if (result.exists())
        resultsWriter = new BufferedWriter(new FileWriter(result, true));
    else {
        resultsWriter = new BufferedWriter(new FileWriter(result));
        resultsWriter.write("***");
        resultsWriter.newLine();
    }

    if (Globals.PERFORMANCE_FILE.exists())
        performancesWriter = new BufferedWriter(new FileWriter(Globals.PERFORMANCE_FILE, true));
    else {
        performancesWriter = new BufferedWriter(new FileWriter(Globals.PERFORMANCE_FILE));
        performancesWriter.write("***");
        performancesWriter.newLine();
    }

    Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            if ((t != null) && (t.getName() != null))
                System.out.println("In thread : " + t.getName());

            if ((e != null) && (e.getMessage() != null)) {
                System.out.println(e.getClass().getName() + ": " + e.getMessage());
                if (e.getStackTrace() != null)
                    for (StackTraceElement ste : e.getStackTrace())
                        if (ste != null)
                            System.out.println(ste.getFileName() + " at line " + ste.getLineNumber());
            }
        }
    });

    if (target.isDirectory()) {
        enumerateDirectory(target);
    } else {
        String name = target.getName().toLowerCase();

        if (name.endsWith(".apklist"))
            readFileList(target);
        else if (name.endsWith(".apk"))
            checkFile(target);
    }

    closeWriters();
}

private static void println(String message) {
    if (!silentMode)
        System.out.println(message);
}

private static void print(String message) {
    if (!silentMode)
        System.out.print(message);
}


private static void enumerateDirectory(File directory) {
    for (File file : directory.listFiles()) {
        checkFile(file);

        if (file.isDirectory())
            enumerateDirectory(file);
    }
}

private static void readFileList(File file) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(file));
        String line = null;

        while((line = reader.readLine()) != null) {
            File readFile = new File(line);

            if (readFile.exists())
                checkFile(readFile);
        }

        reader.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static void checkFile(File file) {
    if (examinedFiles.contains(file)) {
        println("Skipped: " + file.getName());
        return;
    }

    if (!file.getName().toLowerCase().endsWith(".apk")) {
        return;
    }

    final Wrapper<Double> unpackingTime = new Wrapper<Double>(0.0);
    final ApplicationData data = unpack(file, unpackingTime);

    if (data == null) {
        return;
    }

    scanData(data, unpackingTime.value);
}


private static ApplicationData unpack(final File file, final Wrapper<Double> unpackingTime) {
    final Wrapper<ApplicationData> resultWrapper = new Wrapper<ApplicationData>(null);
    final Wrapper<Exception> exceptionWrapper = new Wrapper<Exception>(null);

    println("Unpacking: " + file.getName());

    unpackingTime.value = Stopwatch.time(new Runnable() {
        @Override
        public void run() {
            try {
                resultWrapper.value = ApplicationData.open(file);
            } catch (Exception e) {
                exceptionWrapper.value = e;
            }
        }
    });

    if (resultWrapper.value != null)
        println("Unpacked: " + file.getName());
    else if (exceptionWrapper.value != null)
        println("Dropped: " + file.getName() + " : " + exceptionWrapper.value.getMessage());

    return resultWrapper.value;
}

private static void scanData(final ApplicationData applicationData, Double unpackingTime) {
    String apkName = applicationData.getDecodedPackage().getOriginalApk().getAbsolutePath();
    println("Submitted: " + apkName);

    examinedFiles.add(applicationData.getDecodedPackage().getOriginalApk());

    final Wrapper<Boolean> aDetected = new Wrapper<Boolean>(false);
    final Wrapper<Result> bDetected = new Wrapper<Result>(new Result());
    final Wrapper<Boolean> cDetected = new Wrapper<Boolean>(false);

    final Wrapper<Double> aDetectionTime = new Wrapper<Double>((double)ANALYSIS_TIMEOUT);
    final Wrapper<Double> bDetectionTime = new Wrapper<Double>((double)ANALYSIS_TIMEOUT);
    final Wrapper<Double> cDetectionTime = new Wrapper<Double>((double)ANALYSIS_TIMEOUT);

    ExecutorService executor = Executors.newFixedThreadPool(3);

    executor.submit(new Runnable() {
        @Override
        public void run() {
            textDetectionTime.value = Stopwatch.time(new Runnable() {
                @Override
                public void run() {
                    bScanner.setUnpackedApkDirectory(applicationData.getDecodedPackage().getDecodedDirectory());
                    bDetected.value = bScanner.evaluate();
                }
            });
        }
    });

    if (!noA)
        executor.submit(new Runnable() {
            @Override
            public void run() {
                lockDetectionTime.value = Stopwatch.time(new Runnable() {
                    @Override
                    public void run() {
                        aStrategy.setTarget(applicationData.getDecodedPackage());
                        aDetected.value = aStrategy.detect();
                    }
                });
            }
        });

    if (!noC)
        executor.submit(new Runnable() {
            @Override
            public void run() {
                encryptionDetectionTime.value = Stopwatch.time(new Runnable() {
                    @Override
                    public void run() {
                        cDetector.setTarget(applicationData.getDecodedPackage());
                        cDetected.value = cDetector.detect();
                    }
                });
            }
        });

    boolean timedOut = false;
    executor.shutdown();

    try {
        if (!executor.awaitTermination(ANALYSIS_TIMEOUT, TimeUnit.SECONDS)) {
            executor.shutdownNow();
            timedOut = true;
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    try {
        resultsWriter.write(String.format("%s, %b, %b, %f, %b, \"%s\", %b\n",
                apkName,
                aDetected.value,
                bDetected.value.isAccepted(),
                bDetected.value.getScore(),
                cDetected.value,
                bDetected.value.getComment(),
                timedOut));

        performancesWriter.write(String.format("%s, %f, %f, %f, %f, %d, %dl, %dl\n",
                apkName,
                aDetectionTime.value,
                bDetectionTime.value,
                cDetectionTime.value,
                unpackingTime,
                applicationData.getSmaliLoader().getClassesCount(),
                applicationData.getSmaliLoader().getTotalClassesSize(),
                applicationData.getDecodedPackage().getOriginalApk().length()));

        resultsWriter.flush();
        performancesWriter.flush();
    } catch (IOException e) { }

    // No longer deleting temp files

    if (!timedOut)
        println("Completed: " + apkName);
    else {
        print("Timeout");

        if (bDetectionTime.value == 0) print(" TextDetection");
        if (!noA && (aDetectionTime.value == 0)) print(" LockDetection");
        if (!noC && (cDetectionTime.value == 0)) print(" EncryptionDetection");

        println(": " + apkName);
    }
}


private static void closeWriters() throws IOException {
    resultsWriter.close();
    performancesWriter.close();
    examinedFiles.dispose();
}


private static final int ANALYSIS_TIMEOUT = 40; // seconds

private static Boolean silentMode = false;
private static Boolean noA = false;
private static Boolean noC = false;

private static PersistentFileList examinedFiles;
private static BufferedWriter resultsWriter;
private static BufferedWriter performancesWriter;

private static A aStrategy;
private static B bScanner;
private static C cDetector;
}

I labeled the question as multithread because the same happens in the multithreaded version, which I serialized using this code in order to debug that error. Notice that the NullPointerException is in thread main, not in other Executor-spawned threads.

Totem
  • 454
  • 5
  • 18
  • Did you check where the program halts using `System.out.println()` ? – Prerak Sola Jan 22 '15 at 15:53
  • Please make a *minimal* code sample that demonstrates your problem; the code you posted doesn't compile because it depends on all kind of other classes (60 compile errors). My tip for you: wrap the whole code in your UncaughtExceptionHandler in a try/catch(Throwable t) block that has `{ t.printStackTrace(); }` in it, to find out where the error occurs. – Erwin Bolwidt Jan 22 '15 at 15:54
  • Just out of curiosity: did you honestly expect anybody here to wade through several hundred lines of incomplete code and debug your problem? – Voo Jan 22 '15 at 16:04
  • Since the error message says that the problem occurs within your `UncaughtExceptionHandler` I recommend setting a breakpoint right at the beginning of your `UncaughtExceptionHandler` and debug it step by step until you found out what’s happening. – Holger Jan 22 '15 at 18:18
  • I cannot provide a minimal code that has the same issue since I don't know what raises the issue. I already tried putting a try-catch and even a breakpoint in the exception handler and I found it is never reached. Additionally, if I don't provide the code, someone will say that the problem is too generic to solve. And I cannot debug step by step because the issue arises randomly when analyzing hundreds of thousands of samples. Even testing on the last analyzed sample before crashing doesn't replicate the issue. – Totem Jan 22 '15 at 18:40

1 Answers1

2

If you don't have a stack trace, it could mean that there are some crazy exceptions thrown in your code (see Exception without stack trace in Java), but it is more likely that the JVM is re-using exception objects as a performance optimization and the -XX:-OmitStackTraceInFastThrow JVM option would help you.

See this article for details

Community
  • 1
  • 1
lbalazscs
  • 17,474
  • 7
  • 42
  • 50