summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@chromium.org>2018-06-21 08:39:30 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-06-28 07:06:46 -0700
commit6c6888037c8d82228b480eeba0eaf1b0aa83e9f8 (patch)
tree5ccd44915959fa98d811bb4e53f71b295ec41317
parentdcfbe0be69d3445edfd45fb036bfae2581b6fdd5 (diff)
downloadchrome-ec-6c6888037c8d82228b480eeba0eaf1b0aa83e9f8.tar.gz
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 <drinkcat@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1109661 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--Makefile.toolchain11
-rw-r--r--include/common.h17
-rw-r--r--include/console.h3
-rw-r--r--include/extension.h9
-rw-r--r--include/hooks.h6
-rw-r--r--include/host_command.h7
-rw-r--r--include/mkbp_event.h3
-rw-r--r--include/test_util.h3
-rwxr-xr-xutil/run_host_test12
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 {
&params->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, &params->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: