diff options
author | 2020-08-26 11:59:56 -0700 | |
---|---|---|
committer | 2020-08-26 11:59:56 -0700 | |
commit | db8467bf302b0398feaf8317cbba0a2801775da5 (patch) | |
tree | 7d8436451ae03a59064024eae835e92a38fe6ffd /infra | |
parent | a6abdaa5ac13d8c92654d2ce871de699d583e7da (diff) |
[CI] Don't do coverage builds for engineless fuzzers. (#4374)
Coverage builds need to be special cased since they aren't specified
in sanitizers. Instead they are done for all C/C++ projects that
use libFuzzer.
Move all of this special casing to `should_build_coverage` and call that from
`should_build` so we have one place where we decide this.
Add tests as well.
Fixes: https://github.com/google/oss-fuzz/issues/4371
Diffstat (limited to 'infra')
-rwxr-xr-x | infra/ci/build.py | 40 | ||||
-rw-r--r-- | infra/ci/build_test.py | 93 |
2 files changed, 122 insertions, 11 deletions
diff --git a/infra/ci/build.py b/infra/ci/build.py index 15dd4fb6..9bdbb969 100755 --- a/infra/ci/build.py +++ b/infra/ci/build.py @@ -87,8 +87,34 @@ def check_build(project, engine, sanitizer, architecture): ]) +def should_build_coverage(project_yaml): + """Returns True if a coverage build should be done based on project.yaml + contents.""" + # Enable coverage builds on projects that use engines. Those that don't use + # engines shouldn't get coverage builds. + engines = project_yaml.get('fuzzing_engines', DEFAULT_ENGINES) + engineless = 'none' in engines + if engineless: + assert_message = ('Forbidden to specify multiple engines for ' + '"fuzzing_engines" if "none" is specified.') + assert len(engines) == 1, assert_message + return False + + language = project_yaml.get('language') + if language not in LANGUAGES_WITH_COVERAGE_SUPPORT: + print(('Project is written in "{language}", ' + 'coverage is not supported yet.').format(language=language)) + return False + + return True + + def should_build(project_yaml): - """Return bool on if the build specified is enabled in the project.yaml.""" + """Returns True on if the build specified is enabled in the project.yaml.""" + + if os.getenv('SANITIZER') == 'coverage': + # This assumes we only do coverage builds with libFuzzer on x86_64. + return should_build_coverage(project_yaml) def is_enabled(env_var, yaml_name, defaults): """Is the value of |env_var| enabled in |project_yaml| (in the |yaml_name| @@ -115,18 +141,10 @@ def build_project(project): engine = os.getenv('ENGINE') sanitizer = os.getenv('SANITIZER') architecture = os.getenv('ARCHITECTURE') - language = project_yaml.get('language') - - if (sanitizer == 'coverage' and - language not in LANGUAGES_WITH_COVERAGE_SUPPORT): - print(('Project "{project}" is written in "{language}", ' - 'coverage is not supported yet.').format(project=project, - language=language)) - return - if sanitizer != 'coverage' and not should_build(project_yaml): + if not should_build(project_yaml): print(('Specified build: engine: {0}, sanitizer: {1}, architecture: {2} ' - 'not enabled for this project: {3}. skipping build.').format( + 'not enabled for this project: {3}. Skipping build.').format( engine, sanitizer, architecture, project)) return diff --git a/infra/ci/build_test.py b/infra/ci/build_test.py new file mode 100644 index 00000000..ef2d3a80 --- /dev/null +++ b/infra/ci/build_test.py @@ -0,0 +1,93 @@ +# 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 +# +# http://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. +# +################################################################################ +"""Tests for build.py""" + +import os +import unittest +from unittest import mock + +from ci import build + + +def patch_environ(testcase_obj): + """Patch environment.""" + env = {} + patcher = mock.patch.dict(os.environ, env) + testcase_obj.addCleanup(patcher.stop) + patcher.start() + + +def _set_coverage_build(): + """Set the right environment variables for a coverage build.""" + os.environ['SANITIZER'] = 'coverage' + os.environ['ENGINE'] = 'libfuzzer' + os.environ['ARCHITECTURE'] = 'x86_64' + + +class TestShouldBuild(unittest.TestCase): + """Tests that should_build() works as intended.""" + + def setUp(self): + patch_environ(self) + + def test_none_engine_coverage_build(self): + """Tests that should_build returns False for a coverage build of a + project that specifies 'none' for fuzzing_engines.""" + _set_coverage_build() + project_yaml = { + 'language': 'c++', + 'fuzzing_engines': ['none'], + 'sanitizers': ['address'] + } + self.assertFalse(build.should_build(project_yaml)) + + def test_unspecified_engines_coverage_build(self): + """Tests that should_build returns True for a coverage build of a + project that doesn't specify fuzzing_engines.""" + _set_coverage_build() + project_yaml = {'language': 'c++'} + self.assertTrue(build.should_build(project_yaml)) + + def test_libfuzzer_coverage_build(self): + """Tests that should_build returns True for coverage build of a project + specifying 'libfuzzer' and for fuzzing_engines.""" + _set_coverage_build() + project_yaml = { + 'language': 'c++', + 'fuzzing_engines': ['libfuzzer'], + 'sanitizers': ['address'] + } + self.assertTrue(build.should_build(project_yaml)) + + def test_go_coverage_build(self): + """Tests that should_build returns False for coverage build of a project + specifying 'libfuzzer' and for fuzzing_engines.""" + _set_coverage_build() + project_yaml = {'language': 'go'} + self.assertFalse(build.should_build(project_yaml)) + + def test_engine_project_none_build(self): + """Tests that should_build returns False for an engine: 'none' build when + the project doesn't specify engines.""" + os.environ['SANITIZER'] = 'address' + os.environ['ENGINE'] = 'none' + os.environ['ARCHITECTURE'] = 'x86_64' + project_yaml = { + 'language': 'c++', + 'fuzzing_engines': ['libfuzzer'], + 'sanitizers': ['address'] + } + self.assertFalse(build.should_build(project_yaml)) |