blob: 543b0dc74e30d4aaf54e29757b3459623b01fb57 [file] [log] [blame]
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Primitives for defining fuzzing engine instrumentations."""
load(
"//fuzzing:instrum_opts.bzl",
"base_opts",
"fuzzing_engine_opts",
"instrumentation_opts",
"sanitizer_opts",
)
def _merge_opts(left_opts, right_opts):
return instrumentation_opts(
copts = left_opts.copts + right_opts.copts,
linkopts = left_opts.linkopts + right_opts.linkopts,
)
def _fuzzing_binary_transition_impl(settings, attr):
opts = instrumentation_opts(
copts = settings["//command_line_option:copt"],
linkopts = settings["//command_line_option:linkopt"],
)
opts = _merge_opts(opts, base_opts)
engine = settings["//fuzzing:cc_engine_instrumentation"]
if engine in fuzzing_engine_opts:
opts = _merge_opts(opts, fuzzing_engine_opts[engine])
else:
fail("unsupported engine instrumentation '%s'" % engine)
sanitizer = settings["//fuzzing:cc_engine_sanitizer"]
if sanitizer in sanitizer_opts:
opts = _merge_opts(opts, sanitizer_opts[sanitizer])
else:
fail("unsupported sanitizer '%s'" % sanitizer)
opts = _merge_opts(opts, instrumentation_opts(
copts = attr.extra_copts,
linkopts = attr.extra_linkopts,
))
return {
"//command_line_option:copt": opts.copts,
"//command_line_option:linkopt": opts.linkopts,
# Make sure binaries are built statically, to maximize the scope of the
# instrumentation.
"//command_line_option:dynamic_mode": "off",
}
fuzzing_binary_transition = transition(
implementation = _fuzzing_binary_transition_impl,
inputs = [
"//fuzzing:cc_engine_instrumentation",
"//fuzzing:cc_engine_sanitizer",
"//command_line_option:copt",
"//command_line_option:linkopt",
],
outputs = [
"//command_line_option:copt",
"//command_line_option:linkopt",
"//command_line_option:dynamic_mode",
],
)
def _instrumented_fuzzing_binary_impl(ctx):
output_file = ctx.actions.declare_file(ctx.label.name)
ctx.actions.symlink(
output = output_file,
target_file = ctx.executable.binary,
is_executable = True,
)
return [DefaultInfo(
executable = output_file,
runfiles = ctx.attr.binary[0][DefaultInfo].default_runfiles,
)]
instrumented_fuzzing_binary = rule(
implementation = _instrumented_fuzzing_binary_impl,
doc = """
Compiles a fuzzing executable according to the specified instrumentation.
The instrumentation is configured through the
`@rules_fuzzing//fuzzing:cc_engine_instrumentation` and
`@rules_fuzzing//fuzzing:cc_engine_sanitizer` flags.
Additional options can be specified using the `extra_copts` and `extra_linkopts`
attributes and are appended to the option lists.
""",
attrs = {
"binary": attr.label(
executable = True,
doc = "The fuzz test executable to instrument.",
cfg = fuzzing_binary_transition,
mandatory = True,
),
"extra_copts": attr.string_list(
doc = "Extra C++ compilation options appended to the instrumentation.",
),
"extra_linkopts": attr.string_list(
doc = "Extra C++ linker options appended to the instrumentation.",
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
executable = True,
)