Skip to content

Commit 5992ad2

Browse files
authored
Merge pull request #67 from TheSoftwareDesignLab/callGraph
remove dead-code mutants
2 parents 280a219 + 070e144 commit 5992ad2

25 files changed

+686
-68890
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>edu.uniandes.thesoftwaredesignlab</groupId>
66
<artifactId>MutAPK</artifactId>
7-
<version>1.0.0</version>
7+
<version>2.0.0</version>
88
<name>MutAPK</name>
99
<description>Android Application Mutation Testion over APK files</description>
1010
<build>

src/main/java/edu/uniandes/tsdl/mutapk/MutAPK.java

Lines changed: 174 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
import java.io.FileWriter;
88
import java.io.FilenameFilter;
99
import java.io.IOException;
10-
import java.io.UnsupportedEncodingException;
1110
import java.nio.file.Paths;
1211
import java.util.HashMap;
1312
import java.util.List;
13+
import java.util.Map.Entry;
1414
import java.util.Set;
1515

1616
import javax.xml.parsers.ParserConfigurationException;
1717

18+
import org.antlr.runtime.RecognitionException;
1819
import org.json.simple.JSONObject;
1920
import org.json.simple.parser.JSONParser;
2021
import org.json.simple.parser.ParseException;
@@ -26,8 +27,12 @@
2627
import edu.uniandes.tsdl.mutapk.hashfunction.sha3.ApkHashOrder;
2728
import edu.uniandes.tsdl.mutapk.hashfunction.sha3.ApkHashSeparator;
2829
import edu.uniandes.tsdl.mutapk.helper.APKToolWrapper;
30+
import edu.uniandes.tsdl.mutapk.helper.ASTHelper;
31+
import edu.uniandes.tsdl.mutapk.helper.CallGraphHelper;
2932
import edu.uniandes.tsdl.mutapk.helper.Helper;
33+
import edu.uniandes.tsdl.mutapk.model.CallGraphNode;
3034
import edu.uniandes.tsdl.mutapk.model.MutationType;
35+
import edu.uniandes.tsdl.mutapk.model.SmaliAST;
3136
import edu.uniandes.tsdl.mutapk.model.location.MutationLocation;
3237
import edu.uniandes.tsdl.mutapk.operators.OperatorBundle;
3338
import edu.uniandes.tsdl.mutapk.processors.MutationsProcessor;
@@ -54,6 +59,7 @@ public class MutAPK {
5459
static String extraPath = "";
5560
static String operatorsDir = "";
5661
static boolean multithread = true;
62+
static boolean ignoreDeadCode = true;
5763
static String selectionStrategy = "";
5864

5965
// Optional arguments
@@ -63,7 +69,13 @@ public class MutAPK {
6369
static int confidenceLevel = -1;
6470
static int marginError = -1;
6571

66-
static OperatorBundle operatorBundle;
72+
static OperatorBundle operatorBundle;
73+
74+
static HashMap<String, SmaliAST> smaliASTs = new HashMap<String, SmaliAST>();
75+
76+
static HashMap<String, HashMap<String, CallGraphNode>> callGraph = new HashMap<String, HashMap<String, CallGraphNode>>();
77+
78+
static HashMap<String, HashMap<String, CallGraphNode>> deadCode = new HashMap<String, HashMap<String, CallGraphNode>>();
6779

6880
public static void main(String[] args) {
6981
try {
@@ -83,7 +95,7 @@ public static void main(String[] args) {
8395
}
8496
}
8597

86-
public static void runMutAPK(String[] args) throws NumberFormatException, FileNotFoundException, IOException, ParseException, MutAPKException, InterruptedException, ParserConfigurationException, SAXException {
98+
public static void runMutAPK(String[] args) throws NumberFormatException, FileNotFoundException, IOException, ParseException, MutAPKException, InterruptedException, ParserConfigurationException, SAXException, RecognitionException {
8799

88100
// Read JSON config file
89101
readConfig(args[0]);
@@ -103,15 +115,85 @@ public static void runMutAPK(String[] args) throws NumberFormatException, FileNo
103115
String apkAbsolutePath = APKToolWrapper.openAPK(apkPath, extraPath);
104116
System.out.println("--------------------------------------");
105117

118+
119+
//--------------------------------------------
120+
// Run detection phase for AST-based detectors
121+
//--------------------------------------------
122+
// Generate HashMap with all the ASTs
123+
SourceCodeProcessor scp = new SourceCodeProcessor();
124+
scp.generateASTsMap(extraPath, appName, smaliASTs);
125+
if(ignoreDeadCode) {
126+
127+
Long initTime = System.currentTimeMillis();
128+
129+
// Generate the Call Graph
130+
System.out.println("## Call Graph Results");
131+
System.out.println("");
132+
System.out.println("Method Type | Amount");
133+
System.out.println("----------------|---------");
134+
135+
callGraph = CallGraphHelper.getCallGraph(smaliASTs);
136+
int cNDC = 0;
137+
int cDC = 0;
138+
139+
for(Entry<String, HashMap<String, CallGraphNode>> entry : callGraph.entrySet()) {
140+
for(Entry<String, CallGraphNode> entryy : entry.getValue().entrySet()) {
141+
CallGraphNode cGN = entryy.getValue();
142+
boolean isDeadCode = methodIsDeadCode(cGN);
143+
if(!isDeadCode) {
144+
cNDC++;
145+
} else {
146+
if(deadCode.get(cGN.getUnitName())!=null) {
147+
deadCode.get(cGN.getUnitName()).put(cGN.getId(), cGN);
148+
} else {
149+
HashMap<String, CallGraphNode> temp = new HashMap<String, CallGraphNode>();
150+
temp.put(cGN.getId(), cGN);
151+
deadCode.put(cGN.getUnitName(), temp);
152+
}
153+
cDC++;
154+
}
155+
}
156+
}
157+
System.out.println("CalledAndDefined | "+cNDC);
158+
System.out.println("DeadCode | "+cDC);
159+
System.out.println("\n----------------------------------");
160+
161+
// Check Dead Code Methods
162+
163+
// for(Entry<String, HashMap<String, CallGraphNode>> entry : deadCode.entrySet()) {
164+
// System.out.println(entry.getKey());
165+
// for(Entry<String, CallGraphNode> entryy : entry.getValue().entrySet()) {
166+
// System.out.println(" "+entryy.getKey());
167+
// }
168+
// }
169+
170+
// Prune ASTs
171+
for(Entry<String, SmaliAST> entry: smaliASTs.entrySet()) {
172+
if(deadCode.get(entry.getKey())!=null) {
173+
smaliASTs.put(entry.getKey(), ASTHelper.pruneAST(entry.getValue(),deadCode.get(entry.getKey())));
174+
}
175+
}
176+
177+
Long duration = (System.currentTimeMillis()-initTime);
178+
System.out.println("");
179+
System.out.println("> It took "+duration+" miliseconds to remove dead code from APK analysis.");
180+
181+
182+
}
183+
106184
// Text-Based operators selected
107185
List<MutationLocationDetector> textBasedDetectors = operatorBundle.getTextBasedDetectors();
108186

109187
// Run detection phase for Text-based detectors
110188
HashMap<MutationType, List<MutationLocation>> locations = TextBasedDetectionsProcessor.process("temp", textBasedDetectors);
111189

112-
// Run detection phase for AST-based detectors
113-
SourceCodeProcessor scp = new SourceCodeProcessor(operatorBundle);
114-
locations.putAll(scp.processFolder("temp", extraPath, appName));
190+
// Generate PFP over pruned ASTs
191+
for(Entry<String, SmaliAST> entry : smaliASTs.entrySet()) {
192+
SmaliAST temp = entry.getValue();
193+
194+
HashMap<MutationType, List<MutationLocation>> fileLocations = ASTHelper.findLocations(temp, operatorBundle);
195+
appendLocations(fileLocations, locations);
196+
}
115197

116198
// Report the statistics of the found Potential Fault Locations
117199
Set<MutationType> keys = locations.keySet();
@@ -126,11 +208,6 @@ public static void runMutAPK(String[] args) throws NumberFormatException, FileNo
126208
System.out.println(list.size() + " | " + mutationType);
127209
}
128210

129-
// Check if the amount of PFLocations is lower than the requested by the user
130-
if(totalMutants < amountMutants) {
131-
throw new MutAPKException("The total of mutants need to be greater than the amount of mutants asked");
132-
}
133-
System.out.println("");
134211

135212
// Build MutationLocation List
136213
List<MutationLocation> mutationLocationList = MutationLocationListBuilder.buildList(locations);
@@ -139,47 +216,90 @@ public static void runMutAPK(String[] args) throws NumberFormatException, FileNo
139216
System.out.println();
140217
System.out.println("--------------------------------------");
141218

142-
// Select Selector
143-
switch (selectionStrategy) {
144-
case AMOUNT_MUTANTS_SS:
145-
SelectorAmountMutantsMethod selectorAmountMutantsMethod = new SelectorAmountMutantsMethod();
146-
SelectorAmountMutants selectorAmountMutants = new SelectorAmountMutants(false, false, totalMutants,
147-
amountMutants);
148-
mutationLocationList = selectorAmountMutantsMethod.mutantSelector(locations, selectorAmountMutants);
149-
break;
150-
case REPRESENTATIVE_SUBSET_SS:
151-
SelectorConfidenceInterval selectorConfidenceInterval = new SelectorConfidenceInterval(true, false,
152-
totalMutants, isRSPerOPerator, confidenceLevel, marginError);
153-
SelectorConfidenceIntervalMethod CIMS = new SelectorConfidenceIntervalMethod();
154-
mutationLocationList = CIMS.mutantSelector(locations, selectorConfidenceInterval);
155-
break;
156-
default:
157-
break;
219+
if(ignoreDeadCode) {
220+
// Select Selector
221+
switch (selectionStrategy) {
222+
case AMOUNT_MUTANTS_SS:
223+
SelectorAmountMutantsMethod selectorAmountMutantsMethod = new SelectorAmountMutantsMethod();
224+
SelectorAmountMutants selectorAmountMutants = new SelectorAmountMutants(false, false, totalMutants,
225+
amountMutants);
226+
mutationLocationList = selectorAmountMutantsMethod.mutantSelector(locations, selectorAmountMutants);
227+
break;
228+
case REPRESENTATIVE_SUBSET_SS:
229+
SelectorConfidenceInterval selectorConfidenceInterval = new SelectorConfidenceInterval(true, false,
230+
totalMutants, isRSPerOPerator, confidenceLevel, marginError);
231+
SelectorConfidenceIntervalMethod CIMS = new SelectorConfidenceIntervalMethod();
232+
mutationLocationList = CIMS.mutantSelector(locations, selectorConfidenceInterval);
233+
break;
234+
default:
235+
break;
236+
}
237+
System.out.println("");
238+
239+
System.out.println("## Mutation Process Log");
240+
System.out.println();
241+
System.out.println("```sh");
242+
243+
// Execute mutation phase
244+
MutationsProcessor mProcessor = new MutationsProcessor("temp", appName, mutantsFolder);
245+
246+
// Create de apkhash for the base folder
247+
File manifest = new File(apkAbsolutePath + File.separator + "AndroidManifest.xml");
248+
File smali = new File(apkAbsolutePath + File.separator + "smali");
249+
File resource = new File(apkAbsolutePath + File.separator + "res");
250+
251+
252+
// Create ApkHashSeparator
253+
ApkHashSeparator apkHashSeparator = mProcessor.generateApkHashSeparator(manifest, smali, resource, 0);
254+
// Add the base apkHashSeparator
255+
ApkHashOrder.getInstance().setApkHashSeparator(apkHashSeparator);
256+
257+
if (multithread) {
258+
mProcessor.processMultithreaded(mutationLocationList, extraPath, apkName);
259+
} else {
260+
mProcessor.process(mutationLocationList, extraPath, apkName);
261+
}
158262
}
159-
System.out.println("");
160-
161-
System.out.println("## Mutation Process Log");
162-
System.out.println();
163-
System.out.println("```sh");
164263

165-
// Execute mutation phase
166-
MutationsProcessor mProcessor = new MutationsProcessor("temp", appName, mutantsFolder);
264+
}
167265

168-
// Create de apkhash for the base folder
169-
File manifest = new File(apkAbsolutePath + File.separator + "AndroidManifest.xml");
170-
File smali = new File(apkAbsolutePath + File.separator + "smali");
171-
File resource = new File(apkAbsolutePath + File.separator + "res");
266+
private static boolean methodIsDeadCode(CallGraphNode cGN) {
172267

268+
String[] exceptions = new String[] {
269+
"<init>","<clinit>","init","onClick","onCreate","onOptionsItemSelected","onCreateOptionsMenu","onResume","update",
270+
"query","getType","insert","doInBackground","onPostExecute","delete","clone","onCreateDialog","onCancel","onRestoreInstanceState",
271+
"onSaveInstanceState","onRetainNonConfigurationInstance","run","getParent","onNothingSelected","onItemSelected","onProgressUpdate",
272+
"onPreExecute", "onReceive","toString","onItemClick","getUri","onPreferenceClick","onTabChanged","getDropDownView","getCount",
273+
"getViewTypeCount","getView","registerDataSetObserver","saved","isEnabled","onActivityResult","unregisterDataSetObserver","attach",
274+
"onChange","isIntentAvailable","onDateChanged","onContextItemSelected", "onCreateContextMenu"
275+
};
173276

174-
// Create ApkHashSeparator
175-
ApkHashSeparator apkHashSeparator = mProcessor.generateApkHashSeparator(manifest, smali, resource, 0);
176-
// Add the base apkHashSeparator
177-
ApkHashOrder.getInstance().setApkHashSeparator(apkHashSeparator);
277+
if(cGN.getCallers().size()>0) {
278+
return false;
279+
}
178280

179-
if (multithread) {
180-
mProcessor.processMultithreaded(mutationLocationList, extraPath, apkName);
181-
} else {
182-
mProcessor.process(mutationLocationList, extraPath, apkName);
281+
for (int i = 0; i < exceptions.length; i++) {
282+
if(cGN.getId().startsWith(exceptions[i]+"(")) {
283+
return false;
284+
}
285+
}
286+
return true;
287+
288+
}
289+
290+
private static void appendLocations(HashMap<MutationType, List<MutationLocation>> source, HashMap<MutationType, List<MutationLocation>> target){
291+
292+
for(Entry<MutationType, List<MutationLocation>> entry : source.entrySet()){
293+
List<MutationLocation> sourceLocations = source.get(entry.getKey());
294+
List<MutationLocation> targetLocations = target.get(entry.getKey());
295+
296+
if(targetLocations != null){
297+
targetLocations.addAll(sourceLocations);
298+
} else {
299+
targetLocations = sourceLocations;
300+
}
301+
302+
target.put(entry.getKey(), targetLocations);
183303
}
184304

185305
}
@@ -194,9 +314,10 @@ private static void readConfig(String configFilePath) throws NumberFormatExcepti
194314
appName = getVariableValuesString(jsonObject, "appName");
195315
mutantsFolder = getVariableValuesString(jsonObject, "mutantsFolder");
196316
multithread = Boolean.valueOf(getVariableValuesString(jsonObject, "multithreadExec"));
317+
ignoreDeadCode = Boolean.valueOf(getOptionalVariableValuesString(jsonObject, "ignoreDeadCode"));
197318
selectionStrategy = getVariableValues(jsonObject, "selectionStrategy");
198-
operatorsDir = getOptionalVariableValuesString(jsonObject, "operatorsDir");
199-
extraPath = getOptionalVariableValuesString(jsonObject, "extraPath");
319+
operatorsDir = getVariableValuesString(jsonObject, "operatorsDir");
320+
extraPath = getVariableValuesString(jsonObject, "extraPath");
200321

201322
// Impreme valor por defecto
202323
System.out.println("");
@@ -210,6 +331,7 @@ private static void readConfig(String configFilePath) throws NumberFormatExcepti
210331
System.out.println("extraPath | " + extraPath);
211332
System.out.println("operatorsDir | " + operatorsDir);
212333
System.out.println("multithread | " + multithread);
334+
System.out.println("ignoreDeadCode | " + ignoreDeadCode);
213335
System.out.println("selectionStrategy | " + selectionStrategy);
214336

215337
JSONObject selectionParameters = (JSONObject) jsonObject.get("selectionParameters");
@@ -246,15 +368,14 @@ private static void readConfig(String configFilePath) throws NumberFormatExcepti
246368
}
247369

248370
private static void checkAndPrepareParameters() throws MutAPKException, IOException {
249-
// TODO Auto-generated method stub
250371

251372
// Preprocess paths to fit to OS filsesystem format
252373
String os = System.getProperty("os.name").toLowerCase();
253374
if (os.indexOf("win") >= 0) {
254375
mutantsFolder = mutantsFolder.replaceFirst("/", File.separator+File.separator) +File.separator;
255376
apkPath = apkPath.replaceAll("/", File.separator+File.separator);
256377
apkName = apkPath.substring(apkPath.lastIndexOf("\\"));
257-
378+
258379
extraPath = extraPath.equals("")?"":extraPath.replaceAll("/", File.separator+File.separator) + File.separator;
259380
operatorsDir = operatorsDir.equals("")?"":operatorsDir.replaceAll("/", File.separator+File.separator) + File.separator;
260381
} else {
@@ -281,7 +402,7 @@ private static void checkAndPrepareParameters() throws MutAPKException, IOExcept
281402
}
282403
System.out.println(operFolderFO.getCanonicalPath().toString());
283404
File[] properties = operFolderFO.listFiles(new FilenameFilter() {
284-
405+
285406
@Override
286407
public boolean accept(File dir, String name) {
287408
return name.endsWith("operators.properties");
@@ -296,7 +417,7 @@ public boolean accept(File dir, String name) {
296417
throw new MutAPKException("Path to extra folder is not correct. The path does not exist.");
297418
}
298419
File[] extraFO = extraFolderFO.listFiles(new FilenameFilter() {
299-
420+
300421
@Override
301422
public boolean accept(File dir, String name) {
302423
return ( name.endsWith("apktool.jar") || name.endsWith("uber-apk-signer.jar") || name.endsWith("materialistic.jks"));
@@ -345,7 +466,7 @@ private static String getOptionalVariableValuesString(JSONObject jsonObject, Str
345466
if (temp != null) {
346467
return temp;
347468
} else {
348-
return "";
469+
return "true";
349470
}
350471
}
351472

src/main/java/edu/uniandes/tsdl/mutapk/detectors/code/visitors/APICallVO.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@ public class APICallVO {
66

77
private CommonTree tree;
88
private int line;
9-
private String filePath;
109
private int[] muTypes;
1110

12-
public APICallVO(CommonTree tree, int line, String filePath, int[] muTypes) {
11+
public APICallVO(CommonTree tree, int line, int[] muTypes) {
1312
super();
1413
this.tree = tree;
1514
this.line = line;
16-
this.filePath = filePath;
1715
this.muTypes = muTypes;
1816
}
1917

@@ -29,12 +27,6 @@ public int getLine() {
2927
public void setLine(int line) {
3028
this.line = line;
3129
}
32-
public String getFilePath() {
33-
return filePath;
34-
}
35-
public void setFilePath(String filePath) {
36-
this.filePath = filePath;
37-
}
3830

3931
public int[] getMuTypes() {
4032
return muTypes;

0 commit comments

Comments
 (0)