sanitycheck: native: Add option to enable UBSAN
Add option for native platform to enable undefined behaviour sanitizer. Signed-off-by: Christian Taedcke <christian.taedcke@lemonbeat.com>
This commit is contained in:
parent
cb7835d18f
commit
3dbe9f2960
3 changed files with 37 additions and 13 deletions
|
@ -337,6 +337,7 @@ class BinaryHandler(Handler):
|
||||||
self.valgrind = False
|
self.valgrind = False
|
||||||
self.lsan = False
|
self.lsan = False
|
||||||
self.asan = False
|
self.asan = False
|
||||||
|
self.ubsan = False
|
||||||
self.coverage = False
|
self.coverage = False
|
||||||
|
|
||||||
def try_kill_process_by_pid(self):
|
def try_kill_process_by_pid(self):
|
||||||
|
@ -414,6 +415,10 @@ class BinaryHandler(Handler):
|
||||||
if not self.lsan:
|
if not self.lsan:
|
||||||
env["ASAN_OPTIONS"] += "detect_leaks=0"
|
env["ASAN_OPTIONS"] += "detect_leaks=0"
|
||||||
|
|
||||||
|
if self.ubsan:
|
||||||
|
env["UBSAN_OPTIONS"] = "log_path=stdout:halt_on_error=1:" + \
|
||||||
|
env.get("UBSAN_OPTIONS", "")
|
||||||
|
|
||||||
with subprocess.Popen(command, stdout=subprocess.PIPE,
|
with subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE, cwd=self.build_dir, env=env) as proc:
|
stderr=subprocess.PIPE, cwd=self.build_dir, env=env) as proc:
|
||||||
logger.debug("Spawning BinaryHandler Thread for %s" % self.name)
|
logger.debug("Spawning BinaryHandler Thread for %s" % self.name)
|
||||||
|
@ -1623,7 +1628,7 @@ class TestInstance(DisablePyTestCollectionMixin):
|
||||||
self.run = not self.build_only
|
self.run = not self.build_only
|
||||||
return
|
return
|
||||||
|
|
||||||
def create_overlay(self, platform, enable_asan=False, enable_coverage=False, coverage_platform=[]):
|
def create_overlay(self, platform, enable_asan=False, enable_ubsan=False, enable_coverage=False, coverage_platform=[]):
|
||||||
# Create this in a "sanitycheck/" subdirectory otherwise this
|
# Create this in a "sanitycheck/" subdirectory otherwise this
|
||||||
# will pass this overlay to kconfig.py *twice* and kconfig.cmake
|
# will pass this overlay to kconfig.py *twice* and kconfig.cmake
|
||||||
# will silently give that second time precedence over any
|
# will silently give that second time precedence over any
|
||||||
|
@ -1647,6 +1652,10 @@ class TestInstance(DisablePyTestCollectionMixin):
|
||||||
if platform.type == "native":
|
if platform.type == "native":
|
||||||
content = content + "\nCONFIG_ASAN=y"
|
content = content + "\nCONFIG_ASAN=y"
|
||||||
|
|
||||||
|
if enable_ubsan:
|
||||||
|
if platform.type == "native":
|
||||||
|
content = content + "\nCONFIG_UBSAN=y"
|
||||||
|
|
||||||
f.write(content)
|
f.write(content)
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
@ -1896,6 +1905,7 @@ class ProjectBuilder(FilterBuilder):
|
||||||
|
|
||||||
self.lsan = kwargs.get('lsan', False)
|
self.lsan = kwargs.get('lsan', False)
|
||||||
self.asan = kwargs.get('asan', False)
|
self.asan = kwargs.get('asan', False)
|
||||||
|
self.ubsan = kwargs.get('ubsan', False)
|
||||||
self.valgrind = kwargs.get('valgrind', False)
|
self.valgrind = kwargs.get('valgrind', False)
|
||||||
self.extra_args = kwargs.get('extra_args', [])
|
self.extra_args = kwargs.get('extra_args', [])
|
||||||
self.device_testing = kwargs.get('device_testing', False)
|
self.device_testing = kwargs.get('device_testing', False)
|
||||||
|
@ -1962,6 +1972,7 @@ class ProjectBuilder(FilterBuilder):
|
||||||
handler.asan = self.asan
|
handler.asan = self.asan
|
||||||
handler.valgrind = self.valgrind
|
handler.valgrind = self.valgrind
|
||||||
handler.lsan = self.lsan
|
handler.lsan = self.lsan
|
||||||
|
handler.ubsan = self.ubsan
|
||||||
handler.coverage = self.coverage
|
handler.coverage = self.coverage
|
||||||
|
|
||||||
handler.binary = os.path.join(instance.build_dir, "zephyr", "zephyr.exe")
|
handler.binary = os.path.join(instance.build_dir, "zephyr", "zephyr.exe")
|
||||||
|
@ -2168,7 +2179,7 @@ class ProjectBuilder(FilterBuilder):
|
||||||
overlays = extract_overlays(args)
|
overlays = extract_overlays(args)
|
||||||
|
|
||||||
if (self.testcase.extra_configs or self.coverage or
|
if (self.testcase.extra_configs or self.coverage or
|
||||||
self.asan):
|
self.asan or self.ubsan):
|
||||||
overlays.append(os.path.join(instance.build_dir,
|
overlays.append(os.path.join(instance.build_dir,
|
||||||
"sanitycheck", "testcase_extra.conf"))
|
"sanitycheck", "testcase_extra.conf"))
|
||||||
|
|
||||||
|
@ -2274,6 +2285,7 @@ class TestSuite(DisablePyTestCollectionMixin):
|
||||||
self.device_testing = False
|
self.device_testing = False
|
||||||
self.fixtures = []
|
self.fixtures = []
|
||||||
self.enable_coverage = False
|
self.enable_coverage = False
|
||||||
|
self.enable_ubsan = False
|
||||||
self.enable_lsan = False
|
self.enable_lsan = False
|
||||||
self.enable_asan = False
|
self.enable_asan = False
|
||||||
self.enable_valgrind = False
|
self.enable_valgrind = False
|
||||||
|
@ -2620,7 +2632,7 @@ class TestSuite(DisablePyTestCollectionMixin):
|
||||||
self.device_testing,
|
self.device_testing,
|
||||||
self.fixtures
|
self.fixtures
|
||||||
)
|
)
|
||||||
instance.create_overlay(platform, self.enable_asan, self.enable_coverage, self.coverage_platform)
|
instance.create_overlay(platform, self.enable_asan, self.enable_ubsan, self.enable_coverage, self.coverage_platform)
|
||||||
instance_list.append(instance)
|
instance_list.append(instance)
|
||||||
self.add_instances(instance_list)
|
self.add_instances(instance_list)
|
||||||
|
|
||||||
|
@ -2815,7 +2827,7 @@ class TestSuite(DisablePyTestCollectionMixin):
|
||||||
self.add_instances(instance_list)
|
self.add_instances(instance_list)
|
||||||
|
|
||||||
for _, case in self.instances.items():
|
for _, case in self.instances.items():
|
||||||
case.create_overlay(case.platform, self.enable_asan, self.enable_coverage, self.coverage_platform)
|
case.create_overlay(case.platform, self.enable_asan, self.enable_ubsan, self.enable_coverage, self.coverage_platform)
|
||||||
|
|
||||||
self.discards = discards
|
self.discards = discards
|
||||||
self.selected_platforms = set(p.platform.name for p in self.instances.values())
|
self.selected_platforms = set(p.platform.name for p in self.instances.values())
|
||||||
|
@ -2876,6 +2888,7 @@ class TestSuite(DisablePyTestCollectionMixin):
|
||||||
test,
|
test,
|
||||||
lsan=self.enable_lsan,
|
lsan=self.enable_lsan,
|
||||||
asan=self.enable_asan,
|
asan=self.enable_asan,
|
||||||
|
ubsan=self.enable_ubsan,
|
||||||
coverage=self.enable_coverage,
|
coverage=self.enable_coverage,
|
||||||
extra_args=self.extra_args,
|
extra_args=self.extra_args,
|
||||||
device_testing=self.device_testing,
|
device_testing=self.device_testing,
|
||||||
|
|
|
@ -641,6 +641,14 @@ structure in the main Zephyr tree: boards/<arch>/<board_name>/""")
|
||||||
configuration and when --enable-asan is given.
|
configuration and when --enable-asan is given.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--enable-ubsan", action="store_true",
|
||||||
|
help="""Enable undefined behavior sanitizer to check for undefined
|
||||||
|
behaviour during program execution. It uses an optional runtime library
|
||||||
|
to provide better error diagnostics. This option only works with host
|
||||||
|
binaries such as those generated for the native_posix configuration.
|
||||||
|
""")
|
||||||
|
|
||||||
parser.add_argument("--enable-coverage", action="store_true",
|
parser.add_argument("--enable-coverage", action="store_true",
|
||||||
help="Enable code coverage using gcov.")
|
help="Enable code coverage using gcov.")
|
||||||
|
|
||||||
|
@ -777,6 +785,7 @@ def main():
|
||||||
suite.fixtures = options.fixture
|
suite.fixtures = options.fixture
|
||||||
suite.enable_asan = options.enable_asan
|
suite.enable_asan = options.enable_asan
|
||||||
suite.enable_lsan = options.enable_lsan
|
suite.enable_lsan = options.enable_lsan
|
||||||
|
suite.enable_ubsan = options.enable_ubsan
|
||||||
suite.enable_coverage = options.enable_coverage
|
suite.enable_coverage = options.enable_coverage
|
||||||
suite.enable_valgrind = options.enable_valgrind
|
suite.enable_valgrind = options.enable_valgrind
|
||||||
suite.coverage_platform = options.coverage_platform
|
suite.coverage_platform = options.coverage_platform
|
||||||
|
|
|
@ -53,16 +53,18 @@ def test_check_build_or_run(class_testsuite, monkeypatch, all_testcases_dict, pl
|
||||||
assert testinstance.build_only and not testinstance.run
|
assert testinstance.build_only and not testinstance.run
|
||||||
|
|
||||||
TESTDATA_2 = [
|
TESTDATA_2 = [
|
||||||
(True, True, ["demo_board_2"], "native", '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y'),
|
(True, True, True, ["demo_board_2"], "native", '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y\nCONFIG_UBSAN=y'),
|
||||||
(False, True, ["demo_board_2"], 'native', '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'),
|
(True, False, True, ["demo_board_2"], "native", '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y'),
|
||||||
(True, True, ["demo_board_2"], 'mcu', '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'),
|
(False, False, True, ["demo_board_2"], 'native', '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'),
|
||||||
(False, False, ["demo_board_2"], 'native', ''),
|
(True, False, True, ["demo_board_2"], 'mcu', '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'),
|
||||||
(False, True, ['demo_board_1'], 'native', ''),
|
(False, False, False, ["demo_board_2"], 'native', ''),
|
||||||
(True, False, ["demo_board_2"], 'native', '\nCONFIG_ASAN=y'),
|
(False, False, True, ['demo_board_1'], 'native', ''),
|
||||||
|
(True, False, False, ["demo_board_2"], 'native', '\nCONFIG_ASAN=y'),
|
||||||
|
(False, True, False, ["demo_board_2"], 'native', '\nCONFIG_UBSAN=y'),
|
||||||
]
|
]
|
||||||
|
|
||||||
@pytest.mark.parametrize("enable_asan, enable_coverage, coverage_platform, platform_type, expected_content", TESTDATA_2)
|
@pytest.mark.parametrize("enable_asan, enable_ubsan, enable_coverage, coverage_platform, platform_type, expected_content", TESTDATA_2)
|
||||||
def test_create_overlay(class_testsuite, all_testcases_dict, platforms_list, enable_asan, enable_coverage, coverage_platform, platform_type, expected_content):
|
def test_create_overlay(class_testsuite, all_testcases_dict, platforms_list, enable_asan, enable_ubsan, enable_coverage, coverage_platform, platform_type, expected_content):
|
||||||
"""Test correct content is written to testcase_extra.conf based on if conditions
|
"""Test correct content is written to testcase_extra.conf based on if conditions
|
||||||
TO DO: Add extra_configs to the input list"""
|
TO DO: Add extra_configs to the input list"""
|
||||||
class_testsuite.testcases = all_testcases_dict
|
class_testsuite.testcases = all_testcases_dict
|
||||||
|
@ -72,7 +74,7 @@ def test_create_overlay(class_testsuite, all_testcases_dict, platforms_list, ena
|
||||||
|
|
||||||
testinstance = TestInstance(testcase, platform, class_testsuite.outdir)
|
testinstance = TestInstance(testcase, platform, class_testsuite.outdir)
|
||||||
platform.type = platform_type
|
platform.type = platform_type
|
||||||
assert testinstance.create_overlay(platform, enable_asan, enable_coverage, coverage_platform) == expected_content
|
assert testinstance.create_overlay(platform, enable_asan, enable_ubsan, enable_coverage, coverage_platform) == expected_content
|
||||||
|
|
||||||
def test_calculate_sizes(class_testsuite, all_testcases_dict, platforms_list):
|
def test_calculate_sizes(class_testsuite, all_testcases_dict, platforms_list):
|
||||||
""" Test Calculate sizes method for zephyr elf"""
|
""" Test Calculate sizes method for zephyr elf"""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue