Fixed a few bugs in dexfuzz:
- Set error level on exit when there are divergences.
- Fix cleanCodeCache not preprending adb shell.
- Fixed clearCache.
- Fixed bug in reading end of try block.
- Fixed bug in shifting try block.
- Fixed a bug reading debug info.
Test: Extract dex files from art-tests as named below and test run commands:
dexfuzz --arm --interpreter --optimizing --repeat=2 --execute --input=seeds/068-classloader.dex
dexfuzz --arm --interpreter --optimizing --repeat=2 --execute --input=seeds/510-checker-try-catch.dex
You should not get errors.
Change-Id: I0e0fb6dc27ef6f828a6427b088f6b2ca36aae243
diff --git a/tools/dexfuzz/src/dexfuzz/DexFuzz.java b/tools/dexfuzz/src/dexfuzz/DexFuzz.java
index 7337ffc..18db4c1 100644
--- a/tools/dexfuzz/src/dexfuzz/DexFuzz.java
+++ b/tools/dexfuzz/src/dexfuzz/DexFuzz.java
@@ -21,9 +21,9 @@
import dexfuzz.fuzzers.FuzzerMultipleNoExecute;
import dexfuzz.fuzzers.FuzzerSingleExecute;
import dexfuzz.fuzzers.FuzzerSingleNoExecute;
-import dexfuzz.listeners.BaseListener;
import dexfuzz.listeners.BisectionSearchListener;
import dexfuzz.listeners.ConsoleLoggerListener;
+import dexfuzz.listeners.FinalStatusListener;
import dexfuzz.listeners.LogFileListener;
import dexfuzz.listeners.MultiplexerListener;
import dexfuzz.listeners.UniqueProgramTrackerListener;
@@ -52,12 +52,15 @@
Options.usage();
}
- // Create the Listener, which will listen for events and report them.
- BaseListener listener = null;
+
+ // Create a Listener that is responsible for multiple Listeners.
+ MultiplexerListener multipleListener = new MultiplexerListener();
+ multipleListener.setup();
+
+ FinalStatusListener statusListener = new FinalStatusListener();
+ multipleListener.addListener(statusListener);
+
if (Options.repeat > 1 && Options.execute) {
- // Create a Listener that is responsible for multiple Listeners.
- MultiplexerListener multipleListener = new MultiplexerListener();
- multipleListener.setup();
// Add the live updating listener, but only if we're not printing out lots of logs.
if (!Log.likelyToLog()) {
multipleListener.addListener(new UpdatingConsoleListener());
@@ -73,22 +76,21 @@
}
// Add the unique program tracker.
multipleListener.addListener(new UniqueProgramTrackerListener(Options.uniqueDatabaseFile));
- listener = multipleListener;
} else {
// Just use the basic listener.
- listener = new ConsoleLoggerListener();
+ multipleListener.addListener(new ConsoleLoggerListener());
}
// Create the Fuzzer that uses a particular strategy for fuzzing.
Fuzzer fuzzer = null;
if ((Options.repeat > 1) && Options.execute) {
- fuzzer = new FuzzerMultipleExecute(listener);
+ fuzzer = new FuzzerMultipleExecute(multipleListener);
} else if ((Options.repeat > 1) && !Options.execute) {
- fuzzer = new FuzzerMultipleNoExecute(listener);
+ fuzzer = new FuzzerMultipleNoExecute(multipleListener);
} else if ((Options.repeat == 1) && Options.execute) {
- fuzzer = new FuzzerSingleExecute(listener);
+ fuzzer = new FuzzerSingleExecute(multipleListener);
} else if ((Options.repeat == 1) && !Options.execute) {
- fuzzer = new FuzzerSingleNoExecute(listener);
+ fuzzer = new FuzzerSingleNoExecute(multipleListener);
} else {
Log.errorAndQuit("Invalid options provided, desired fuzzer unknown.");
}
@@ -101,6 +103,10 @@
fuzzer.shutdown();
// Cleanup the Listener.
- listener.shutdown();
+ multipleListener.shutdown();
+
+ if (!statusListener.isSuccessful()) {
+ System.exit(1);
+ }
}
}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Device.java b/tools/dexfuzz/src/dexfuzz/executors/Device.java
index 72f73b8..ba1365e 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/Device.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/Device.java
@@ -272,7 +272,7 @@
}
public void cleanCodeCache(Architecture architecture, String testLocation, String programName) {
- String command = "rm -f " + getCacheLocation(architecture)
+ String command = getExecutionPrefixWithAdb("shell") + "rm -f " + getCacheLocation(architecture)
+ getOatFileName(testLocation, programName);
executeCommand(command, false);
}
@@ -280,7 +280,11 @@
public void pushProgramToDevice(String programName, String testLocation) {
assert(!isHost);
if (!programPushed) {
- executeCommand(getExecutionPrefixWithAdb("push") + programName + " " + testLocation, false);
+ String command = getExecutionPrefixWithAdb("push") + programName + " " + testLocation;
+ ExecutionResult result = executeCommand(command, false);
+ if (result.returnValue != 0) {
+ Log.errorAndQuit("Could not ADB PUSH program to device.");
+ }
programPushed = true;
}
}
diff --git a/tools/dexfuzz/src/dexfuzz/listeners/FinalStatusListener.java b/tools/dexfuzz/src/dexfuzz/listeners/FinalStatusListener.java
new file mode 100644
index 0000000..0f85f62
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/listeners/FinalStatusListener.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dexfuzz.listeners;
+
+import java.util.List;
+import java.util.Map;
+
+import dexfuzz.executors.Executor;
+
+/**
+ * Counts divergences as they appear and checks if the testing was successful
+ * or not. Testing is successful if all divergences found are either self
+ * divergent or caused by differences in architectures.
+ */
+public class FinalStatusListener extends BaseListener {
+ private long divergence;
+ private long selfDivergent;
+ private long architectureSplit;
+
+ @Override
+ public void handleDivergences(Map<String, List<Executor>> outputMap) {
+ divergence++;
+ }
+
+ @Override
+ public void handleSelfDivergence() {
+ selfDivergent++;
+ }
+
+ @Override
+ public void handleArchitectureSplit() {
+ architectureSplit++;
+ }
+
+ public boolean isSuccessful() {
+ return (divergence - selfDivergent - architectureSplit) == 0;
+ }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/CodeTranslator.java b/tools/dexfuzz/src/dexfuzz/program/CodeTranslator.java
index 650501b..5335d15 100644
--- a/tools/dexfuzz/src/dexfuzz/program/CodeTranslator.java
+++ b/tools/dexfuzz/src/dexfuzz/program/CodeTranslator.java
@@ -259,8 +259,15 @@
// Get the MInsns that form the start and end of the try block.
int startLocation = tryItem.startAddr;
mTryBlock.startInsn = insnLocationMap.get(startLocation);
- int endLocation = tryItem.startAddr + tryItem.insnCount;
+
+ // The instructions vary in size, so we have to find the last instruction in the block in a
+ // few tries.
+ int endLocation = tryItem.startAddr + tryItem.insnCount - 1;
mTryBlock.endInsn = insnLocationMap.get(endLocation);
+ while ((mTryBlock.endInsn == null) && (endLocation >= startLocation)) {
+ endLocation--;
+ mTryBlock.endInsn = insnLocationMap.get(endLocation);
+ }
// Sanity checks.
if (mTryBlock.startInsn == null) {
@@ -356,8 +363,9 @@
TryItem tryItem = codeItem.tries[tryItemIdx];
tryItem.startAddr = mTryBlock.startInsn.location;
- tryItem.insnCount =
- (short) (mTryBlock.endInsn.location - mTryBlock.startInsn.location);
+ int insnCount = mTryBlock.endInsn.location - mTryBlock.startInsn.location +
+ mTryBlock.endInsn.insn.getSize();
+ tryItem.insnCount = (short) insnCount;
// Get the EncodedCatchHandler.
EncodedCatchHandler encodedCatchHandler =
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/TryBlockShifter.java b/tools/dexfuzz/src/dexfuzz/program/mutators/TryBlockShifter.java
index 1bf6463..55e3e60 100644
--- a/tools/dexfuzz/src/dexfuzz/program/mutators/TryBlockShifter.java
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/TryBlockShifter.java
@@ -81,12 +81,15 @@
@Override
protected boolean canMutate(MutatableCode mutatableCode) {
- if (mutatableCode.triesSize > 0) {
- return true;
+ if (mutatableCode.triesSize == 0) {
+ Log.debug("Method contains no tries.");
+ return false;
}
-
- Log.debug("Method contains no tries.");
- return false;
+ if (mutatableCode.getInstructionCount() <= 1) {
+ Log.debug("Not enough instructions to shift try block.");
+ return false;
+ }
+ return true;
}
@Override
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/DebugInfoItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/DebugInfoItem.java
index 922ee58..561e986 100644
--- a/tools/dexfuzz/src/dexfuzz/rawdex/DebugInfoItem.java
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/DebugInfoItem.java
@@ -16,6 +16,8 @@
package dexfuzz.rawdex;
+import dexfuzz.Log;
+
import java.io.IOException;
// Right now we are not parsing debug_info_item, just take the raw size
@@ -32,6 +34,11 @@
file.getOffsetTracker().getNewOffsettable(file, this);
data = new byte[size];
file.read(data);
+
+ // Since we are not parsing the section, ensure that the last byte is DBG_END_SEQUENCE.
+ if (data[size - 1] != 0) {
+ Log.errorAndQuit("Error reading debug_info_item. The last byte is not DBG_END_SEQUENCE.");
+ }
}
@Override
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/MapList.java b/tools/dexfuzz/src/dexfuzz/rawdex/MapList.java
index 080b5a4..729aa71 100644
--- a/tools/dexfuzz/src/dexfuzz/rawdex/MapList.java
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/MapList.java
@@ -162,10 +162,15 @@
case MapItem.TYPE_DEBUG_INFO_ITEM:
{
// We aren't interested in updating the debug data, so just read it as a blob.
- int start = mapItem.offset.getOriginalOffset();
- int end = mapItems.get(mapItemIdx + 1).offset.getOriginalOffset();
- int size = end - start;
- rawDexFile.debugInfoItem = new DebugInfoItem(size);
+ long start = mapItem.offset.getOriginalOffset();
+ long end = 0;
+ if (mapItemIdx + 1 == mapItems.size()) {
+ end = file.length();
+ } else {
+ end = mapItems.get(mapItemIdx + 1).offset.getOriginalOffset();
+ }
+ long size = end - start;
+ rawDexFile.debugInfoItem = new DebugInfoItem((int)size);
rawDexFile.debugInfoItem.read(file);
break;
}