Skip to content

Commit

Permalink
gcc: introduce the --gcc-analyzer-bin option
Browse files Browse the repository at this point in the history
... to specify a custom build of gcc to be used for `gcc -fanalyzer`

Closes: #41
  • Loading branch information
sibeream authored and kdudka committed Oct 25, 2021
1 parent 587eb56 commit da68dd4
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 10 deletions.
6 changes: 5 additions & 1 deletion py/common/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ def translate_one(i):
return cmd_out.lstrip()


def write_toolver(ini_writer, tool_key, ver):
ini_writer.append("analyzer-version-%s" % tool_key, ver)


def write_toolver_from_rpmlist(results, mock, tool, tool_key):
cmd = "grep '^%s-[0-9]' %s/rpm-list-mock.txt" % (tool, results.dbgdir)
(rc, nvr) = results.get_cmd_output(cmd)
Expand All @@ -56,7 +60,7 @@ def write_toolver_from_rpmlist(results, mock, tool, tool_key):
return rc

ver = re.sub("-[0-9].*$", "", re.sub("^%s-" % tool, "", nvr.strip()))
results.ini_writer.append("analyzer-version-%s" % tool_key, ver)
write_toolver(results.ini_writer, tool_key, ver)
return 0


Expand Down
7 changes: 4 additions & 3 deletions py/csmock
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ class ScanProps:
self.pkg = None
self.imp_checker_set = set()
self.imp_csgrep_filters = []
self.cswrap_path = None

def enable_cswrap(self):
if self.cswrap_enabled:
Expand All @@ -435,10 +436,10 @@ class ScanProps:
cmd = ["cswrap", "--print-path-to-wrap"]
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, _) = subproc.communicate()
cswrap_path = out.decode("utf8").strip()
self.cswrap_path = out.decode("utf8").strip()

self.copy_in_files += ["/usr/bin/cswrap", cswrap_path]
self.path = [cswrap_path] + self.path
self.copy_in_files += ["/usr/bin/cswrap", self.cswrap_path]
self.path = [self.cswrap_path] + self.path
self.env["CSWRAP_CAP_FILE"] = "/builddir/cswrap-capture.err"
self.env["CSWRAP_TIMEOUT"] = "%d" % self.cswrap_timeout
self.env["CSWRAP_TIMEOUT_FOR"] = ":"
Expand Down
56 changes: 50 additions & 6 deletions py/plugins/gcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@

from csmock.common.cflags import add_custom_flag_opts, flags_by_warning_level

CSGCCA_BIN="/usr/bin/csgcca"
CSGCCA_BIN = "/usr/bin/csgcca"

CSMOCK_GCC_WRAPPER_NAME = 'csmock-gcc-wrapper'
CSMOCK_GCC_WRAPPER_PATH = '/usr/bin/%s' % CSMOCK_GCC_WRAPPER_NAME
CSMOCK_GCC_WRAPPER_TEMPLATE = '#!/bin/bash\n' \
'exec %s "$@"'


class PluginProps:
def __init__(self):
Expand Down Expand Up @@ -67,6 +73,10 @@ def init_parser(self, parser):
"--gcc-analyze", action="store_true",
help="run `gcc -fanalyzer` in a separate process")

parser.add_argument(
"--gcc-analyzer-bin", action="store",
help="use custom build of gcc to perform scan")

parser.add_argument(
"--gcc-analyze-add-flag", action="append", default=[],
help="append the given flag when invoking `gcc -fanalyzer` \
Expand Down Expand Up @@ -101,7 +111,9 @@ def handle_args(self, parser, args, props):
self.enable()
self.flags = flags_by_warning_level(args.gcc_warning_level)

if args.gcc_analyze or getattr(args, "all_tools", False):
if args.gcc_analyze or \
args.gcc_analyzer_bin or \
getattr(args, "all_tools", False):
self.enable()
# resolve csgcca_path by querying csclng binary
cmd = [CSGCCA_BIN, "--print-path-to-wrap"]
Expand Down Expand Up @@ -165,13 +177,38 @@ def handle_args(self, parser, args, props):

if self.csgcca_path is not None:
def csgcca_hook(results, mock):
analyzer_bin = args.gcc_analyzer_bin if args.gcc_analyzer_bin else "gcc"
cmd = "echo 'int main() {}'"
cmd += " | gcc -xc - -c -o /dev/null"
cmd += " | %s -xc - -c -o /dev/null" % analyzer_bin
cmd += " -fanalyzer -fdiagnostics-path-format=separate-events"
if 0 != mock.exec_mockbuild_cmd(cmd):
results.error("`gcc -fanalyzer` does not seem to work, disabling the tool", ec=0)
results.error("`%s -fanalyzer` does not seem to work, "
"disabling the tool" % analyzer_bin, ec=0)
return 0

if args.gcc_analyzer_bin:
# create an executable shell script to wrap the custom gcc binary
wrapper_script = CSMOCK_GCC_WRAPPER_TEMPLATE % analyzer_bin
cmd = "echo '%s' > %s && chmod 755 %s" % \
(wrapper_script,
CSMOCK_GCC_WRAPPER_PATH,
CSMOCK_GCC_WRAPPER_PATH)
rv = mock.exec_chroot_cmd(cmd)
if 0 != rv:
results.error("failed to create csmock gcc wrapper script")
return rv

# wrap the shell script by cswrap to capture output of `gcc -fanalyzer`
cmd = "ln -sf ../../bin/cswrap %s/%s" % \
(props.cswrap_path, CSMOCK_GCC_WRAPPER_NAME)
rv = mock.exec_chroot_cmd(cmd)
if 0 != rv:
results.error("failed to create csmock gcc wrapper symlink")
return rv

# tell csgcca to use the wrapped script rather than system gcc analyzer
props.env["CSGCCA_ANALYZER_BIN"] = CSMOCK_GCC_WRAPPER_NAME

# XXX: changing props this way is extremely fragile
# insert csgcca right before cswrap to avoid chaining
# csclng/cscppc while invoking `gcc -fanalyzer`
Expand All @@ -182,13 +219,20 @@ def csgcca_hook(results, mock):
break
props.path.insert(idx_cswrap, self.csgcca_path)

props.env["CSWRAP_TIMEOUT_FOR"] += ":gcc"
props.env["CSWRAP_TIMEOUT_FOR"] += ":%s" % (CSMOCK_GCC_WRAPPER_NAME if args.gcc_analyzer_bin else "gcc")
if args.gcc_analyze_add_flag:
# propagate custom GCC analyzer flags
props.env["CSGCCA_ADD_OPTS"] = csmock.common.cflags.serialize_flags(args.gcc_analyze_add_flag)

# record that `gcc -fanalyzer` was used for this scan
csmock.common.util.write_toolver_from_rpmlist(results, mock, "gcc", "gcc-analyzer")
cmd = mock.get_mock_cmd(["--chroot", "%s --version" % analyzer_bin])
(rc, ver) = results.get_cmd_output(cmd, shell=False)
if rc != 0:
return rc
ver = ver.partition('\n')[0].strip()
ver = ver.split(' ')[2]
csmock.common.util.write_toolver(results.ini_writer, "gcc-analyzer", ver)

return 0

props.post_depinst_hooks += [csgcca_hook]

0 comments on commit da68dd4

Please sign in to comment.