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
================
.. 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
)
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)
vm = a->vm;
p = a->process;
+ vlib_process_finish_switch_stack (vm);
+
f = a->frame;
node = &p->node_runtime;
ASSERT (vlib_process_stack_is_valid (p));
+ vlib_process_start_switch_stack (vm, 0);
clib_longjmp (&p->return_longjmp, n);
return n;
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
| 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;
}
/* 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;
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. */
#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
{
/* 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;
}
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;
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);
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)
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). */
__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);
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);
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);
__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));
#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. */