Reviewed By: sblackshear Differential Revision: D3619339 fbshipit-source-id: 46f3cc1master
parent
33b417c280
commit
9a79e74380
@ -0,0 +1,73 @@
|
|||||||
|
sources = glob(['**/*.java','**/*.json'])
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
'//dependencies/java/android/support/v4:android-support-v4',
|
||||||
|
'//infer/annotations:annotations',
|
||||||
|
'//infer/lib/java/android:android',
|
||||||
|
]
|
||||||
|
|
||||||
|
java_library(
|
||||||
|
name = 'checkers',
|
||||||
|
srcs = sources,
|
||||||
|
deps = dependencies,
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
out = 'out'
|
||||||
|
inferconfig_file = '$(location //infer/tests/codetoanalyze/java:inferconfig)'
|
||||||
|
copy_inferconfig = ' '.join(['cp', inferconfig_file, '$SRCDIR'])
|
||||||
|
clean_cmd = ' '.join(['rm', '-rf', out])
|
||||||
|
classpath = ':'.join([('$(classpath ' + path + ')') for path in dependencies])
|
||||||
|
|
||||||
|
def mk_infer_cmd(tag, srcs, stacktrace):
|
||||||
|
infer_cmd_main = ' '.join([
|
||||||
|
'infer',
|
||||||
|
'--no-progress-bar',
|
||||||
|
'--absolute-paths',
|
||||||
|
'-o', out,
|
||||||
|
'-a', 'crashcontext',
|
||||||
|
'--stacktrace', stacktrace,
|
||||||
|
'--',
|
||||||
|
'javac',
|
||||||
|
'-cp', classpath,
|
||||||
|
srcs])
|
||||||
|
out_rename = ' '.join(['cp',
|
||||||
|
out + '/crashcontext/crashcontext.json',
|
||||||
|
'$OUT' + "." + tag])
|
||||||
|
return ' && '.join([infer_cmd_main, out_rename])
|
||||||
|
|
||||||
|
infer_cmds = [
|
||||||
|
mk_infer_cmd(
|
||||||
|
"MinimalCrashExample",
|
||||||
|
"MinimalCrashExample.java",
|
||||||
|
"MinimalCrashExample.stacktrace.json"
|
||||||
|
),
|
||||||
|
mk_infer_cmd(
|
||||||
|
"MultiStackFrameCrashExample",
|
||||||
|
"MultiStackFrameCrashExample.java",
|
||||||
|
"MultiStackFrameCrashExample.stacktrace.json"
|
||||||
|
),
|
||||||
|
mk_infer_cmd(
|
||||||
|
"BranchingCallsExample",
|
||||||
|
"BranchingCallsExample.java",
|
||||||
|
"BranchingCallsExample.stacktrace.json"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Copy the last crashcontext.json because buck expects it as the output file.
|
||||||
|
# This will only contain the results for the last run infer_cmd above.
|
||||||
|
copy_cmd = ' '.join(['cp', out + '/crashcontext/crashcontext.json', '$OUT'])
|
||||||
|
command = ' && '.join([clean_cmd, copy_inferconfig, ' && '.join(infer_cmds), copy_cmd])
|
||||||
|
|
||||||
|
genrule(
|
||||||
|
name = 'analyze',
|
||||||
|
srcs = sources,
|
||||||
|
out = 'crashcontext.json',
|
||||||
|
cmd = command,
|
||||||
|
deps = dependencies + [':checkers'],
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC',
|
||||||
|
]
|
||||||
|
)
|
@ -1 +1 @@
|
|||||||
{"exception_type": "java.lang.NullPointerException", "stack_trace": ["at endtoend.java.crashcontext.MinimalCrashExample.main(MinimalCrashExample.java:16)",""], "exception_message": "", "normvector_stack": ["endtoend.java.crashcontext.MinimalCrashExample.main"]}
|
{"exception_type": "java.lang.NullPointerException", "stack_trace": ["at codetoanalyze.java.crashcontext.MinimalCrashExample.main(MinimalCrashExample.java:16)",""], "exception_message": "", "normvector_stack": ["codetoanalyze.java.crashcontext.MinimalCrashExample.main"]}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
java_test(
|
||||||
|
name='crashcontext',
|
||||||
|
srcs=glob(['*.java']),
|
||||||
|
deps=[
|
||||||
|
'//dependencies/java/guava:guava',
|
||||||
|
'//dependencies/java/junit:hamcrest',
|
||||||
|
'//dependencies/java/junit:junit',
|
||||||
|
'//infer/tests/utils:utils',
|
||||||
|
],
|
||||||
|
resources=[
|
||||||
|
'//infer/tests/codetoanalyze/java/crashcontext:analyze',
|
||||||
|
],
|
||||||
|
visibility=[
|
||||||
|
'PUBLIC',
|
||||||
|
],
|
||||||
|
)
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package endtoend.java.crashcontext;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import utils.CrashContextResults;
|
||||||
|
|
||||||
|
public class BranchingCallsTest {
|
||||||
|
|
||||||
|
public static final String TAG = "BranchingCallsExample";
|
||||||
|
|
||||||
|
public static final String MAIN_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.BranchingCallsExample.main(java.lang.String[]):void";
|
||||||
|
|
||||||
|
public static final String FOO_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.BranchingCallsExample.foo():void";
|
||||||
|
|
||||||
|
public static final String PRE_BAR_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.BranchingCallsExample.pre_bar():void";
|
||||||
|
|
||||||
|
public static final String BAR_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.BranchingCallsExample.bar():void";
|
||||||
|
|
||||||
|
public static final String POST_BAR_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.BranchingCallsExample.post_bar():void";
|
||||||
|
|
||||||
|
public static final String TO_STRING_METHOD =
|
||||||
|
"java.lang.String.toString():java.lang.String";
|
||||||
|
|
||||||
|
private static CrashContextResults crashcontext;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void loadResults() throws IOException {
|
||||||
|
crashcontext =
|
||||||
|
CrashContextResults.loadJSONResults(TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shapeOfTheStack() {
|
||||||
|
assertThat("The stack trace should contain " + BAR_METHOD,
|
||||||
|
crashcontext.hasStackFrame(BAR_METHOD, 0));
|
||||||
|
assertThat("The stack trace should contain " + FOO_METHOD,
|
||||||
|
crashcontext.hasStackFrame(FOO_METHOD, 1));
|
||||||
|
assertThat("The stack trace should contain " + MAIN_METHOD,
|
||||||
|
crashcontext.hasStackFrame(MAIN_METHOD, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toStringMethodIsFound() {
|
||||||
|
assertThat("Method " + TO_STRING_METHOD + " should be part of the context",
|
||||||
|
crashcontext.hasMethod(TO_STRING_METHOD));
|
||||||
|
assertThat("Method " + TO_STRING_METHOD + " should be reachable in the " +
|
||||||
|
"context tree from " + BAR_METHOD,
|
||||||
|
crashcontext.hasPath(BAR_METHOD, TO_STRING_METHOD));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void preBarMethodIsFound() {
|
||||||
|
assertThat("Method " + PRE_BAR_METHOD + " should be part of the context",
|
||||||
|
crashcontext.hasMethod(PRE_BAR_METHOD));
|
||||||
|
assertThat("Method " + PRE_BAR_METHOD + " should be reachable in the " +
|
||||||
|
"context tree from " + FOO_METHOD,
|
||||||
|
crashcontext.hasPath(FOO_METHOD, PRE_BAR_METHOD));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void postBarMethodIsOmitted() {
|
||||||
|
assertThat("Method " + POST_BAR_METHOD + " shouldn't be part of the context",
|
||||||
|
crashcontext.hasNotMethod(POST_BAR_METHOD));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package endtoend.java.crashcontext;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import utils.CrashContextResults;
|
||||||
|
|
||||||
|
public class MinimalCrashTest {
|
||||||
|
|
||||||
|
public static final String TAG = "MinimalCrashExample";
|
||||||
|
|
||||||
|
public static final String MAIN_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.MinimalCrashExample.main(java.lang.String[]):void";
|
||||||
|
|
||||||
|
public static final String TO_STRING_METHOD =
|
||||||
|
"java.lang.String.toString():java.lang.String";
|
||||||
|
|
||||||
|
private static CrashContextResults crashcontext;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void loadResults() throws IOException {
|
||||||
|
crashcontext =
|
||||||
|
CrashContextResults.loadJSONResults(TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shapeOfTheStack() {
|
||||||
|
assertThat("The stack trace should contain " + MAIN_METHOD,
|
||||||
|
crashcontext.hasStackFrame(MAIN_METHOD, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toStringMethodIsDetected() {
|
||||||
|
assertThat("Method " + TO_STRING_METHOD + " should be part of the context",
|
||||||
|
crashcontext.hasMethod(TO_STRING_METHOD));
|
||||||
|
assertThat("Method " + TO_STRING_METHOD + " should be reachable in the " +
|
||||||
|
"context tree from " + MAIN_METHOD,
|
||||||
|
crashcontext.hasPath(MAIN_METHOD, TO_STRING_METHOD));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package endtoend.java.crashcontext;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import utils.CrashContextResults;
|
||||||
|
|
||||||
|
public class MultiStackFrameCrashTest {
|
||||||
|
|
||||||
|
public static final String TAG = "MultiStackFrameCrashExample";
|
||||||
|
|
||||||
|
public static final String MAIN_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.main(java.lang.String[]):void";
|
||||||
|
|
||||||
|
public static final String FOO_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.foo():void";
|
||||||
|
|
||||||
|
public static final String BAR_METHOD =
|
||||||
|
"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.bar():void";
|
||||||
|
|
||||||
|
public static final String TO_STRING_METHOD =
|
||||||
|
"java.lang.String.toString():java.lang.String";
|
||||||
|
|
||||||
|
private static CrashContextResults crashcontext;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void loadResults() throws IOException {
|
||||||
|
crashcontext =
|
||||||
|
CrashContextResults.loadJSONResults(TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shapeOfTheStack() {
|
||||||
|
assertThat("The stack trace should contain " + BAR_METHOD,
|
||||||
|
crashcontext.hasStackFrame(BAR_METHOD, 0));
|
||||||
|
assertThat("The stack trace should contain " + FOO_METHOD,
|
||||||
|
crashcontext.hasStackFrame(FOO_METHOD, 1));
|
||||||
|
assertThat("The stack trace should contain " + MAIN_METHOD,
|
||||||
|
crashcontext.hasStackFrame(MAIN_METHOD, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toStringMethodIsFound() {
|
||||||
|
assertThat("Method " + TO_STRING_METHOD + " should be part of the context",
|
||||||
|
crashcontext.hasMethod(TO_STRING_METHOD));
|
||||||
|
assertThat("Method " + TO_STRING_METHOD + " should be reachable in the " +
|
||||||
|
"context tree from " + BAR_METHOD,
|
||||||
|
crashcontext.hasPath(BAR_METHOD, TO_STRING_METHOD));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package utils;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
|
||||||
|
public class CrashContextResults {
|
||||||
|
|
||||||
|
private static final String CRASHCONTEXT_JSON =
|
||||||
|
"/buck-out/gen/infer/tests/codetoanalyze/java/crashcontext/analyze/crashcontext.json";
|
||||||
|
|
||||||
|
private JsonNode json;
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
private CrashContextResults(String tag) throws IOException {
|
||||||
|
String path =
|
||||||
|
System.getProperty("user.dir") + CRASHCONTEXT_JSON + "." + tag;
|
||||||
|
byte[] jsonData = ByteStreams.toByteArray(new FileInputStream(path));
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
json = objectMapper.readTree(jsonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStackFrame(String methodSignature, int pos) {
|
||||||
|
return methodSignature.equals(
|
||||||
|
json.path("stack").get(pos).path("method").asText());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStackFrame(String methodSignature) {
|
||||||
|
for (JsonNode frame : json.path("stack")) {
|
||||||
|
if(methodSignature.equals(frame.path("method").asText())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<JsonNode> findNodesForMethod(JsonNode node,
|
||||||
|
String methodSignature,
|
||||||
|
List<JsonNode> accumulator) {
|
||||||
|
if(methodSignature.equals(node.path("method").asText())) {
|
||||||
|
accumulator.add(node);
|
||||||
|
}
|
||||||
|
for(JsonNode callee : node.path("callees")) {
|
||||||
|
findNodesForMethod(callee, methodSignature, accumulator);
|
||||||
|
}
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<JsonNode> findNodesForMethod(String methodSignature) {
|
||||||
|
List<JsonNode> accumulator = new ArrayList<JsonNode>();
|
||||||
|
for (JsonNode frame : json.path("stack")) {
|
||||||
|
findNodesForMethod(frame, methodSignature, accumulator);
|
||||||
|
}
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMethod(String methodSignature) {
|
||||||
|
return !findNodesForMethod(methodSignature).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNotMethod(String methodSignature) {
|
||||||
|
return findNodesForMethod(methodSignature).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPath(String methodFrom, String methodTo) {
|
||||||
|
for(JsonNode from : findNodesForMethod(methodFrom)) {
|
||||||
|
if(!findNodesForMethod(from, methodTo, new ArrayList()).isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CrashContextResults loadJSONResults(String tag) throws IOException {
|
||||||
|
return new CrashContextResults(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue