waf support

Summary:public
This adds support for the waf build system. The workflow to analyse a waf
project looks something like:

```sh
infer -- ./waf configure build
```

closes #316

Reviewed By: jeremydubreil

Differential Revision: D3093056

fb-gh-sync-id: ff3d29e
shipit-source-id: ff3d29e
master
Jules Villard 9 years ago committed by Facebook Github Bot 3
parent c0e5365458
commit bc5dc80df6

@ -15,7 +15,7 @@ import sys
import inferlib import inferlib
from inferlib import analyze, config, utils from inferlib import analyze, config, utils
from inferlib.capture import make
CAPTURE_PACKAGE = 'capture' CAPTURE_PACKAGE = 'capture'
@ -32,7 +32,7 @@ MODULE_TO_COMMAND = {
'buck': ['buck'], 'buck': ['buck'],
'gradle': ['gradle', 'gradlew'], 'gradle': ['gradle', 'gradlew'],
'javac': ['javac'], 'javac': ['javac'],
'make': ['make', 'clang', 'clang++', 'cc', 'gcc', 'g++'], 'make': make.SUPPORTED_COMMANDS,
'xcodebuild': ['xcodebuild'], 'xcodebuild': ['xcodebuild'],
'mvn': ['mvn'] 'mvn': ['mvn']
} }

@ -25,6 +25,9 @@ infer -- make all
infer -- clang -c srcfile.m infer -- clang -c srcfile.m
infer -- gcc -c srcfile.c''' infer -- gcc -c srcfile.c'''
ALIASED_COMMANDS = ['clang', 'clang++', 'cc', 'gcc', 'g++']
BUILD_COMMANDS = ['make', 'waf']
SUPPORTED_COMMANDS = ALIASED_COMMANDS + BUILD_COMMANDS
def gen_instance(*args): def gen_instance(*args):
return MakeCapture(*args) return MakeCapture(*args)
@ -37,7 +40,12 @@ create_argparser = \
class MakeCapture: class MakeCapture:
def __init__(self, args, cmd): def __init__(self, args, cmd):
self.args = args self.args = args
self.cmd = [os.path.basename(cmd[0])] + cmd[1:] self.cmd = cmd
command_name = os.path.basename(cmd[0])
if command_name in ALIASED_COMMANDS:
# remove absolute paths for these commands as we want to
# substitue our own wrappers instead using a PATH trick
cmd[0] = command_name
def get_envvars(self): def get_envvars(self):
env_vars = dict(os.environ) env_vars = dict(os.environ)

@ -54,7 +54,7 @@ REPORT_FIELDS = [
CODETOANALYZE_DIR = os.path.join(SCRIPT_DIR, 'codetoanalyze') CODETOANALYZE_DIR = os.path.join(SCRIPT_DIR, 'codetoanalyze')
EXPECTED_OUTPUTS_DIR = os.path.join(SCRIPT_DIR, 'expected_outputs') EXPECTED_OUTPUTS_DIR = os.path.join(SCRIPT_DIR, 'expected_outputs')
ALL_TESTS = ['ant', 'buck', 'gradle', 'make', 'locale'] ALL_TESTS = ['ant', 'buck', 'gradle', 'make', 'locale', 'waf']
to_test = ALL_TESTS to_test = ALL_TESTS
@ -272,6 +272,21 @@ class BuildIntegrationTest(unittest.TestCase):
original = os.path.join(EXPECTED_OUTPUTS_DIR, 'locale_report.json') original = os.path.join(EXPECTED_OUTPUTS_DIR, 'locale_report.json')
do_test(errors, original) do_test(errors, original)
def test_waf_integration(self):
if 'waf' not in to_test:
print('\nSkipping waf integration test')
return
print('\nRunning waf integration test')
root = os.path.join(CODETOANALYZE_DIR, 'make')
errors = run_analysis(
root,
['make', 'clean'],
['./waf', 'build'],
INFER_EXECUTABLE)
original = os.path.join(EXPECTED_OUTPUTS_DIR, 'waf_report.json')
do_test(errors, original)
if __name__ == '__main__': if __name__ == '__main__':
# hackish capturing of the arguments after '--' # hackish capturing of the arguments after '--'

@ -0,0 +1,11 @@
#!/bin/sh
# mock waf implementation
# waf likes to hardcode paths to compilers during ./waf configure, so
# you should run `infer -- ./waf configure` to capture compiler calls
my_cc=$(which gcc)
echo "compiling"
# compile everything with the hardcoded compiler
make CC="$my_cc"

@ -0,0 +1,7 @@
[
{
"bug_type": "NULL_DEREFERENCE",
"file": "utf8_in_function_names.c",
"procedure": "test_\uc131\uacf5"
}
]
Loading…
Cancel
Save