We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
expose BENCHMARK env variable to builder container
It would be useful to expose a BENCHMARK env variable to the runner. This way fuzzer.py can use it adjust the building code (fuzzer.py). For example: currently lafintel uses the PWD env variable to detect the php benchmark. Cleaner to have a BENCHMARK variable

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `fuzzers/utils.py`
Content:
```
1 # Copyright 2020 Google LLC
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Utility functions for running fuzzers."""
15 
16 import configparser
17 import contextlib
18 import os
19 import shutil
20 import subprocess
21 import tempfile
22 
23 # Keep all fuzzers at same optimization level until fuzzer explicitly needs or
24 # specifies it.
25 DEFAULT_OPTIMIZATION_LEVEL = '-O3'
26 
27 OSS_FUZZ_LIB_FUZZING_ENGINE_PATH = '/usr/lib/libFuzzingEngine.a'
28 
29 
30 def build_benchmark(env=None):
31     """Build a benchmark using fuzzer library."""
32     if not env:
33         env = os.environ.copy()
34 
35     # Add OSS-Fuzz environment variable for fuzzer library.
36     fuzzer_lib = env['FUZZER_LIB']
37     env['LIB_FUZZING_ENGINE'] = fuzzer_lib
38     if os.path.exists(fuzzer_lib):
39         # Make /usr/lib/libFuzzingEngine.a point to our library for OSS-Fuzz
40         # so we can build projects that are using -lFuzzingEngine.
41         shutil.copy(fuzzer_lib, OSS_FUZZ_LIB_FUZZING_ENGINE_PATH)
42 
43     if os.getenv('OSS_FUZZ'):
44         build_script = os.path.join(os.environ['SRC'], 'build.sh')
45     else:
46         build_script = os.path.join('benchmark', 'build.sh')
47 
48     print('Building benchmark')
49     subprocess.check_call(['/bin/bash', '-ex', build_script], env=env)
50 
51 
52 def append_flags(env_var, additional_flags, env=None):
53     """Append |additional_flags| to those already set in the value of |env_var|
54     and assign env_var to the result."""
55     if env is None:
56         env = os.environ
57     flags = env.get(env_var, '').split(' ')
58     flags.extend(additional_flags)
59     env[env_var] = ' '.join(flags)
60 
61 
62 # Use these flags when compiling benchmark code without a sanitizer (e.g. when
63 # using eclipser). This is necessary because many OSS-Fuzz targets cannot
64 # otherwise be compiled without a sanitizer because they implicitly depend on
65 # libraries linked into the sanitizer runtime. These flags link against those
66 # libraries.
67 NO_SANITIZER_COMPAT_CFLAGS = [
68     '-pthread', '-Wl,--no-as-needed', '-Wl,-ldl', '-Wl,-lm',
69     '-Wno-unused-command-line-argument'
70 ]
71 NO_SANITIZER_COMPAT_CXXFLAGS = ['-stdlib=libc++'] + NO_SANITIZER_COMPAT_CFLAGS
72 
73 
74 def set_no_sanitizer_compilation_flags(env=None):
75     """Set compilation flags (CFLAGS and CXXFLAGS) in |env| so that a benchmark
76     can be compiled without a sanitizer. If |env| is not provided, the program's
77     environment will be used."""
78     if env is None:
79         env = os.environ
80     env['CFLAGS'] = ' '.join(NO_SANITIZER_COMPAT_CFLAGS)
81     env['CXXFLAGS'] = ' '.join(NO_SANITIZER_COMPAT_CXXFLAGS)
82 
83 
84 @contextlib.contextmanager
85 def restore_directory(directory):
86     """Helper contextmanager that when created saves a backup of |directory| and
87     when closed/exited replaces |directory| with the backup.
88 
89     Example usage:
90 
91     directory = 'my-directory'
92     with restore_directory(directory):
93        shutil.rmtree(directory)
94     # At this point directory is in the same state where it was before we
95     # deleted it.
96     """
97     # TODO(metzman): Figure out if this is worth it, so far it only allows QSYM
98     # to compile bloaty.
99     if not directory:
100         # Don't do anything if directory is None.
101         yield
102         return
103     # Save cwd so that if it gets deleted we can just switch into the restored
104     # version without code that runs after us running into issues.
105     initial_cwd = os.getcwd()
106     with tempfile.TemporaryDirectory() as temp_dir:
107         backup = os.path.join(temp_dir, os.path.basename(directory))
108         shutil.copytree(directory, backup)
109         yield
110         shutil.rmtree(directory)
111         shutil.move(backup, directory)
112         try:
113             os.getcwd()
114         except FileNotFoundError:
115             os.chdir(initial_cwd)
116 
117 
118 def get_dictionary_path(target_binary):
119     """Return dictionary path for a target binary."""
120     if os.getenv('SKIP_DICT'):
121         return None
122 
123     dictionary_path = target_binary + '.dict'
124     if os.path.exists(dictionary_path):
125         return dictionary_path
126 
127     options_file_path = target_binary + '.options'
128     if not os.path.exists(options_file_path):
129         return None
130 
131     config = configparser.ConfigParser()
132     with open(options_file_path, 'r') as file_handle:
133         try:
134             config.read_file(file_handle)
135         except configparser.Error:
136             raise Exception('Failed to parse fuzzer options file: ' +
137                             options_file_path)
138 
139     for section in config.sections():
140         for key, value in config.items(section):
141             if key == 'dict':
142                 dictionary_path = os.path.join(os.path.dirname(target_binary),
143                                                value)
144                 if not os.path.exists(dictionary_path):
145                     raise ValueError('Bad dictionary path in options file: ' +
146                                      options_file_path)
147                 return dictionary_path
148     return None
149 
150 
151 def set_default_optimization_flag(env=None):
152     """Set default optimization flag if none is already set."""
153     if not env:
154         env = os.environ
155 
156     for flag_var in ['CFLAGS', 'CXXFLAGS']:
157         append_flags(flag_var, [DEFAULT_OPTIMIZATION_LEVEL], env=env)
158 
159 
160 def initialize_flags(env=None):
161     """Set initial flags before fuzzer.build() is called."""
162     set_no_sanitizer_compilation_flags(env)
163     set_default_optimization_flag(env)
164 
165     for flag_var in ['CFLAGS', 'CXXFLAGS']:
166         print('{flag_var} = {flag_value}'.format(
167             flag_var=flag_var, flag_value=os.getenv(flag_var)))
168
```

Path: `experiment/build/gcb_build.py`
Content:
```
1 # Copyright 2020 Google LLC
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Module for building things on Google Cloud Build for use in trials."""
15 
16 import os
17 from typing import Dict, Tuple
18 
19 from common import benchmark_utils
20 from common import experiment_path as exp_path
21 from common import experiment_utils
22 from common import logs
23 from common import new_process
24 from common import utils
25 from experiment.build import build_utils
26 
27 # Maximum time to wait for a GCB config to finish build.
28 GCB_BUILD_TIMEOUT = 2 * 60 * 60  # 2 hours.
29 
30 # High cpu configuration for faster builds.
31 GCB_MACHINE_TYPE = 'n1-highcpu-8'
32 
33 logger = logs.Logger('builder')  # pylint: disable=invalid-name
34 
35 
36 def build_base_images() -> Tuple[int, str]:
37     """Build base images on GCB."""
38     return _build(get_build_config_file('base-images.yaml'), 'base-images')
39 
40 
41 def build_coverage(benchmark):
42     """Build coverage image for benchmark on GCB."""
43     if benchmark_utils.is_oss_fuzz(benchmark):
44         _build_oss_fuzz_project_coverage(benchmark)
45     else:
46         _build_benchmark_coverage(benchmark)
47 
48 
49 def _build_benchmark_coverage(benchmark: str) -> Tuple[int, str]:
50     """Build a coverage build of |benchmark| on GCB."""
51     coverage_binaries_dir = exp_path.gcs(
52         build_utils.get_coverage_binaries_dir())
53     substitutions = {
54         '_GCS_COVERAGE_BINARIES_DIR': coverage_binaries_dir,
55         '_BENCHMARK': benchmark,
56     }
57     config_file = get_build_config_file('coverage.yaml')
58     config_name = 'benchmark-{benchmark}-coverage'.format(benchmark=benchmark)
59     return _build(config_file, config_name, substitutions)
60 
61 
62 def _build_oss_fuzz_project_fuzzer(benchmark: str,
63                                    fuzzer: str) -> Tuple[int, str]:
64     """Build a |benchmark|, |fuzzer| runner image on GCB."""
65     project = benchmark_utils.get_project(benchmark)
66     oss_fuzz_builder_hash = benchmark_utils.get_oss_fuzz_builder_hash(benchmark)
67     substitutions = {
68         '_OSS_FUZZ_PROJECT': project,
69         '_FUZZER': fuzzer,
70         '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,
71     }
72     config_file = get_build_config_file('oss-fuzz-fuzzer.yaml')
73     config_name = 'oss-fuzz-{project}-fuzzer-{fuzzer}-hash-{hash}'.format(
74         project=project, fuzzer=fuzzer, hash=oss_fuzz_builder_hash)
75 
76     return _build(config_file, config_name, substitutions)
77 
78 
79 def _build_benchmark_fuzzer(benchmark: str, fuzzer: str) -> Tuple[int, str]:
80     """Build a |benchmark|, |fuzzer| runner image on GCB."""
81     # See link for why substitutions must begin with an underscore:
82     # https://cloud.google.com/cloud-build/docs/configuring-builds/substitute-variable-values#using_user-defined_substitutions
83     substitutions = {
84         '_BENCHMARK': benchmark,
85         '_FUZZER': fuzzer,
86     }
87     config_file = get_build_config_file('fuzzer.yaml')
88     config_name = 'benchmark-{benchmark}-fuzzer-{fuzzer}'.format(
89         benchmark=benchmark, fuzzer=fuzzer)
90     return _build(config_file, config_name, substitutions)
91 
92 
93 def _build_oss_fuzz_project_coverage(benchmark: str) -> Tuple[int, str]:
94     """Build a coverage build of OSS-Fuzz-based benchmark |benchmark| on GCB."""
95     project = benchmark_utils.get_project(benchmark)
96     oss_fuzz_builder_hash = benchmark_utils.get_oss_fuzz_builder_hash(benchmark)
97     coverage_binaries_dir = exp_path.gcs(
98         build_utils.get_coverage_binaries_dir())
99     substitutions = {
100         '_GCS_COVERAGE_BINARIES_DIR': coverage_binaries_dir,
101         '_OSS_FUZZ_PROJECT': project,
102         '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,
103     }
104     config_file = get_build_config_file('oss-fuzz-coverage.yaml')
105     config_name = 'oss-fuzz-{project}-coverage-hash-{hash}'.format(
106         project=project, hash=oss_fuzz_builder_hash)
107     return _build(config_file, config_name, substitutions)
108 
109 
110 def _build(config_file: str,
111            config_name: str,
112            substitutions: Dict[str, str] = None,
113            timeout_seconds: int = GCB_BUILD_TIMEOUT) -> Tuple[int, str]:
114     """Build each of |args| on gcb."""
115     config_arg = '--config=%s' % config_file
116     machine_type_arg = '--machine-type=%s' % GCB_MACHINE_TYPE
117 
118     # Use "s" suffix to denote seconds.
119     timeout_arg = '--timeout=%ds' % timeout_seconds
120 
121     command = [
122         'gcloud',
123         'builds',
124         'submit',
125         str(utils.ROOT_DIR),
126         config_arg,
127         timeout_arg,
128         machine_type_arg,
129     ]
130 
131     if substitutions is None:
132         substitutions = {}
133 
134     assert '_REPO' not in substitutions
135     substitutions['_REPO'] = experiment_utils.get_base_docker_tag()
136 
137     substitutions = [
138         '%s=%s' % (key, value) for key, value in substitutions.items()
139     ]
140     substitutions = ','.join(substitutions)
141     command.append('--substitutions=%s' % substitutions)
142 
143     # Don't write to stdout to make concurrent building faster. Otherwise
144     # writing becomes the bottleneck.
145     result = new_process.execute(command,
146                                  write_to_stdout=False,
147                                  kill_children=True,
148                                  timeout=timeout_seconds)
149     build_utils.store_build_logs(config_name, result)
150     return result
151 
152 
153 def get_build_config_file(filename: str) -> str:
154     """Return the path of the GCB build config file |filename|."""
155     return os.path.join(utils.ROOT_DIR, 'experiment', 'gcb', filename)
156 
157 
158 def build_fuzzer_benchmark(fuzzer: str, benchmark: str) -> bool:
159     """Builds |benchmark| for |fuzzer|."""
160     if benchmark_utils.is_oss_fuzz(benchmark):
161         _build_oss_fuzz_project_fuzzer(benchmark, fuzzer)
162     else:
163         _build_benchmark_fuzzer(benchmark, fuzzer)
164
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/experiment/build/gcb_build.py b/experiment/build/gcb_build.py
--- a/experiment/build/gcb_build.py
+++ b/experiment/build/gcb_build.py
@@ -66,6 +66,7 @@
     oss_fuzz_builder_hash = benchmark_utils.get_oss_fuzz_builder_hash(benchmark)
     substitutions = {
         '_OSS_FUZZ_PROJECT': project,
+        '_BENCHMARK': benchmark,
         '_FUZZER': fuzzer,
         '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,
     }
@@ -99,6 +100,7 @@
     substitutions = {
         '_GCS_COVERAGE_BINARIES_DIR': coverage_binaries_dir,
         '_OSS_FUZZ_PROJECT': project,
+        '_BENCHMARK': benchmark,
         '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,
     }
     config_file = get_build_config_file('oss-fuzz-coverage.yaml')
diff --git a/fuzzers/utils.py b/fuzzers/utils.py
--- a/fuzzers/utils.py
+++ b/fuzzers/utils.py
@@ -45,7 +45,10 @@
     else:
         build_script = os.path.join('benchmark', 'build.sh')
 
-    print('Building benchmark')
+    benchmark = os.getenv('BENCHMARK')
+    fuzzer = os.getenv('FUZZER')
+    print('Building benchmark {benchmark} with fuzzer {fuzzer}'.format(
+        benchmark=benchmark, fuzzer=fuzzer))
     subprocess.check_call(['/bin/bash', '-ex', build_script], env=env)

{"golden_diff": "diff --git a/experiment/build/gcb_build.py b/experiment/build/gcb_build.py\n--- a/experiment/build/gcb_build.py\n+++ b/experiment/build/gcb_build.py\n@@ -66,6 +66,7 @@\n     oss_fuzz_builder_hash = benchmark_utils.get_oss_fuzz_builder_hash(benchmark)\n     substitutions = {\n         '_OSS_FUZZ_PROJECT': project,\n+        '_BENCHMARK': benchmark,\n         '_FUZZER': fuzzer,\n         '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,\n     }\n@@ -99,6 +100,7 @@\n     substitutions = {\n         '_GCS_COVERAGE_BINARIES_DIR': coverage_binaries_dir,\n         '_OSS_FUZZ_PROJECT': project,\n+        '_BENCHMARK': benchmark,\n         '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,\n     }\n     config_file = get_build_config_file('oss-fuzz-coverage.yaml')\ndiff --git a/fuzzers/utils.py b/fuzzers/utils.py\n--- a/fuzzers/utils.py\n+++ b/fuzzers/utils.py\n@@ -45,7 +45,10 @@\n     else:\n         build_script = os.path.join('benchmark', 'build.sh')\n \n-    print('Building benchmark')\n+    benchmark = os.getenv('BENCHMARK')\n+    fuzzer = os.getenv('FUZZER')\n+    print('Building benchmark {benchmark} with fuzzer {fuzzer}'.format(\n+        benchmark=benchmark, fuzzer=fuzzer))\n     subprocess.check_call(['/bin/bash', '-ex', build_script], env=env)\n", "issue": "expose BENCHMARK env variable to builder container\nIt would be useful to expose a BENCHMARK env variable to the runner. This way fuzzer.py can use it adjust the building code (fuzzer.py). For example: currently lafintel uses the PWD env variable to detect the php benchmark. Cleaner to have a BENCHMARK variable\n", "before_files": [{"content": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Utility functions for running fuzzers.\"\"\"\n\nimport configparser\nimport contextlib\nimport os\nimport shutil\nimport subprocess\nimport tempfile\n\n# Keep all fuzzers at same optimization level until fuzzer explicitly needs or\n# specifies it.\nDEFAULT_OPTIMIZATION_LEVEL = '-O3'\n\nOSS_FUZZ_LIB_FUZZING_ENGINE_PATH = '/usr/lib/libFuzzingEngine.a'\n\n\ndef build_benchmark(env=None):\n    \"\"\"Build a benchmark using fuzzer library.\"\"\"\n    if not env:\n        env = os.environ.copy()\n\n    # Add OSS-Fuzz environment variable for fuzzer library.\n    fuzzer_lib = env['FUZZER_LIB']\n    env['LIB_FUZZING_ENGINE'] = fuzzer_lib\n    if os.path.exists(fuzzer_lib):\n        # Make /usr/lib/libFuzzingEngine.a point to our library for OSS-Fuzz\n        # so we can build projects that are using -lFuzzingEngine.\n        shutil.copy(fuzzer_lib, OSS_FUZZ_LIB_FUZZING_ENGINE_PATH)\n\n    if os.getenv('OSS_FUZZ'):\n        build_script = os.path.join(os.environ['SRC'], 'build.sh')\n    else:\n        build_script = os.path.join('benchmark', 'build.sh')\n\n    print('Building benchmark')\n    subprocess.check_call(['/bin/bash', '-ex', build_script], env=env)\n\n\ndef append_flags(env_var, additional_flags, env=None):\n    \"\"\"Append |additional_flags| to those already set in the value of |env_var|\n    and assign env_var to the result.\"\"\"\n    if env is None:\n        env = os.environ\n    flags = env.get(env_var, '').split(' ')\n    flags.extend(additional_flags)\n    env[env_var] = ' '.join(flags)\n\n\n# Use these flags when compiling benchmark code without a sanitizer (e.g. when\n# using eclipser). This is necessary because many OSS-Fuzz targets cannot\n# otherwise be compiled without a sanitizer because they implicitly depend on\n# libraries linked into the sanitizer runtime. These flags link against those\n# libraries.\nNO_SANITIZER_COMPAT_CFLAGS = [\n    '-pthread', '-Wl,--no-as-needed', '-Wl,-ldl', '-Wl,-lm',\n    '-Wno-unused-command-line-argument'\n]\nNO_SANITIZER_COMPAT_CXXFLAGS = ['-stdlib=libc++'] + NO_SANITIZER_COMPAT_CFLAGS\n\n\ndef set_no_sanitizer_compilation_flags(env=None):\n    \"\"\"Set compilation flags (CFLAGS and CXXFLAGS) in |env| so that a benchmark\n    can be compiled without a sanitizer. If |env| is not provided, the program's\n    environment will be used.\"\"\"\n    if env is None:\n        env = os.environ\n    env['CFLAGS'] = ' '.join(NO_SANITIZER_COMPAT_CFLAGS)\n    env['CXXFLAGS'] = ' '.join(NO_SANITIZER_COMPAT_CXXFLAGS)\n\n\n@contextlib.contextmanager\ndef restore_directory(directory):\n    \"\"\"Helper contextmanager that when created saves a backup of |directory| and\n    when closed/exited replaces |directory| with the backup.\n\n    Example usage:\n\n    directory = 'my-directory'\n    with restore_directory(directory):\n       shutil.rmtree(directory)\n    # At this point directory is in the same state where it was before we\n    # deleted it.\n    \"\"\"\n    # TODO(metzman): Figure out if this is worth it, so far it only allows QSYM\n    # to compile bloaty.\n    if not directory:\n        # Don't do anything if directory is None.\n        yield\n        return\n    # Save cwd so that if it gets deleted we can just switch into the restored\n    # version without code that runs after us running into issues.\n    initial_cwd = os.getcwd()\n    with tempfile.TemporaryDirectory() as temp_dir:\n        backup = os.path.join(temp_dir, os.path.basename(directory))\n        shutil.copytree(directory, backup)\n        yield\n        shutil.rmtree(directory)\n        shutil.move(backup, directory)\n        try:\n            os.getcwd()\n        except FileNotFoundError:\n            os.chdir(initial_cwd)\n\n\ndef get_dictionary_path(target_binary):\n    \"\"\"Return dictionary path for a target binary.\"\"\"\n    if os.getenv('SKIP_DICT'):\n        return None\n\n    dictionary_path = target_binary + '.dict'\n    if os.path.exists(dictionary_path):\n        return dictionary_path\n\n    options_file_path = target_binary + '.options'\n    if not os.path.exists(options_file_path):\n        return None\n\n    config = configparser.ConfigParser()\n    with open(options_file_path, 'r') as file_handle:\n        try:\n            config.read_file(file_handle)\n        except configparser.Error:\n            raise Exception('Failed to parse fuzzer options file: ' +\n                            options_file_path)\n\n    for section in config.sections():\n        for key, value in config.items(section):\n            if key == 'dict':\n                dictionary_path = os.path.join(os.path.dirname(target_binary),\n                                               value)\n                if not os.path.exists(dictionary_path):\n                    raise ValueError('Bad dictionary path in options file: ' +\n                                     options_file_path)\n                return dictionary_path\n    return None\n\n\ndef set_default_optimization_flag(env=None):\n    \"\"\"Set default optimization flag if none is already set.\"\"\"\n    if not env:\n        env = os.environ\n\n    for flag_var in ['CFLAGS', 'CXXFLAGS']:\n        append_flags(flag_var, [DEFAULT_OPTIMIZATION_LEVEL], env=env)\n\n\ndef initialize_flags(env=None):\n    \"\"\"Set initial flags before fuzzer.build() is called.\"\"\"\n    set_no_sanitizer_compilation_flags(env)\n    set_default_optimization_flag(env)\n\n    for flag_var in ['CFLAGS', 'CXXFLAGS']:\n        print('{flag_var} = {flag_value}'.format(\n            flag_var=flag_var, flag_value=os.getenv(flag_var)))\n", "path": "fuzzers/utils.py"}, {"content": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Module for building things on Google Cloud Build for use in trials.\"\"\"\n\nimport os\nfrom typing import Dict, Tuple\n\nfrom common import benchmark_utils\nfrom common import experiment_path as exp_path\nfrom common import experiment_utils\nfrom common import logs\nfrom common import new_process\nfrom common import utils\nfrom experiment.build import build_utils\n\n# Maximum time to wait for a GCB config to finish build.\nGCB_BUILD_TIMEOUT = 2 * 60 * 60  # 2 hours.\n\n# High cpu configuration for faster builds.\nGCB_MACHINE_TYPE = 'n1-highcpu-8'\n\nlogger = logs.Logger('builder')  # pylint: disable=invalid-name\n\n\ndef build_base_images() -> Tuple[int, str]:\n    \"\"\"Build base images on GCB.\"\"\"\n    return _build(get_build_config_file('base-images.yaml'), 'base-images')\n\n\ndef build_coverage(benchmark):\n    \"\"\"Build coverage image for benchmark on GCB.\"\"\"\n    if benchmark_utils.is_oss_fuzz(benchmark):\n        _build_oss_fuzz_project_coverage(benchmark)\n    else:\n        _build_benchmark_coverage(benchmark)\n\n\ndef _build_benchmark_coverage(benchmark: str) -> Tuple[int, str]:\n    \"\"\"Build a coverage build of |benchmark| on GCB.\"\"\"\n    coverage_binaries_dir = exp_path.gcs(\n        build_utils.get_coverage_binaries_dir())\n    substitutions = {\n        '_GCS_COVERAGE_BINARIES_DIR': coverage_binaries_dir,\n        '_BENCHMARK': benchmark,\n    }\n    config_file = get_build_config_file('coverage.yaml')\n    config_name = 'benchmark-{benchmark}-coverage'.format(benchmark=benchmark)\n    return _build(config_file, config_name, substitutions)\n\n\ndef _build_oss_fuzz_project_fuzzer(benchmark: str,\n                                   fuzzer: str) -> Tuple[int, str]:\n    \"\"\"Build a |benchmark|, |fuzzer| runner image on GCB.\"\"\"\n    project = benchmark_utils.get_project(benchmark)\n    oss_fuzz_builder_hash = benchmark_utils.get_oss_fuzz_builder_hash(benchmark)\n    substitutions = {\n        '_OSS_FUZZ_PROJECT': project,\n        '_FUZZER': fuzzer,\n        '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,\n    }\n    config_file = get_build_config_file('oss-fuzz-fuzzer.yaml')\n    config_name = 'oss-fuzz-{project}-fuzzer-{fuzzer}-hash-{hash}'.format(\n        project=project, fuzzer=fuzzer, hash=oss_fuzz_builder_hash)\n\n    return _build(config_file, config_name, substitutions)\n\n\ndef _build_benchmark_fuzzer(benchmark: str, fuzzer: str) -> Tuple[int, str]:\n    \"\"\"Build a |benchmark|, |fuzzer| runner image on GCB.\"\"\"\n    # See link for why substitutions must begin with an underscore:\n    # https://cloud.google.com/cloud-build/docs/configuring-builds/substitute-variable-values#using_user-defined_substitutions\n    substitutions = {\n        '_BENCHMARK': benchmark,\n        '_FUZZER': fuzzer,\n    }\n    config_file = get_build_config_file('fuzzer.yaml')\n    config_name = 'benchmark-{benchmark}-fuzzer-{fuzzer}'.format(\n        benchmark=benchmark, fuzzer=fuzzer)\n    return _build(config_file, config_name, substitutions)\n\n\ndef _build_oss_fuzz_project_coverage(benchmark: str) -> Tuple[int, str]:\n    \"\"\"Build a coverage build of OSS-Fuzz-based benchmark |benchmark| on GCB.\"\"\"\n    project = benchmark_utils.get_project(benchmark)\n    oss_fuzz_builder_hash = benchmark_utils.get_oss_fuzz_builder_hash(benchmark)\n    coverage_binaries_dir = exp_path.gcs(\n        build_utils.get_coverage_binaries_dir())\n    substitutions = {\n        '_GCS_COVERAGE_BINARIES_DIR': coverage_binaries_dir,\n        '_OSS_FUZZ_PROJECT': project,\n        '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,\n    }\n    config_file = get_build_config_file('oss-fuzz-coverage.yaml')\n    config_name = 'oss-fuzz-{project}-coverage-hash-{hash}'.format(\n        project=project, hash=oss_fuzz_builder_hash)\n    return _build(config_file, config_name, substitutions)\n\n\ndef _build(config_file: str,\n           config_name: str,\n           substitutions: Dict[str, str] = None,\n           timeout_seconds: int = GCB_BUILD_TIMEOUT) -> Tuple[int, str]:\n    \"\"\"Build each of |args| on gcb.\"\"\"\n    config_arg = '--config=%s' % config_file\n    machine_type_arg = '--machine-type=%s' % GCB_MACHINE_TYPE\n\n    # Use \"s\" suffix to denote seconds.\n    timeout_arg = '--timeout=%ds' % timeout_seconds\n\n    command = [\n        'gcloud',\n        'builds',\n        'submit',\n        str(utils.ROOT_DIR),\n        config_arg,\n        timeout_arg,\n        machine_type_arg,\n    ]\n\n    if substitutions is None:\n        substitutions = {}\n\n    assert '_REPO' not in substitutions\n    substitutions['_REPO'] = experiment_utils.get_base_docker_tag()\n\n    substitutions = [\n        '%s=%s' % (key, value) for key, value in substitutions.items()\n    ]\n    substitutions = ','.join(substitutions)\n    command.append('--substitutions=%s' % substitutions)\n\n    # Don't write to stdout to make concurrent building faster. Otherwise\n    # writing becomes the bottleneck.\n    result = new_process.execute(command,\n                                 write_to_stdout=False,\n                                 kill_children=True,\n                                 timeout=timeout_seconds)\n    build_utils.store_build_logs(config_name, result)\n    return result\n\n\ndef get_build_config_file(filename: str) -> str:\n    \"\"\"Return the path of the GCB build config file |filename|.\"\"\"\n    return os.path.join(utils.ROOT_DIR, 'experiment', 'gcb', filename)\n\n\ndef build_fuzzer_benchmark(fuzzer: str, benchmark: str) -> bool:\n    \"\"\"Builds |benchmark| for |fuzzer|.\"\"\"\n    if benchmark_utils.is_oss_fuzz(benchmark):\n        _build_oss_fuzz_project_fuzzer(benchmark, fuzzer)\n    else:\n        _build_benchmark_fuzzer(benchmark, fuzzer)\n", "path": "experiment/build/gcb_build.py"}], "after_files": [{"content": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Utility functions for running fuzzers.\"\"\"\n\nimport configparser\nimport contextlib\nimport os\nimport shutil\nimport subprocess\nimport tempfile\n\n# Keep all fuzzers at same optimization level until fuzzer explicitly needs or\n# specifies it.\nDEFAULT_OPTIMIZATION_LEVEL = '-O3'\n\nOSS_FUZZ_LIB_FUZZING_ENGINE_PATH = '/usr/lib/libFuzzingEngine.a'\n\n\ndef build_benchmark(env=None):\n    \"\"\"Build a benchmark using fuzzer library.\"\"\"\n    if not env:\n        env = os.environ.copy()\n\n    # Add OSS-Fuzz environment variable for fuzzer library.\n    fuzzer_lib = env['FUZZER_LIB']\n    env['LIB_FUZZING_ENGINE'] = fuzzer_lib\n    if os.path.exists(fuzzer_lib):\n        # Make /usr/lib/libFuzzingEngine.a point to our library for OSS-Fuzz\n        # so we can build projects that are using -lFuzzingEngine.\n        shutil.copy(fuzzer_lib, OSS_FUZZ_LIB_FUZZING_ENGINE_PATH)\n\n    if os.getenv('OSS_FUZZ'):\n        build_script = os.path.join(os.environ['SRC'], 'build.sh')\n    else:\n        build_script = os.path.join('benchmark', 'build.sh')\n\n    benchmark = os.getenv('BENCHMARK')\n    fuzzer = os.getenv('FUZZER')\n    print('Building benchmark {benchmark} with fuzzer {fuzzer}'.format(\n        benchmark=benchmark, fuzzer=fuzzer))\n    subprocess.check_call(['/bin/bash', '-ex', build_script], env=env)\n\n\ndef append_flags(env_var, additional_flags, env=None):\n    \"\"\"Append |additional_flags| to those already set in the value of |env_var|\n    and assign env_var to the result.\"\"\"\n    if env is None:\n        env = os.environ\n    flags = env.get(env_var, '').split(' ')\n    flags.extend(additional_flags)\n    env[env_var] = ' '.join(flags)\n\n\n# Use these flags when compiling benchmark code without a sanitizer (e.g. when\n# using eclipser). This is necessary because many OSS-Fuzz targets cannot\n# otherwise be compiled without a sanitizer because they implicitly depend on\n# libraries linked into the sanitizer runtime. These flags link against those\n# libraries.\nNO_SANITIZER_COMPAT_CFLAGS = [\n    '-pthread', '-Wl,--no-as-needed', '-Wl,-ldl', '-Wl,-lm',\n    '-Wno-unused-command-line-argument'\n]\nNO_SANITIZER_COMPAT_CXXFLAGS = ['-stdlib=libc++'] + NO_SANITIZER_COMPAT_CFLAGS\n\n\ndef set_no_sanitizer_compilation_flags(env=None):\n    \"\"\"Set compilation flags (CFLAGS and CXXFLAGS) in |env| so that a benchmark\n    can be compiled without a sanitizer. If |env| is not provided, the program's\n    environment will be used.\"\"\"\n    if env is None:\n        env = os.environ\n    env['CFLAGS'] = ' '.join(NO_SANITIZER_COMPAT_CFLAGS)\n    env['CXXFLAGS'] = ' '.join(NO_SANITIZER_COMPAT_CXXFLAGS)\n\n\n@contextlib.contextmanager\ndef restore_directory(directory):\n    \"\"\"Helper contextmanager that when created saves a backup of |directory| and\n    when closed/exited replaces |directory| with the backup.\n\n    Example usage:\n\n    directory = 'my-directory'\n    with restore_directory(directory):\n       shutil.rmtree(directory)\n    # At this point directory is in the same state where it was before we\n    # deleted it.\n    \"\"\"\n    # TODO(metzman): Figure out if this is worth it, so far it only allows QSYM\n    # to compile bloaty.\n    if not directory:\n        # Don't do anything if directory is None.\n        yield\n        return\n    # Save cwd so that if it gets deleted we can just switch into the restored\n    # version without code that runs after us running into issues.\n    initial_cwd = os.getcwd()\n    with tempfile.TemporaryDirectory() as temp_dir:\n        backup = os.path.join(temp_dir, os.path.basename(directory))\n        shutil.copytree(directory, backup)\n        yield\n        shutil.rmtree(directory)\n        shutil.move(backup, directory)\n        try:\n            os.getcwd()\n        except FileNotFoundError:\n            os.chdir(initial_cwd)\n\n\ndef get_dictionary_path(target_binary):\n    \"\"\"Return dictionary path for a target binary.\"\"\"\n    if os.getenv('SKIP_DICT'):\n        return None\n\n    dictionary_path = target_binary + '.dict'\n    if os.path.exists(dictionary_path):\n        return dictionary_path\n\n    options_file_path = target_binary + '.options'\n    if not os.path.exists(options_file_path):\n        return None\n\n    config = configparser.ConfigParser()\n    with open(options_file_path, 'r') as file_handle:\n        try:\n            config.read_file(file_handle)\n        except configparser.Error:\n            raise Exception('Failed to parse fuzzer options file: ' +\n                            options_file_path)\n\n    for section in config.sections():\n        for key, value in config.items(section):\n            if key == 'dict':\n                dictionary_path = os.path.join(os.path.dirname(target_binary),\n                                               value)\n                if not os.path.exists(dictionary_path):\n                    raise ValueError('Bad dictionary path in options file: ' +\n                                     options_file_path)\n                return dictionary_path\n    return None\n\n\ndef set_default_optimization_flag(env=None):\n    \"\"\"Set default optimization flag if none is already set.\"\"\"\n    if not env:\n        env = os.environ\n\n    for flag_var in ['CFLAGS', 'CXXFLAGS']:\n        append_flags(flag_var, [DEFAULT_OPTIMIZATION_LEVEL], env=env)\n\n\ndef initialize_flags(env=None):\n    \"\"\"Set initial flags before fuzzer.build() is called.\"\"\"\n    set_no_sanitizer_compilation_flags(env)\n    set_default_optimization_flag(env)\n\n    for flag_var in ['CFLAGS', 'CXXFLAGS']:\n        print('{flag_var} = {flag_value}'.format(\n            flag_var=flag_var, flag_value=os.getenv(flag_var)))\n", "path": "fuzzers/utils.py"}, {"content": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Module for building things on Google Cloud Build for use in trials.\"\"\"\n\nimport os\nfrom typing import Dict, Tuple\n\nfrom common import benchmark_utils\nfrom common import experiment_path as exp_path\nfrom common import experiment_utils\nfrom common import logs\nfrom common import new_process\nfrom common import utils\nfrom experiment.build import build_utils\n\n# Maximum time to wait for a GCB config to finish build.\nGCB_BUILD_TIMEOUT = 2 * 60 * 60  # 2 hours.\n\n# High cpu configuration for faster builds.\nGCB_MACHINE_TYPE = 'n1-highcpu-8'\n\nlogger = logs.Logger('builder')  # pylint: disable=invalid-name\n\n\ndef build_base_images() -> Tuple[int, str]:\n    \"\"\"Build base images on GCB.\"\"\"\n    return _build(get_build_config_file('base-images.yaml'), 'base-images')\n\n\ndef build_coverage(benchmark):\n    \"\"\"Build coverage image for benchmark on GCB.\"\"\"\n    if benchmark_utils.is_oss_fuzz(benchmark):\n        _build_oss_fuzz_project_coverage(benchmark)\n    else:\n        _build_benchmark_coverage(benchmark)\n\n\ndef _build_benchmark_coverage(benchmark: str) -> Tuple[int, str]:\n    \"\"\"Build a coverage build of |benchmark| on GCB.\"\"\"\n    coverage_binaries_dir = exp_path.gcs(\n        build_utils.get_coverage_binaries_dir())\n    substitutions = {\n        '_GCS_COVERAGE_BINARIES_DIR': coverage_binaries_dir,\n        '_BENCHMARK': benchmark,\n    }\n    config_file = get_build_config_file('coverage.yaml')\n    config_name = 'benchmark-{benchmark}-coverage'.format(benchmark=benchmark)\n    return _build(config_file, config_name, substitutions)\n\n\ndef _build_oss_fuzz_project_fuzzer(benchmark: str,\n                                   fuzzer: str) -> Tuple[int, str]:\n    \"\"\"Build a |benchmark|, |fuzzer| runner image on GCB.\"\"\"\n    project = benchmark_utils.get_project(benchmark)\n    oss_fuzz_builder_hash = benchmark_utils.get_oss_fuzz_builder_hash(benchmark)\n    substitutions = {\n        '_OSS_FUZZ_PROJECT': project,\n        '_BENCHMARK': benchmark,\n        '_FUZZER': fuzzer,\n        '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,\n    }\n    config_file = get_build_config_file('oss-fuzz-fuzzer.yaml')\n    config_name = 'oss-fuzz-{project}-fuzzer-{fuzzer}-hash-{hash}'.format(\n        project=project, fuzzer=fuzzer, hash=oss_fuzz_builder_hash)\n\n    return _build(config_file, config_name, substitutions)\n\n\ndef _build_benchmark_fuzzer(benchmark: str, fuzzer: str) -> Tuple[int, str]:\n    \"\"\"Build a |benchmark|, |fuzzer| runner image on GCB.\"\"\"\n    # See link for why substitutions must begin with an underscore:\n    # https://cloud.google.com/cloud-build/docs/configuring-builds/substitute-variable-values#using_user-defined_substitutions\n    substitutions = {\n        '_BENCHMARK': benchmark,\n        '_FUZZER': fuzzer,\n    }\n    config_file = get_build_config_file('fuzzer.yaml')\n    config_name = 'benchmark-{benchmark}-fuzzer-{fuzzer}'.format(\n        benchmark=benchmark, fuzzer=fuzzer)\n    return _build(config_file, config_name, substitutions)\n\n\ndef _build_oss_fuzz_project_coverage(benchmark: str) -> Tuple[int, str]:\n    \"\"\"Build a coverage build of OSS-Fuzz-based benchmark |benchmark| on GCB.\"\"\"\n    project = benchmark_utils.get_project(benchmark)\n    oss_fuzz_builder_hash = benchmark_utils.get_oss_fuzz_builder_hash(benchmark)\n    coverage_binaries_dir = exp_path.gcs(\n        build_utils.get_coverage_binaries_dir())\n    substitutions = {\n        '_GCS_COVERAGE_BINARIES_DIR': coverage_binaries_dir,\n        '_OSS_FUZZ_PROJECT': project,\n        '_BENCHMARK': benchmark,\n        '_OSS_FUZZ_BUILDER_HASH': oss_fuzz_builder_hash,\n    }\n    config_file = get_build_config_file('oss-fuzz-coverage.yaml')\n    config_name = 'oss-fuzz-{project}-coverage-hash-{hash}'.format(\n        project=project, hash=oss_fuzz_builder_hash)\n    return _build(config_file, config_name, substitutions)\n\n\ndef _build(config_file: str,\n           config_name: str,\n           substitutions: Dict[str, str] = None,\n           timeout_seconds: int = GCB_BUILD_TIMEOUT) -> Tuple[int, str]:\n    \"\"\"Build each of |args| on gcb.\"\"\"\n    config_arg = '--config=%s' % config_file\n    machine_type_arg = '--machine-type=%s' % GCB_MACHINE_TYPE\n\n    # Use \"s\" suffix to denote seconds.\n    timeout_arg = '--timeout=%ds' % timeout_seconds\n\n    command = [\n        'gcloud',\n        'builds',\n        'submit',\n        str(utils.ROOT_DIR),\n        config_arg,\n        timeout_arg,\n        machine_type_arg,\n    ]\n\n    if substitutions is None:\n        substitutions = {}\n\n    assert '_REPO' not in substitutions\n    substitutions['_REPO'] = experiment_utils.get_base_docker_tag()\n\n    substitutions = [\n        '%s=%s' % (key, value) for key, value in substitutions.items()\n    ]\n    substitutions = ','.join(substitutions)\n    command.append('--substitutions=%s' % substitutions)\n\n    # Don't write to stdout to make concurrent building faster. Otherwise\n    # writing becomes the bottleneck.\n    result = new_process.execute(command,\n                                 write_to_stdout=False,\n                                 kill_children=True,\n                                 timeout=timeout_seconds)\n    build_utils.store_build_logs(config_name, result)\n    return result\n\n\ndef get_build_config_file(filename: str) -> str:\n    \"\"\"Return the path of the GCB build config file |filename|.\"\"\"\n    return os.path.join(utils.ROOT_DIR, 'experiment', 'gcb', filename)\n\n\ndef build_fuzzer_benchmark(fuzzer: str, benchmark: str) -> bool:\n    \"\"\"Builds |benchmark| for |fuzzer|.\"\"\"\n    if benchmark_utils.is_oss_fuzz(benchmark):\n        _build_oss_fuzz_project_fuzzer(benchmark, fuzzer)\n    else:\n        _build_benchmark_fuzzer(benchmark, fuzzer)\n", "path": "experiment/build/gcb_build.py"}]}