vlib: address sanitizer support for stack switch, enable clang
Type: improvement Change-Id: I81df4b61d1f0b8c1df77c1ee9bebcb491e155b69 Signed-off-by: Damjan Marion <damarion@cisco.com>
This commit is contained in:

committed by
Benoît Ganne

parent
173484fe3a
commit
cea46522e7
@ -6,7 +6,7 @@ Google Sanitizers
|
||||
|
||||
VPP is instrumented to support `Google Sanitizers <https://github.com/google/sanitizers>`_.
|
||||
As of today, only `AddressSanitizer <https://github.com/google/sanitizers/wiki/AddressSanitizer>`_
|
||||
is supported, only for GCC and only for the heap.
|
||||
is supported, both for GCC and clang.
|
||||
|
||||
AddressSanitizer
|
||||
================
|
||||
@ -20,19 +20,19 @@ build option, so all VPP targets should be supported. For example:
|
||||
.. code-block:: console
|
||||
|
||||
# build a debug image with ASan support:
|
||||
$ make rebuild VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
|
||||
$ make rebuild VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON
|
||||
....
|
||||
|
||||
# build a release image with ASan support:
|
||||
$ make rebuild-release VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
|
||||
$ make rebuild-release VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON
|
||||
....
|
||||
|
||||
# build packages in debug mode with ASan support:
|
||||
$ make pkg-deb-debug VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
|
||||
$ make pkg-deb-debug VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON
|
||||
....
|
||||
|
||||
# run GBP plugin tests in debug mode with ASan
|
||||
$ make test-debug TEST=test_gbp VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
|
||||
$ make test-debug TEST=test_gbp VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON
|
||||
....
|
||||
|
||||
Once VPP has been built with ASan support you can use it as usual including
|
||||
|
@ -117,7 +117,7 @@ set(VPP_SANITIZE_ADDR_OPTIONS
|
||||
)
|
||||
|
||||
if (VPP_ENABLE_SANITIZE_ADDR)
|
||||
set(CMAKE_C_FLAGS "-fsanitize=address --param asan-stack=0 -DCLIB_SANITIZE_ADDR ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "-fsanitize=address -DCLIB_SANITIZE_ADDR ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=address ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-fsanitize=address ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
endif (VPP_ENABLE_SANITIZE_ADDR)
|
||||
|
@ -1496,6 +1496,8 @@ vlib_process_bootstrap (uword _a)
|
||||
|
||||
vm = a->vm;
|
||||
p = a->process;
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
|
||||
f = a->frame;
|
||||
node = &p->node_runtime;
|
||||
|
||||
@ -1503,6 +1505,7 @@ vlib_process_bootstrap (uword _a)
|
||||
|
||||
ASSERT (vlib_process_stack_is_valid (p));
|
||||
|
||||
vlib_process_start_switch_stack (vm, 0);
|
||||
clib_longjmp (&p->return_longjmp, n);
|
||||
|
||||
return n;
|
||||
@ -1521,14 +1524,19 @@ vlib_process_startup (vlib_main_t * vm, vlib_process_t * p, vlib_frame_t * f)
|
||||
|
||||
r = clib_setjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_RETURN);
|
||||
if (r == VLIB_PROCESS_RETURN_LONGJMP_RETURN)
|
||||
r = clib_calljmp (vlib_process_bootstrap, pointer_to_uword (&a),
|
||||
(void *) p->stack + (1 << p->log2_n_stack_bytes));
|
||||
{
|
||||
vlib_process_start_switch_stack (vm, p);
|
||||
r = clib_calljmp (vlib_process_bootstrap, pointer_to_uword (&a),
|
||||
(void *) p->stack + (1 << p->log2_n_stack_bytes));
|
||||
}
|
||||
else
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static_always_inline uword
|
||||
vlib_process_resume (vlib_process_t * p)
|
||||
vlib_process_resume (vlib_main_t * vm, vlib_process_t * p)
|
||||
{
|
||||
uword r;
|
||||
p->flags &= ~(VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
|
||||
@ -1536,7 +1544,12 @@ vlib_process_resume (vlib_process_t * p)
|
||||
| VLIB_PROCESS_RESUME_PENDING);
|
||||
r = clib_setjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_RETURN);
|
||||
if (r == VLIB_PROCESS_RETURN_LONGJMP_RETURN)
|
||||
clib_longjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_RESUME);
|
||||
{
|
||||
vlib_process_start_switch_stack (vm, p);
|
||||
clib_longjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_RESUME);
|
||||
}
|
||||
else
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1655,7 +1668,7 @@ dispatch_suspended_process (vlib_main_t * vm,
|
||||
/* Save away current process for suspend. */
|
||||
nm->current_process_index = node->runtime_index;
|
||||
|
||||
n_vectors = vlib_process_resume (p);
|
||||
n_vectors = vlib_process_resume (vm, p);
|
||||
t = clib_cpu_time_now ();
|
||||
|
||||
nm->current_process_index = ~0;
|
||||
|
@ -280,6 +280,10 @@ typedef struct vlib_main_t
|
||||
u32 buffer_alloc_success_seed;
|
||||
f64 buffer_alloc_success_rate;
|
||||
|
||||
#ifdef CLIB_SANITIZE_ADDR
|
||||
/* address sanitizer stack save */
|
||||
void *asan_stack_save;
|
||||
#endif
|
||||
} vlib_main_t;
|
||||
|
||||
/* Global main structure. */
|
||||
|
@ -48,6 +48,32 @@
|
||||
#include <vppinfra/fifo.h>
|
||||
#include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
|
||||
|
||||
#ifdef CLIB_SANITIZE_ADDR
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#endif
|
||||
|
||||
static_always_inline void
|
||||
vlib_process_start_switch_stack (vlib_main_t * vm, vlib_process_t * p)
|
||||
{
|
||||
#ifdef CLIB_SANITIZE_ADDR
|
||||
void *stack = p ? (void *) p->stack : vlib_thread_stacks[vm->thread_index];
|
||||
u32 stack_bytes = p ? p->log2_n_stack_bytes : VLIB_THREAD_STACK_SIZE;
|
||||
__sanitizer_start_switch_fiber (&vm->asan_stack_save, stack, stack_bytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
static_always_inline void
|
||||
vlib_process_finish_switch_stack (vlib_main_t * vm)
|
||||
{
|
||||
#ifdef CLIB_SANITIZE_ADDR
|
||||
const void *bottom_old;
|
||||
size_t size_old;
|
||||
|
||||
__sanitizer_finish_switch_fiber (&vm->asan_stack_save, &bottom_old,
|
||||
&size_old);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief Get vlib node by index.
|
||||
@warning This function will ASSERT if @c i is out of range.
|
||||
@param vm vlib_main_t pointer, varies by thread
|
||||
@ -456,8 +482,11 @@ vlib_process_suspend (vlib_main_t * vm, f64 dt)
|
||||
{
|
||||
/* expiration time in 10us ticks */
|
||||
p->resume_clock_interval = dt * 1e5;
|
||||
vlib_process_start_switch_stack (vm, 0);
|
||||
clib_longjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
|
||||
}
|
||||
else
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -625,8 +654,13 @@ vlib_process_wait_for_event (vlib_main_t * vm)
|
||||
r =
|
||||
clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
|
||||
if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
|
||||
clib_longjmp (&p->return_longjmp,
|
||||
VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
|
||||
{
|
||||
vlib_process_start_switch_stack (vm, 0);
|
||||
clib_longjmp (&p->return_longjmp,
|
||||
VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
|
||||
}
|
||||
else
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
}
|
||||
|
||||
return p->non_empty_event_type_bitmap;
|
||||
@ -649,8 +683,13 @@ vlib_process_wait_for_one_time_event (vlib_main_t * vm,
|
||||
r =
|
||||
clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
|
||||
if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
|
||||
clib_longjmp (&p->return_longjmp,
|
||||
VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
|
||||
{
|
||||
vlib_process_start_switch_stack (vm, 0);
|
||||
clib_longjmp (&p->return_longjmp,
|
||||
VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
|
||||
}
|
||||
else
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
}
|
||||
|
||||
return vlib_process_get_events_helper (p, with_type_index, data_vector);
|
||||
@ -673,8 +712,13 @@ vlib_process_wait_for_event_with_type (vlib_main_t * vm,
|
||||
r =
|
||||
clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
|
||||
if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
|
||||
clib_longjmp (&p->return_longjmp,
|
||||
VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
|
||||
{
|
||||
vlib_process_start_switch_stack (vm, 0);
|
||||
clib_longjmp (&p->return_longjmp,
|
||||
VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
|
||||
}
|
||||
else
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
|
||||
/* See if unknown event type has been signaled now. */
|
||||
if (!h)
|
||||
@ -715,8 +759,11 @@ vlib_process_wait_for_event_or_clock (vlib_main_t * vm, f64 dt)
|
||||
if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
|
||||
{
|
||||
p->resume_clock_interval = dt * 1e5;
|
||||
vlib_process_start_switch_stack (vm, 0);
|
||||
clib_longjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
|
||||
}
|
||||
else
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
|
||||
/* Return amount of time still left to sleep.
|
||||
If <= 0 then we've been waken up by the clock (and not an event). */
|
||||
|
@ -581,6 +581,7 @@ vlib_worker_thread_bootstrap_fn (void *arg)
|
||||
|
||||
__os_thread_index = w - vlib_worker_threads;
|
||||
|
||||
vlib_process_start_switch_stack (vlib_mains[__os_thread_index], 0);
|
||||
rv = (void *) clib_calljmp
|
||||
((uword (*)(uword)) w->thread_function,
|
||||
(uword) arg, w->thread_stack + VLIB_THREAD_STACK_SIZE);
|
||||
@ -1777,6 +1778,8 @@ vlib_worker_thread_fn (void *arg)
|
||||
vlib_main_t *vm = vlib_get_main ();
|
||||
clib_error_t *e;
|
||||
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
|
||||
ASSERT (vm->thread_index == vlib_get_thread_index ());
|
||||
|
||||
vlib_worker_thread_init (w);
|
||||
|
@ -654,6 +654,8 @@ thread0 (uword arg)
|
||||
unformat_input_t input;
|
||||
int i;
|
||||
|
||||
vlib_process_finish_switch_stack (vm);
|
||||
|
||||
unformat_init_command_line (&input, (char **) vm->argv);
|
||||
i = vlib_main (vm, &input);
|
||||
unformat_free (&input);
|
||||
@ -727,6 +729,7 @@ vlib_unix_main (int argc, char *argv[])
|
||||
__os_thread_index = 0;
|
||||
vm->thread_index = 0;
|
||||
|
||||
vlib_process_start_switch_stack (vm, 0);
|
||||
i = clib_calljmp (thread0, (uword) vm,
|
||||
(void *) (vlib_thread_stacks[0] +
|
||||
VLIB_THREAD_STACK_SIZE));
|
||||
|
@ -122,6 +122,7 @@ u8 *vlib_get_vat_plugin_path (void);
|
||||
|
||||
#define VLIB_PLUGIN_REGISTER() \
|
||||
vlib_plugin_registration_t vlib_plugin_registration \
|
||||
CLIB_NOSANITIZE_ADDR \
|
||||
__attribute__((__section__(".vlib_plugin_registration")))
|
||||
|
||||
/* Call a plugin init function: used for init function dependencies. */
|
||||
|
Reference in New Issue
Block a user