-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 680130b
Showing
18 changed files
with
874 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.pyc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
Running | ||
======= | ||
|
||
To run, add bin/ to your PATH and invoke from the directory of the project you want to analyze: | ||
|
||
dljc -o logs -- ant build | ||
|
||
Where "ant build" is replaced by whatever command builds your project. Output will be emitted to logs/toplevel.log | ||
|
||
You may also run a checking tool on the discovered java files, by invoking with the -t option and a tool to use (e.g. "-t soot", "-t inference" or "-t checker"). | ||
|
||
LICENSE | ||
======= | ||
|
||
Parts of the code in this directory were taken from the Facebook Infer project. Its license is available at | ||
|
||
https://github.com/facebook/infer/blob/master/LICENSE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import argparse | ||
import os | ||
import sys | ||
import imp | ||
|
||
DEFAULT_OUTPUT_DIRECTORY = os.path.join(os.getcwd(), 'dljc-out') | ||
|
||
# token that identifies the end of the options for do-like-javac and the beginning | ||
# of the compilation command | ||
CMD_MARKER = '--' | ||
|
||
# insert here the correspondence between module name and the list of | ||
# compiler/build-systems it handles. | ||
# All supported commands should be listed here | ||
MODULE_TO_COMMAND = { | ||
'javac': ['javac'], | ||
'ant': ['ant'], | ||
'gradle': ['gradle', 'gradlew'], | ||
'mvn': ['mvn'] | ||
} | ||
|
||
CAPTURE_PACKAGE = 'capture' | ||
LIB_FOLDER = os.path.join( | ||
os.path.dirname(os.path.realpath(__file__)), os.path.pardir, 'lib') | ||
|
||
class AbsolutePathAction(argparse.Action): | ||
"""Convert a path from relative to absolute in the arg parser""" | ||
def __call__(self, parser, namespace, values, option_string=None): | ||
setattr(namespace, self.dest, os.path.abspath(values)) | ||
|
||
base_parser = argparse.ArgumentParser(add_help=False) | ||
base_group = base_parser.add_argument_group('global arguments') | ||
base_group.add_argument('-o', '--out', metavar='<directory>', | ||
default=DEFAULT_OUTPUT_DIRECTORY, dest='output_directory', | ||
action=AbsolutePathAction, | ||
help='Set the results directory') | ||
base_group.add_argument('-t', '--tool', metavar='<tool>', | ||
action='store',default=None, | ||
help='choose a tool to run. Valid tools include soot, checker, and inference.') | ||
base_group.add_argument('-c', '--checker', metavar='<checker>', | ||
action='store',default='NullnessChecker', | ||
help='choose a checker to check') | ||
base_group.add_argument('-s', '--solver', metavar='<solver>', | ||
action='store',default='checkers.inference.solver.DebugSolver', | ||
help='solver to use on constraints') | ||
base_group.add_argument('-afud', '--afuOutputDir', metavar='<afud>', | ||
action='store',default='afud/', | ||
help='Annotation File Utilities output directory') | ||
base_group.add_argument('-m', '--mode', metavar='<mode>', | ||
action='store',default='INFER', | ||
help='Modes of operation: TYPECHECK, INFER, ROUNDTRIP,ROUNDTRIP_TYPECHECK') | ||
base_group.add_argument('-i', '--incremental', action='store_true', | ||
help='''Do not delete the results directory across | ||
runs''') | ||
base_group.add_argument('--log_to_stderr', action='store_true', | ||
help='''When set, all logging will go to stderr instead | ||
of log file''') | ||
base_group.add_argument('-j', '--jar', metavar='<jar>', | ||
action='store',default=None, | ||
help='Set the path to either prog2dfg.jar or apilearner.jar.') | ||
|
||
def get_commands(): | ||
"""Return all commands that are supported.""" | ||
#flatten and dedup the list of commands | ||
return set(sum(MODULE_TO_COMMAND.values(), [])) | ||
|
||
def get_module_name(command): | ||
""" Return module that is able to handle the command. None if | ||
there is no such module.""" | ||
for module, commands in MODULE_TO_COMMAND.iteritems(): | ||
if command in commands: | ||
return module | ||
return None | ||
|
||
def split_args_to_parse(): | ||
dd_index = \ | ||
sys.argv.index(CMD_MARKER) if CMD_MARKER in sys.argv else len(sys.argv) | ||
|
||
args, cmd = sys.argv[1:dd_index], sys.argv[dd_index + 1:] | ||
capture_module_name = os.path.basename(cmd[0]) if len(cmd) > 0 else None | ||
mod_name = get_module_name(capture_module_name) | ||
return args, cmd, mod_name | ||
|
||
def create_argparser(parents=[]): | ||
parser = argparse.ArgumentParser( | ||
parents=[base_parser] + parents, | ||
add_help=False, | ||
formatter_class=argparse.RawDescriptionHelpFormatter, | ||
) | ||
group = parser.add_argument_group( | ||
'supported compiler/build-system commands') | ||
|
||
supported_commands = ', '.join(get_commands()) | ||
group.add_argument( | ||
CMD_MARKER, | ||
metavar='<cmd>', | ||
dest='nullarg', | ||
default=None, | ||
help=('Command to run the compiler/build-system. ' | ||
'Supported build commands (run `do-like-javac.py --help -- <cmd_name>` for ' | ||
'extra help, e.g. `do-like-javac.py --help -- ant`): ' + supported_commands), | ||
) | ||
return parser | ||
|
||
def load_module(mod_name): | ||
# load the 'capture' package in lib | ||
pkg_info = imp.find_module(CAPTURE_PACKAGE, [LIB_FOLDER]) | ||
imported_pkg = imp.load_module(CAPTURE_PACKAGE, *pkg_info) | ||
# load the requested module (e.g. make) | ||
mod_file, mod_path, mod_descr = \ | ||
imp.find_module(mod_name, imported_pkg.__path__) | ||
try: | ||
return imp.load_module( | ||
'{pkg}.{mod}'.format(pkg=imported_pkg.__name__, mod=mod_name), | ||
mod_file, mod_path, mod_descr) | ||
finally: | ||
if mod_file: | ||
mod_file.close() | ||
|
||
def parse_args(): | ||
to_parse, cmd, mod_name = split_args_to_parse() | ||
# get the module name (if any), then load it | ||
imported_module = None | ||
if mod_name: | ||
imported_module = load_module(mod_name) | ||
|
||
# get the module's argparser and merge it with the global argparser | ||
module_argparser = [] | ||
if imported_module: | ||
module_argparser.append( | ||
imported_module.create_argparser(mod_name) | ||
) | ||
global_argparser = create_argparser(module_argparser) | ||
|
||
args = global_argparser.parse_args(to_parse) | ||
|
||
if imported_module: | ||
return args, cmd, imported_module | ||
else: | ||
global_argparser.print_help() | ||
sys.exit(os.EX_OK) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import logging | ||
import os | ||
import sys | ||
import platform | ||
import pprint | ||
import subprocess | ||
import traceback | ||
|
||
|
||
def run_checker(javac_commands,args): | ||
# checker-framework javac. | ||
javacheck = os.environ['JSR308']+"/checker-framework/checker/bin/javac" | ||
checker_command = [] | ||
checker_command.extend([javacheck]) | ||
|
||
for jc in javac_commands: | ||
pprint.pformat(jc) | ||
javac_switches = jc['javac_switches'] | ||
cp = javac_switches['classpath'] | ||
java_files = ' '.join(jc['java_files']) | ||
cmd = checker_command + ["-processor", args.checker, "-classpath", cp, java_files] | ||
print ("Running %s" % cmd) | ||
try: | ||
print (subprocess.check_output(cmd, stderr=subprocess.STDOUT)) | ||
except subprocess.CalledProcessError as e: | ||
print e.output |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
#!/usr/bin/env python2.7 | ||
|
||
import logging | ||
import os | ||
import sys | ||
import platform | ||
import pprint | ||
import arg | ||
import log | ||
import soot | ||
import infer | ||
import check | ||
import jprint | ||
import randoop | ||
import graphtools | ||
|
||
def soot_tool(results,jars,args): | ||
soot.run_soot(results) | ||
|
||
def checker_tool(results,jars,args): | ||
check.run_checker(results,args) | ||
|
||
def inference_tool(results,jars,args): | ||
infer.run_inference(results,args) | ||
|
||
def print_tool(results,jars,args): | ||
jprint.run_printer(results, jars) | ||
|
||
def randoop_tool(results,jars,args): | ||
randoop.run_randoop(results) | ||
|
||
def graph_tool(results,jars,args): | ||
graphtools.run(results,args) | ||
|
||
|
||
def log_header(): | ||
logging.info('Running command %s', ' '.join(sys.argv)) | ||
logging.info('Platform: %s', platform.platform()) | ||
logging.info('PATH=%s', os.getenv('PATH')) | ||
logging.info('SHELL=%s', os.getenv('SHELL')) | ||
logging.info('PWD=%s', os.getenv('PWD')) | ||
|
||
def main(): | ||
args, cmd, imported_module = arg.parse_args() | ||
log.configure_logging(args.output_directory, args.incremental, args.log_to_stderr) | ||
|
||
log_header() | ||
|
||
javac_commands, jars = imported_module.gen_instance(cmd).capture() | ||
logging.info('Results: %s', pprint.pformat(javac_commands)) | ||
|
||
options = {'soot' : soot_tool, | ||
'checker' : checker_tool, | ||
'inference' : inference_tool, | ||
'print' : print_tool, | ||
'randoop' : randoop_tool, | ||
'graphtool' : graph_tool, | ||
} | ||
|
||
if args.tool: | ||
options[args.tool](javac_commands,jars,args) | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import logging | ||
import os | ||
import sys | ||
import platform | ||
import pprint | ||
import subprocess | ||
import traceback | ||
|
||
|
||
def run(javac_commands, args): | ||
run_tool(args.jar, javac_commands, args.output_directory) | ||
|
||
|
||
def run_tool(jarfile, javac_commands, outdir): | ||
# first add the call to the soot jar. | ||
tool_command = [] | ||
tool_command.extend(["java", "-jar", jarfile]) | ||
|
||
pp = pprint.PrettyPrinter(indent=2) | ||
for jc in javac_commands: | ||
pp.pformat(jc) | ||
#jc['java_files'] | ||
javac_switches = jc['javac_switches'] | ||
class_dir = os.path.abspath(javac_switches['d']) | ||
|
||
java_files = jc['java_files'] | ||
java_files_file = os.path.join(os.getcwd(), '__java_file_names.txt') | ||
with open(java_files_file, 'w') as f: | ||
for s in java_files: | ||
f.write(s) | ||
f.write("\n") | ||
|
||
current_outdir = os.path.join(outdir, class_dir.replace(os.getcwd(),'').replace(os.sep,"_")) | ||
|
||
cmd = tool_command + ["-o", current_outdir, "-j", class_dir, "-source", java_files_file ] | ||
print ("Running %s" % ' '.join(cmd)) | ||
try: | ||
print (subprocess.check_output(cmd, stderr=subprocess.STDOUT)) | ||
except: | ||
print ('calling {cmd} failed\n{trace}'.format(cmd=' '.join(cmd),trace=traceback.format_exc())) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import logging | ||
import os | ||
import sys | ||
import platform | ||
import pprint | ||
import subprocess | ||
import traceback | ||
|
||
|
||
def run_inference(javac_commands,args): | ||
|
||
# the dist directory if CFI. | ||
CFI_dist = os.environ['JSR308']+"/checker-framework-inference/dist" | ||
CFI_command = [] | ||
|
||
CFI_command.extend(["java"]) | ||
|
||
for jc in javac_commands: | ||
pprint.pformat(jc) | ||
javac_switches = jc['javac_switches'] | ||
target_cp = javac_switches['classpath'] | ||
java_files = ' '.join(jc['java_files']) | ||
cp = target_cp +":"+ CFI_dist + "/checker.jar:" + CFI_dist + "/plume.jar:" + \ | ||
CFI_dist + "/checker-framework-inference.jar" | ||
cmd = CFI_command + ["-classpath", cp, "checkers.inference.InferenceLauncher" , | ||
"--checker" ,args.checker, "--solver", args.solver , | ||
"--mode" , args.mode ,"--targetclasspath", target_cp, "-afud", args.afuOutputDir, java_files] | ||
print ("Running %s" % cmd) | ||
try: | ||
print (subprocess.check_output(cmd, stderr=subprocess.STDOUT)) | ||
except: | ||
print ('calling {cmd} failed\n{trace}'.format(cmd=' '.join(cmd),trace=traceback.format_exc())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import logging | ||
import os | ||
import sys | ||
import platform | ||
import pprint | ||
import subprocess | ||
import traceback | ||
|
||
def run_printer(javac_commands, jars): | ||
pp = pprint.PrettyPrinter(indent=2) | ||
for jc in javac_commands: | ||
pp.pprint(jc) | ||
javac_switches = jc['javac_switches'] | ||
print("Target JARs (experimental):") | ||
pp.pprint(jars) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Copyright (c) 2013 - 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. | ||
|
||
import os | ||
import shutil | ||
import logging | ||
|
||
FORMAT = '[%(levelname)s] %(message)s' | ||
LOG_FILE = 'toplevel.log' | ||
|
||
def remove_output_directory(output_directory): | ||
# it is safe to ignore errors here because recreating the | ||
# output_directory will fail later | ||
shutil.rmtree(output_directory, True) | ||
|
||
def create_results_dir(results_dir): | ||
try: | ||
os.mkdir(results_dir) | ||
except OSError: | ||
pass | ||
|
||
def configure_logging(output_directory, incremental, log_to_stderr): | ||
#if not incremental: | ||
# remove_output_directory(output_directory) | ||
|
||
create_results_dir(output_directory) | ||
|
||
if log_to_stderr: | ||
logging.basicConfig(level=logging.INFO, format=FORMAT) | ||
else: | ||
logging.basicConfig(level=logging.INFO, | ||
format=FORMAT, | ||
filename=os.path.join(output_directory, LOG_FILE), | ||
filemode='w') | ||
|
||
# vim: set sw=4 ts=4 et: |
Oops, something went wrong.