From 6c6888037c8d82228b480eeba0eaf1b0aa83e9f8 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 21 Jun 2018 08:39:30 +0800 Subject: ec: Make it possible to run tests with AddressSanitizer enabled Automatically use CC=clang if TEST_ASAN is specified. Also, add a __no_sanitize_address attribute macro to prevent ASan from adding guards around host_command, mkbp_event, and hook "arrays" that are generated at link-time. Also, set ASAN_OPTIONS env variable in run_host_test. BRANCH=none BUG=chromium:854924 TEST=make TEST_ASAN=y runtests -j Change-Id: Iaf0ec405022760d757a8a9d62a5022460d1b16e1 Signed-off-by: Nicolas Boichat Reviewed-on: https://chromium-review.googlesource.com/1109661 Reviewed-by: Vincent Palatin --- Makefile.toolchain | 11 +++++++++-- include/common.h | 17 +++++++++++++++++ include/console.h | 3 ++- include/extension.h | 9 ++++++--- include/hooks.h | 6 ++++-- include/host_command.h | 7 ++++--- include/mkbp_event.h | 3 ++- include/test_util.h | 3 ++- util/run_host_test | 12 +++++++++--- 9 files changed, 55 insertions(+), 16 deletions(-) diff --git a/Makefile.toolchain b/Makefile.toolchain index e0f796fae6..c0ecdc91ca 100644 --- a/Makefile.toolchain +++ b/Makefile.toolchain @@ -15,6 +15,11 @@ ifeq ($(make_version_ok),) $(error ERROR: GNU make version $(min_make_version) or higher required.) endif +# Default to clang if TEST_ASAN is enabled +ifneq ($(TEST_ASAN),) +CC=clang +endif + # Extract cc-name cc-name:=$(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc) @@ -54,7 +59,8 @@ CFLAGS_TEST=$(if $(TEST_BUILD),-DTEST_BUILD \ $(if $(CTS_MODULE), $(CFLAGS_CTS)) \ $(if $(EMU_BUILD),-DEMU_BUILD) \ $(if $($(PROJECT)-scale),-DTEST_TIME_SCALE=$($(PROJECT)-scale)) \ - -DTEST_$(PROJECT) -DTEST_$(UC_PROJECT) + -DTEST_$(PROJECT) -DTEST_$(UC_PROJECT) \ + $(if $(TEST_ASAN),-fsanitize=address) CFLAGS_COVERAGE=$(if $(TEST_COVERAGE),-fprofile-arcs -ftest-coverage \ -DTEST_COVERAGE,) CFLAGS_DEFINE=-DOUTDIR=$(out)/$(BLD) -DCHIP=$(CHIP) -DBOARD_TASKFILE=$(_tsk_lst_file) \ @@ -101,7 +107,8 @@ LDFLAGS=-nostdlib -g -Wl,-X -Wl,--gc-sections -Wl,--build-id=none \ $(LDFLAGS_EXTRA) $(CFLAGS_CPU) BUILD_LDFLAGS=$(LIBFTDI_LDLIBS) HOST_TEST_LDFLAGS=-Wl,-T core/host/host_exe.lds -lrt -pthread -rdynamic -lm\ - $(if $(TEST_COVERAGE),-fprofile-arcs,) + $(if $(TEST_COVERAGE),-fprofile-arcs,) \ + $(if $(TEST_ASAN), -fsanitize=address) # utility function to provide overridable defaults # $1: name of variable to set diff --git a/include/common.h b/include/common.h index 555f91a953..dac0bf2f00 100644 --- a/include/common.h +++ b/include/common.h @@ -96,6 +96,23 @@ #define __bss_slow __attribute__((section(".bss.slow"))) #endif +/* gcc does not support __has_feature */ +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +/* + * Use this to prevent AddressSanitizer from putting guards around some global + * variables (e.g. hook/commands "arrays" that are put together at link time). + */ +#ifndef __no_sanitize_address +#if __has_feature(address_sanitizer) +#define __no_sanitize_address __attribute__((no_sanitize("address"))) +#else +#define __no_sanitize_address +#endif +#endif + /* There isn't really a better place for this */ #define C_TO_K(temp_c) ((temp_c) + 273) #define K_TO_C(temp_c) ((temp_c) - 273) diff --git a/include/console.h b/include/console.h index d8da234a24..57a190226b 100644 --- a/include/console.h +++ b/include/console.h @@ -158,7 +158,8 @@ void console_has_input(void); static const char __con_cmd_label_##NAME[] = #NAME; \ struct size_check##NAME { \ int field[2 * (sizeof(__con_cmd_label_##NAME) < 16) - 1]; }; \ - const struct console_command __keep __con_cmd_##NAME \ + const struct console_command __keep __no_sanitize_address \ + __con_cmd_##NAME \ __attribute__((section(".rodata.cmds." #NAME))) = \ { .name = __con_cmd_label_##NAME, \ .handler = ROUTINE, \ diff --git a/include/extension.h b/include/extension.h index ed7dd70f32..b984c583b0 100644 --- a/include/extension.h +++ b/include/extension.h @@ -74,7 +74,8 @@ struct extension_command { ¶ms->out_size); \ return VENDOR_RC_SUCCESS; \ } \ - const struct extension_command __keep __extension_cmd_##code \ + const struct extension_command __keep __no_sanitize_address \ + __extension_cmd_##code \ __attribute__((section(".rodata.extensioncmds"))) \ = {.command_code = code, .handler = func##_wrap } @@ -86,13 +87,15 @@ struct extension_command { return func(params->code, params->buffer, \ params->in_size, ¶ms->out_size); \ } \ - const struct extension_command __keep __vendor_cmd_##cmd_code \ + const struct extension_command __keep __no_sanitize_address \ + __vendor_cmd_##cmd_code \ __attribute__((section(".rodata.extensioncmds"))) \ = {.command_code = cmd_code, .handler = func##_wrap} /* Vendor command which takes params as struct */ #define DECLARE_VENDOR_COMMAND_P(cmd_code, func) \ - const struct extension_command __keep __vendor_cmd_##cmd_code \ + const struct extension_command __keep __no_sanitize_address \ + __vendor_cmd_##cmd_code \ __attribute__((section(".rodata.extensioncmds"))) \ = {.command_code = cmd_code, .handler = func} diff --git a/include/hooks.h b/include/hooks.h index ee1d2bc475..d998523126 100644 --- a/include/hooks.h +++ b/include/hooks.h @@ -266,7 +266,8 @@ int hook_call_deferred(const struct deferred_data *data, int us); * order in which hooks are called. */ #define DECLARE_HOOK(hooktype, routine, priority) \ - const struct hook_data __keep CONCAT4(__hook_, hooktype, _, routine) \ + const struct hook_data __keep __no_sanitize_address \ + CONCAT4(__hook_, hooktype, _, routine) \ __attribute__((section(".rodata." STRINGIFY(hooktype)))) \ = {routine, priority} @@ -290,7 +291,8 @@ int hook_call_deferred(const struct deferred_data *data, int us); * @param routine Function pointer, with prototype void routine(void) */ #define DECLARE_DEFERRED(routine) \ - const struct deferred_data __keep CONCAT2(routine, _data) \ + const struct deferred_data __keep __no_sanitize_address \ + CONCAT2(routine, _data) \ __attribute__((section(".rodata.deferred"))) \ = {routine} diff --git a/include/host_command.h b/include/host_command.h index 1f9718fa5f..e68b86c96d 100644 --- a/include/host_command.h +++ b/include/host_command.h @@ -248,8 +248,9 @@ void host_packet_receive(struct host_packet *pkt); * Register a host command handler with * commands starting at offset 0x0000 */ -#define DECLARE_HOST_COMMAND(command, routine, version_mask) \ - const struct host_command __keep EXPAND(0x0000, command) \ +#define DECLARE_HOST_COMMAND(command, routine, version_mask) \ + const struct host_command __keep __no_sanitize_address \ + EXPAND(0x0000, command) \ __attribute__((section(".rodata.hcmds."EXPANDSTR(0x0000, command)))) \ = {routine, command, version_mask} @@ -258,7 +259,7 @@ void host_packet_receive(struct host_packet *pkt); * commands starting at offset EC_CMD_BOARD_SPECIFIC_BASE, */ #define DECLARE_PRIVATE_HOST_COMMAND(command, routine, version_mask) \ - const struct host_command __keep \ + const struct host_command __keep __no_sanitize_address \ EXPAND(EC_CMD_BOARD_SPECIFIC_BASE, command) \ __attribute__((section(".rodata.hcmds."\ EXPANDSTR(EC_CMD_BOARD_SPECIFIC_BASE, command)))) \ diff --git a/include/mkbp_event.h b/include/mkbp_event.h index 68e29c0cd4..3764c40d5b 100644 --- a/include/mkbp_event.h +++ b/include/mkbp_event.h @@ -40,7 +40,8 @@ struct mkbp_event_source { }; #define DECLARE_EVENT_SOURCE(type, func) \ - const struct mkbp_event_source __keep __evt_src_##type \ + const struct mkbp_event_source __keep \ + __no_sanitize_address _evt_src_##type \ __attribute__((section(".rodata.evtsrcs"))) \ = {type, func} diff --git a/include/test_util.h b/include/test_util.h index e3aa1d8c27..a1ab956359 100644 --- a/include/test_util.h +++ b/include/test_util.h @@ -236,7 +236,8 @@ struct test_i2c_write_dev { * @param routine Function pointer, with the same prototype as i2c_xfer() */ #define DECLARE_TEST_I2C_XFER(routine) \ - const struct test_i2c_xfer __test_i2c_xfer_##routine \ + const struct test_i2c_xfer __no_sanitize_address \ + __test_i2c_xfer_##routine \ __attribute__((section(".rodata.test_i2c.xfer"))) \ = {routine} diff --git a/util/run_host_test b/util/run_host_test index c0482a7863..395afd4620 100755 --- a/util/run_host_test +++ b/util/run_host_test @@ -5,6 +5,7 @@ # found in the LICENSE file. from cStringIO import StringIO +import os import pexpect import signal import subprocess @@ -34,9 +35,9 @@ class Tee(object): sys.stdout.flush() self._target.flush() -def RunOnce(test_name, log): +def RunOnce(test_name, log, env): child = pexpect.spawn('build/host/{0}/{0}.exe'.format(test_name), - timeout=TIMEOUT) + timeout=TIMEOUT, env=env) child.logfile = log try: return child.expect(EXPECT_LIST) @@ -49,12 +50,17 @@ def RunOnce(test_name, log): child.kill(signal.SIGTERM) child.read() +# ASAN_OPTIONS environment variable is only required when test is built with +# ASan, but is otherwise harmless. +env = dict(os.environ) +env["ASAN_OPTIONS"] = "log_path=stderr" + log = StringIO() tee_log = Tee(log) test_name = sys.argv[1] start_time = time.time() -result_id = RunOnce(test_name, tee_log) +result_id = RunOnce(test_name, tee_log, env) elapsed_time = time.time() - start_time if result_id == RESULT_ID_TIMEOUT: -- cgit v1.2.1