We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` discarded
It seems that the value of `CFLAGS` set in the builders is discarded while building the benchmarks using the appropriate `fuzzer.py` file. The discard happens here, it would seem:
https://github.com/google/fuzzbench/blob/d156b3579fe882b46fb65ab3f2bc9a5c5aeb3308/fuzzers/utils.py#L179-L180

The value of `CFLAGS` set in the builders contains `-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION`, which is thus discarded while building. Discarding this value makes at least `libxslt_xpath` and `libxml2_libxml2_xml_reader_for_file_fuzzer` compile with features that make executions non-deterministic. Other benchmarks may be affected.

--- 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 ast
17 import configparser
18 import contextlib
19 import os
20 import shutil
21 import subprocess
22 import tempfile
23 
24 import yaml
25 
26 # Keep all fuzzers at same optimization level until fuzzer explicitly needs or
27 # specifies it.
28 DEFAULT_OPTIMIZATION_LEVEL = '-O3'
29 BUGS_OPTIMIZATION_LEVEL = '-O1'
30 
31 LIBCPLUSPLUS_FLAG = '-stdlib=libc++'
32 
33 # Flags to use when using sanitizer for bug based benchmarking.
34 SANITIZER_FLAGS = [
35     '-fsanitize=address',
36     # Matches UBSan features enabled in OSS-Fuzz.
37     # See https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/Dockerfile#L94
38     '-fsanitize=array-bounds,bool,builtin,enum,float-divide-by-zero,function,'
39     'integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,'
40     'shift,signed-integer-overflow,unreachable,vla-bound,vptr',
41 ]
42 
43 # Use these flags when compiling benchmark code without a sanitizer (e.g. when
44 # using eclipser). This is necessary because many OSS-Fuzz targets cannot
45 # otherwise be compiled without a sanitizer because they implicitly depend on
46 # libraries linked into the sanitizer runtime. These flags link against those
47 # libraries.
48 NO_SANITIZER_COMPAT_CFLAGS = [
49     '-pthread', '-Wl,--no-as-needed', '-Wl,-ldl', '-Wl,-lm',
50     '-Wno-unused-command-line-argument'
51 ]
52 
53 OSS_FUZZ_LIB_FUZZING_ENGINE_PATH = '/usr/lib/libFuzzingEngine.a'
54 BENCHMARK_CONFIG_YAML_PATH = '/benchmark.yaml'
55 
56 
57 def build_benchmark(env=None):
58     """Build a benchmark using fuzzer library."""
59     if not env:
60         env = os.environ.copy()
61 
62     # Add OSS-Fuzz environment variable for fuzzer library.
63     fuzzer_lib = env['FUZZER_LIB']
64     env['LIB_FUZZING_ENGINE'] = fuzzer_lib
65     if os.path.exists(fuzzer_lib):
66         # Make /usr/lib/libFuzzingEngine.a point to our library for OSS-Fuzz
67         # so we can build projects that are using -lFuzzingEngine.
68         shutil.copy(fuzzer_lib, OSS_FUZZ_LIB_FUZZING_ENGINE_PATH)
69 
70     build_script = os.path.join(os.environ['SRC'], 'build.sh')
71 
72     benchmark = os.getenv('BENCHMARK')
73     fuzzer = os.getenv('FUZZER')
74     print('Building benchmark {benchmark} with fuzzer {fuzzer}'.format(
75         benchmark=benchmark, fuzzer=fuzzer))
76     subprocess.check_call(['/bin/bash', '-ex', build_script], env=env)
77 
78 
79 def append_flags(env_var, additional_flags, env=None):
80     """Append |additional_flags| to those already set in the value of |env_var|
81     and assign env_var to the result."""
82     if env is None:
83         env = os.environ
84 
85     env_var_value = env.get(env_var)
86     flags = env_var_value.split(' ') if env_var_value else []
87     flags.extend(additional_flags)
88     env[env_var] = ' '.join(flags)
89 
90 
91 def get_config_value(attribute):
92     """Gets config attribute value from benchmark config yaml file."""
93     with open(BENCHMARK_CONFIG_YAML_PATH) as file_handle:
94         config = yaml.load(file_handle, yaml.SafeLoader)
95         return config.get(attribute)
96 
97 
98 @contextlib.contextmanager
99 def restore_directory(directory):
100     """Helper contextmanager that when created saves a backup of |directory| and
101     when closed/exited replaces |directory| with the backup.
102 
103     Example usage:
104 
105     directory = 'my-directory'
106     with restore_directory(directory):
107        shutil.rmtree(directory)
108     # At this point directory is in the same state where it was before we
109     # deleted it.
110     """
111     # TODO(metzman): Figure out if this is worth it, so far it only allows QSYM
112     # to compile bloaty.
113     if not directory:
114         # Don't do anything if directory is None.
115         yield
116         return
117     # Save cwd so that if it gets deleted we can just switch into the restored
118     # version without code that runs after us running into issues.
119     initial_cwd = os.getcwd()
120     with tempfile.TemporaryDirectory() as temp_dir:
121         backup = os.path.join(temp_dir, os.path.basename(directory))
122         shutil.copytree(directory, backup, symlinks=True)
123         yield
124         shutil.rmtree(directory)
125         shutil.move(backup, directory)
126         try:
127             os.getcwd()
128         except FileNotFoundError:
129             os.chdir(initial_cwd)
130 
131 
132 def get_dictionary_path(target_binary):
133     """Return dictionary path for a target binary."""
134     if get_env('NO_DICTIONARIES'):
135         # Don't use dictionaries if experiment specifies not to.
136         return None
137 
138     dictionary_path = target_binary + '.dict'
139     if os.path.exists(dictionary_path):
140         return dictionary_path
141 
142     options_file_path = target_binary + '.options'
143     if not os.path.exists(options_file_path):
144         return None
145 
146     config = configparser.ConfigParser()
147     with open(options_file_path, 'r') as file_handle:
148         try:
149             config.read_file(file_handle)
150         except configparser.Error as error:
151             raise Exception('Failed to parse fuzzer options file: ' +
152                             options_file_path) from error
153 
154     for section in config.sections():
155         for key, value in config.items(section):
156             if key == 'dict':
157                 dictionary_path = os.path.join(os.path.dirname(target_binary),
158                                                value)
159                 if not os.path.exists(dictionary_path):
160                     raise ValueError('Bad dictionary path in options file: ' +
161                                      options_file_path)
162                 return dictionary_path
163     return None
164 
165 
166 def set_fuzz_target(env=None):
167     """Set |FUZZ_TARGET| env flag."""
168     if env is None:
169         env = os.environ
170 
171     env['FUZZ_TARGET'] = get_config_value('fuzz_target')
172 
173 
174 def set_compilation_flags(env=None):
175     """Set compilation flags."""
176     if env is None:
177         env = os.environ
178 
179     env['CFLAGS'] = ''
180     env['CXXFLAGS'] = ''
181 
182     if get_config_value('type') == 'bug':
183         append_flags('CFLAGS',
184                      SANITIZER_FLAGS + [BUGS_OPTIMIZATION_LEVEL],
185                      env=env)
186         append_flags('CXXFLAGS',
187                      SANITIZER_FLAGS +
188                      [LIBCPLUSPLUS_FLAG, BUGS_OPTIMIZATION_LEVEL],
189                      env=env)
190     else:
191         append_flags('CFLAGS',
192                      NO_SANITIZER_COMPAT_CFLAGS + [DEFAULT_OPTIMIZATION_LEVEL],
193                      env=env)
194         append_flags('CXXFLAGS',
195                      NO_SANITIZER_COMPAT_CFLAGS +
196                      [LIBCPLUSPLUS_FLAG, DEFAULT_OPTIMIZATION_LEVEL],
197                      env=env)
198 
199 
200 def initialize_env(env=None):
201     """Set initial flags before fuzzer.build() is called."""
202     set_fuzz_target(env)
203     set_compilation_flags(env)
204 
205     for env_var in ['FUZZ_TARGET', 'CFLAGS', 'CXXFLAGS']:
206         print('{env_var} = {env_value}'.format(env_var=env_var,
207                                                env_value=os.getenv(env_var)))
208 
209 
210 def get_env(env_var, default_value=None):
211     """Return the evaluated value of |env_var| in the environment. This is
212     a copy of common.environment.get function as fuzzers can't have source
213     dependencies outside of this directory."""
214     value_string = os.getenv(env_var)
215 
216     # value_string will be None if the variable is not defined.
217     if value_string is None:
218         return default_value
219 
220     try:
221         return ast.literal_eval(value_string)
222     except Exception:  # pylint: disable=broad-except
223         # String fallback.
224         return value_string
225 
226 
227 def create_seed_file_for_empty_corpus(input_corpus):
228     """Create a fake seed file in an empty corpus, skip otherwise."""
229     if os.listdir(input_corpus):
230         # Input corpus has some files, no need of a seed file. Bail out.
231         return
232 
233     print('Creating a fake seed file in empty corpus directory.')
234     default_seed_file = os.path.join(input_corpus, 'default_seed')
235     with open(default_seed_file, 'w') as file_handle:
236         file_handle.write('hi')
237
```
--- 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/fuzzers/utils.py b/fuzzers/utils.py
--- a/fuzzers/utils.py
+++ b/fuzzers/utils.py
@@ -50,6 +50,8 @@
     '-Wno-unused-command-line-argument'
 ]
 
+FUZZING_CFLAGS = ['-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION']
+
 OSS_FUZZ_LIB_FUZZING_ENGINE_PATH = '/usr/lib/libFuzzingEngine.a'
 BENCHMARK_CONFIG_YAML_PATH = '/benchmark.yaml'
 
@@ -181,18 +183,20 @@
 
     if get_config_value('type') == 'bug':
         append_flags('CFLAGS',
-                     SANITIZER_FLAGS + [BUGS_OPTIMIZATION_LEVEL],
+                     FUZZING_CFLAGS + SANITIZER_FLAGS +
+                     [BUGS_OPTIMIZATION_LEVEL],
                      env=env)
         append_flags('CXXFLAGS',
-                     SANITIZER_FLAGS +
+                     FUZZING_CFLAGS + SANITIZER_FLAGS +
                      [LIBCPLUSPLUS_FLAG, BUGS_OPTIMIZATION_LEVEL],
                      env=env)
     else:
         append_flags('CFLAGS',
-                     NO_SANITIZER_COMPAT_CFLAGS + [DEFAULT_OPTIMIZATION_LEVEL],
+                     FUZZING_CFLAGS + NO_SANITIZER_COMPAT_CFLAGS +
+                     [DEFAULT_OPTIMIZATION_LEVEL],
                      env=env)
         append_flags('CXXFLAGS',
-                     NO_SANITIZER_COMPAT_CFLAGS +
+                     FUZZING_CFLAGS + NO_SANITIZER_COMPAT_CFLAGS +
                      [LIBCPLUSPLUS_FLAG, DEFAULT_OPTIMIZATION_LEVEL],
                      env=env)

{"golden_diff": "diff --git a/fuzzers/utils.py b/fuzzers/utils.py\n--- a/fuzzers/utils.py\n+++ b/fuzzers/utils.py\n@@ -50,6 +50,8 @@\n     '-Wno-unused-command-line-argument'\n ]\n \n+FUZZING_CFLAGS = ['-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION']\n+\n OSS_FUZZ_LIB_FUZZING_ENGINE_PATH = '/usr/lib/libFuzzingEngine.a'\n BENCHMARK_CONFIG_YAML_PATH = '/benchmark.yaml'\n \n@@ -181,18 +183,20 @@\n \n     if get_config_value('type') == 'bug':\n         append_flags('CFLAGS',\n-                     SANITIZER_FLAGS + [BUGS_OPTIMIZATION_LEVEL],\n+                     FUZZING_CFLAGS + SANITIZER_FLAGS +\n+                     [BUGS_OPTIMIZATION_LEVEL],\n                      env=env)\n         append_flags('CXXFLAGS',\n-                     SANITIZER_FLAGS +\n+                     FUZZING_CFLAGS + SANITIZER_FLAGS +\n                      [LIBCPLUSPLUS_FLAG, BUGS_OPTIMIZATION_LEVEL],\n                      env=env)\n     else:\n         append_flags('CFLAGS',\n-                     NO_SANITIZER_COMPAT_CFLAGS + [DEFAULT_OPTIMIZATION_LEVEL],\n+                     FUZZING_CFLAGS + NO_SANITIZER_COMPAT_CFLAGS +\n+                     [DEFAULT_OPTIMIZATION_LEVEL],\n                      env=env)\n         append_flags('CXXFLAGS',\n-                     NO_SANITIZER_COMPAT_CFLAGS +\n+                     FUZZING_CFLAGS + NO_SANITIZER_COMPAT_CFLAGS +\n                      [LIBCPLUSPLUS_FLAG, DEFAULT_OPTIMIZATION_LEVEL],\n                      env=env)\n", "issue": "`FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` discarded\nIt seems that the value of `CFLAGS` set in the builders is discarded while building the benchmarks using the appropriate `fuzzer.py` file. The discard happens here, it would seem:\r\nhttps://github.com/google/fuzzbench/blob/d156b3579fe882b46fb65ab3f2bc9a5c5aeb3308/fuzzers/utils.py#L179-L180\r\n\r\nThe value of `CFLAGS` set in the builders contains `-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION`, which is thus discarded while building. Discarding this value makes at least `libxslt_xpath` and `libxml2_libxml2_xml_reader_for_file_fuzzer` compile with features that make executions non-deterministic. Other benchmarks may be affected.\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 ast\nimport configparser\nimport contextlib\nimport os\nimport shutil\nimport subprocess\nimport tempfile\n\nimport yaml\n\n# Keep all fuzzers at same optimization level until fuzzer explicitly needs or\n# specifies it.\nDEFAULT_OPTIMIZATION_LEVEL = '-O3'\nBUGS_OPTIMIZATION_LEVEL = '-O1'\n\nLIBCPLUSPLUS_FLAG = '-stdlib=libc++'\n\n# Flags to use when using sanitizer for bug based benchmarking.\nSANITIZER_FLAGS = [\n    '-fsanitize=address',\n    # Matches UBSan features enabled in OSS-Fuzz.\n    # See https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/Dockerfile#L94\n    '-fsanitize=array-bounds,bool,builtin,enum,float-divide-by-zero,function,'\n    'integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,'\n    'shift,signed-integer-overflow,unreachable,vla-bound,vptr',\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]\n\nOSS_FUZZ_LIB_FUZZING_ENGINE_PATH = '/usr/lib/libFuzzingEngine.a'\nBENCHMARK_CONFIG_YAML_PATH = '/benchmark.yaml'\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    build_script = os.path.join(os.environ['SRC'], '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\n    env_var_value = env.get(env_var)\n    flags = env_var_value.split(' ') if env_var_value else []\n    flags.extend(additional_flags)\n    env[env_var] = ' '.join(flags)\n\n\ndef get_config_value(attribute):\n    \"\"\"Gets config attribute value from benchmark config yaml file.\"\"\"\n    with open(BENCHMARK_CONFIG_YAML_PATH) as file_handle:\n        config = yaml.load(file_handle, yaml.SafeLoader)\n        return config.get(attribute)\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, symlinks=True)\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 get_env('NO_DICTIONARIES'):\n        # Don't use dictionaries if experiment specifies not to.\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 as error:\n            raise Exception('Failed to parse fuzzer options file: ' +\n                            options_file_path) from error\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_fuzz_target(env=None):\n    \"\"\"Set |FUZZ_TARGET| env flag.\"\"\"\n    if env is None:\n        env = os.environ\n\n    env['FUZZ_TARGET'] = get_config_value('fuzz_target')\n\n\ndef set_compilation_flags(env=None):\n    \"\"\"Set compilation flags.\"\"\"\n    if env is None:\n        env = os.environ\n\n    env['CFLAGS'] = ''\n    env['CXXFLAGS'] = ''\n\n    if get_config_value('type') == 'bug':\n        append_flags('CFLAGS',\n                     SANITIZER_FLAGS + [BUGS_OPTIMIZATION_LEVEL],\n                     env=env)\n        append_flags('CXXFLAGS',\n                     SANITIZER_FLAGS +\n                     [LIBCPLUSPLUS_FLAG, BUGS_OPTIMIZATION_LEVEL],\n                     env=env)\n    else:\n        append_flags('CFLAGS',\n                     NO_SANITIZER_COMPAT_CFLAGS + [DEFAULT_OPTIMIZATION_LEVEL],\n                     env=env)\n        append_flags('CXXFLAGS',\n                     NO_SANITIZER_COMPAT_CFLAGS +\n                     [LIBCPLUSPLUS_FLAG, DEFAULT_OPTIMIZATION_LEVEL],\n                     env=env)\n\n\ndef initialize_env(env=None):\n    \"\"\"Set initial flags before fuzzer.build() is called.\"\"\"\n    set_fuzz_target(env)\n    set_compilation_flags(env)\n\n    for env_var in ['FUZZ_TARGET', 'CFLAGS', 'CXXFLAGS']:\n        print('{env_var} = {env_value}'.format(env_var=env_var,\n                                               env_value=os.getenv(env_var)))\n\n\ndef get_env(env_var, default_value=None):\n    \"\"\"Return the evaluated value of |env_var| in the environment. This is\n    a copy of common.environment.get function as fuzzers can't have source\n    dependencies outside of this directory.\"\"\"\n    value_string = os.getenv(env_var)\n\n    # value_string will be None if the variable is not defined.\n    if value_string is None:\n        return default_value\n\n    try:\n        return ast.literal_eval(value_string)\n    except Exception:  # pylint: disable=broad-except\n        # String fallback.\n        return value_string\n\n\ndef create_seed_file_for_empty_corpus(input_corpus):\n    \"\"\"Create a fake seed file in an empty corpus, skip otherwise.\"\"\"\n    if os.listdir(input_corpus):\n        # Input corpus has some files, no need of a seed file. Bail out.\n        return\n\n    print('Creating a fake seed file in empty corpus directory.')\n    default_seed_file = os.path.join(input_corpus, 'default_seed')\n    with open(default_seed_file, 'w') as file_handle:\n        file_handle.write('hi')\n", "path": "fuzzers/utils.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 ast\nimport configparser\nimport contextlib\nimport os\nimport shutil\nimport subprocess\nimport tempfile\n\nimport yaml\n\n# Keep all fuzzers at same optimization level until fuzzer explicitly needs or\n# specifies it.\nDEFAULT_OPTIMIZATION_LEVEL = '-O3'\nBUGS_OPTIMIZATION_LEVEL = '-O1'\n\nLIBCPLUSPLUS_FLAG = '-stdlib=libc++'\n\n# Flags to use when using sanitizer for bug based benchmarking.\nSANITIZER_FLAGS = [\n    '-fsanitize=address',\n    # Matches UBSan features enabled in OSS-Fuzz.\n    # See https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/Dockerfile#L94\n    '-fsanitize=array-bounds,bool,builtin,enum,float-divide-by-zero,function,'\n    'integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,'\n    'shift,signed-integer-overflow,unreachable,vla-bound,vptr',\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]\n\nFUZZING_CFLAGS = ['-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION']\n\nOSS_FUZZ_LIB_FUZZING_ENGINE_PATH = '/usr/lib/libFuzzingEngine.a'\nBENCHMARK_CONFIG_YAML_PATH = '/benchmark.yaml'\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    build_script = os.path.join(os.environ['SRC'], '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\n    env_var_value = env.get(env_var)\n    flags = env_var_value.split(' ') if env_var_value else []\n    flags.extend(additional_flags)\n    env[env_var] = ' '.join(flags)\n\n\ndef get_config_value(attribute):\n    \"\"\"Gets config attribute value from benchmark config yaml file.\"\"\"\n    with open(BENCHMARK_CONFIG_YAML_PATH) as file_handle:\n        config = yaml.load(file_handle, yaml.SafeLoader)\n        return config.get(attribute)\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, symlinks=True)\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 get_env('NO_DICTIONARIES'):\n        # Don't use dictionaries if experiment specifies not to.\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 as error:\n            raise Exception('Failed to parse fuzzer options file: ' +\n                            options_file_path) from error\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_fuzz_target(env=None):\n    \"\"\"Set |FUZZ_TARGET| env flag.\"\"\"\n    if env is None:\n        env = os.environ\n\n    env['FUZZ_TARGET'] = get_config_value('fuzz_target')\n\n\ndef set_compilation_flags(env=None):\n    \"\"\"Set compilation flags.\"\"\"\n    if env is None:\n        env = os.environ\n\n    env['CFLAGS'] = ''\n    env['CXXFLAGS'] = ''\n\n    if get_config_value('type') == 'bug':\n        append_flags('CFLAGS',\n                     FUZZING_CFLAGS + SANITIZER_FLAGS +\n                     [BUGS_OPTIMIZATION_LEVEL],\n                     env=env)\n        append_flags('CXXFLAGS',\n                     FUZZING_CFLAGS + SANITIZER_FLAGS +\n                     [LIBCPLUSPLUS_FLAG, BUGS_OPTIMIZATION_LEVEL],\n                     env=env)\n    else:\n        append_flags('CFLAGS',\n                     FUZZING_CFLAGS + NO_SANITIZER_COMPAT_CFLAGS +\n                     [DEFAULT_OPTIMIZATION_LEVEL],\n                     env=env)\n        append_flags('CXXFLAGS',\n                     FUZZING_CFLAGS + NO_SANITIZER_COMPAT_CFLAGS +\n                     [LIBCPLUSPLUS_FLAG, DEFAULT_OPTIMIZATION_LEVEL],\n                     env=env)\n\n\ndef initialize_env(env=None):\n    \"\"\"Set initial flags before fuzzer.build() is called.\"\"\"\n    set_fuzz_target(env)\n    set_compilation_flags(env)\n\n    for env_var in ['FUZZ_TARGET', 'CFLAGS', 'CXXFLAGS']:\n        print('{env_var} = {env_value}'.format(env_var=env_var,\n                                               env_value=os.getenv(env_var)))\n\n\ndef get_env(env_var, default_value=None):\n    \"\"\"Return the evaluated value of |env_var| in the environment. This is\n    a copy of common.environment.get function as fuzzers can't have source\n    dependencies outside of this directory.\"\"\"\n    value_string = os.getenv(env_var)\n\n    # value_string will be None if the variable is not defined.\n    if value_string is None:\n        return default_value\n\n    try:\n        return ast.literal_eval(value_string)\n    except Exception:  # pylint: disable=broad-except\n        # String fallback.\n        return value_string\n\n\ndef create_seed_file_for_empty_corpus(input_corpus):\n    \"\"\"Create a fake seed file in an empty corpus, skip otherwise.\"\"\"\n    if os.listdir(input_corpus):\n        # Input corpus has some files, no need of a seed file. Bail out.\n        return\n\n    print('Creating a fake seed file in empty corpus directory.')\n    default_seed_file = os.path.join(input_corpus, 'default_seed')\n    with open(default_seed_file, 'w') as file_handle:\n        file_handle.write('hi')\n", "path": "fuzzers/utils.py"}]}