Skip to content

Commit

Permalink
Enable building PTH with address sanitizer (#1)
Browse files Browse the repository at this point in the history
* Enable building PTH with address sanitizer, on both GCC and Clang.
Clang also has the option to use annotations to enable the sanitizer to switch stacks.

* Adds convenience script for building & installing.
* Adds gitignore file for convenience
* Fix typo in PTH_DEBUG macro when --enable-debug is set
  • Loading branch information
Hnefi authored and neo-apz committed Jan 27, 2020
1 parent ffa31fb commit 58691ee
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 5 deletions.
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
*.o
*.lo
*.la
.libs/
bin/
include/
lib/
man/
share/
test_*
config.log
config.status
libtool
pth_p.h
pth.h
.done-all
.done-test
.gdb*
Makefile
pth-config
pth_acdef.h
pth_acmac.h
tags
8 changes: 8 additions & 0 deletions build_pth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
# USE: This configures/installs pth locally in $HOME/lib and $HOME/include.
# MANDATORY: Set env variables CC and CXX before running this script
# On the parsa cluster, you should use /home/parsacom/tools/gcc-qflex/path/to/bin/gcc and g++
./configure --with-pic --enable-shared --disable-static --prefix=$HOME
make -j
make test
#make install
30 changes: 29 additions & 1 deletion configure
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,7 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-subdir enable local building as subdirectory (default=no)
--enable-debug build for debugging (default=no)
--enable-asan build with address sanitizer (default=no)
--enable-profile build for profiling (default=no)
--enable-optimize build with optimization (default=no)
--enable-shared[=PKGS]
Expand Down Expand Up @@ -2883,6 +2884,34 @@ echo "${ECHO_T}no" >&6
SET_MAKE="MAKE=${MAKE-make}"
fi

# Check whether --enable-asan was requested
if test "${enable_asan+set}" = set; then
echo "$as_me:$LINENO: checking whether compiler supports asan" >&5
echo $ECHO_N "checking whether compiler supports asan... $ECHO_C" >&6
enableval="$enable_asan"
cat >conftest.$ac_ext <<EOF
int main() { return 0; }
EOF
${CC-cc} -c $CFLAGS $CPPFLAGS -fsanitize=address conftest.$ac_ext 1>conftest.out 2>conftest.err
if test $? -ne 0 -o -s conftest.err; then
ac_cv_compiler_option_asan=no
else
ac_cv_compiler_option_asan=yes
fi
rm -f conftest.$ac_ext conftest.out conftest.err

if test ".$ac_cv_compiler_option_asan" = .yes; then
echo "$as_me:$LINENO: result: yes" >&5
echo "${ECHO_T}yes" >&6
CXXFLAGS="$CFLAGS -fsanitize=address"
CFLAGS="$CFLAGS -fsanitize=address"
LDFLAGS="$LDFLAGS -fsanitize=address"
else
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
fi
fi

# Check whether --enable-debug or --disable-debug was given.
if test "${enable_debug+set}" = set; then
enableval="$enable_debug"
Expand Down Expand Up @@ -3020,7 +3049,6 @@ cat >>confdefs.h <<\_ACEOF
#define PTH_DEBUG 1
_ACEOF


else

if test ".$ac_cv_c_compiler_gnu" = ".yes"; then
Expand Down
28 changes: 26 additions & 2 deletions pth_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,14 @@ int pth_init(void)
* function to find the scheduler.
*/
pth_current = pth_sched;
pth_mctx_switch(&pth_main->mctx, &pth_sched->mctx);

/* Msutherl: annotations for Clang api. Nothing happens under the hood if
* support not detected by autoconf.
* */
wrapper_start_fiber_switch(pth_sched->stack,pth_sched->stacksize);
pth_mctx_switch(&pth_main->mctx, &pth_sched->mctx);
wrapper_finish_fiber_switch();
pth_debug5("Finished switch back to pth_init stack 0x%p, size %u, FROM stack 0x%p, size %u",pth_main->stack,pth_main->stacksize,from_stack,from_stacksize);
/* came back, so let's go home... */
pth_debug1("pth_init: leave");
return TRUE;
Expand Down Expand Up @@ -212,6 +218,11 @@ static void pth_spawn_trampoline(void)
{
void *data;

/* Msutherl: Call the finish fiber switch here before jumping into the
* thread's execution function. Prevents all user code from needing to call
* an external sanitizer API. */
wrapper_finish_fiber_switch();

/* just jump into the start routine */
data = (*pth_current->start_func)(pth_current->start_arg);

Expand Down Expand Up @@ -449,7 +460,14 @@ void pth_exit(void *value)
pth_current->join_arg = value;
pth_current->state = PTH_STATE_DEAD;
pth_debug2("pth_exit: switching from thread \"%s\" to scheduler", pth_current->name);

/* Msutherl: annotations for Clang api. Nothing happens under the hood if
* support not detected by autoconf.
*/
wrapper_start_fiber_switch(pth_sched->stack,pth_sched->stacksize);
pth_mctx_switch(&pth_current->mctx, &pth_sched->mctx);
wrapper_finish_fiber_switch();
pth_debug5("Finished switch back to pth_sched stack 0x%p, size %u, FROM stack 0x%p, size %u",pth_sched->stack,pth_sched->stacksize,from_stack,from_stacksize);
}
else {
/*
Expand Down Expand Up @@ -522,9 +540,15 @@ int pth_yield(pth_t to)
"in favour of thread \"%s\"", to->name);
else
pth_debug1("pth_yield: give up control to scheduler");

/* Msutherl: annotations for Clang api. Nothing happens under the hood if
* support not detected by autoconf.
* */
wrapper_start_fiber_switch(pth_sched->stack,pth_sched->stacksize);
pth_mctx_switch(&pth_current->mctx, &pth_sched->mctx);
wrapper_finish_fiber_switch();
pth_debug5("Finished switch back to pth_sched stack 0x%p, size %u, FROM stack 0x%p, size %u",pth_sched->stack,pth_sched->stacksize,from_stack,from_stacksize);
pth_debug1("pth_yield: got back control from scheduler");

pth_debug2("pth_yield: leave to thread \"%s\"", pth_current->name);
return TRUE;
}
Expand Down
48 changes: 46 additions & 2 deletions pth_mctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ struct pth_mctx_st {
int error;
};

/* Msutherl: Parameters to swap out when compiled using address sanitizer
* These params are only used when --enable-asan requested from autoconf. */
void *fake_stack_save;
const void *from_stack;
size_t from_stacksize;

/* Functions that wrap __sanitizer_start_fiber_switch as well as __sanitizer_end_fiber_switch,
* as well as debugging prints if compiled in
*/
void wrapper_start_fiber_switch(const void *new_stack, const size_t new_stacksize);
void wrapper_finish_fiber_switch(void);
/*
** ____ MACHINE STATE SWITCHING ______________________________________
*/
Expand Down Expand Up @@ -119,7 +130,7 @@ struct pth_mctx_st {
* switch from one machine context to another
*/
#define SWITCH_DEBUG_LINE \
"==== THREAD CONTEXT SWITCH ==========================================="
"================== THREAD CONTEXT SWITCH ==========================================="
#ifdef PTH_DEBUG
#define _pth_mctx_switch_debug pth_debug(NULL, 0, 1, SWITCH_DEBUG_LINE);
#else
Expand All @@ -141,6 +152,40 @@ struct pth_mctx_st {

#endif /* cpp */

/* Msutherl: Include sanitizer API */
#if defined(__clang__)
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#include <sanitizer/common_interface_defs.h>
#endif // endif support for Clang ASAN API
#endif // endif has_feature
#endif

/* Msutherl: functions to wrap sanitizer API. They only do anything
* when called by other PTH functions if compiled under ASAN */
intern void wrapper_start_fiber_switch(const void *new_stack, const size_t new_stacksize) {
#if defined(__clang__)
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
pth_debug3("WRAPPER: Switching fiber to new stack 0x%p, size %u",new_stack,new_stacksize);
__sanitizer_start_switch_fiber(NULL,new_stack,new_stacksize);
#endif // endif support for Clang ASAN API
#endif // endif has_feature
#endif
}

intern void wrapper_finish_fiber_switch(void) {
#if defined(__clang__)
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
pth_debug3("WRAPPER: Finished fiber switch FROM stack 0x%p, size %u",from_stack,from_stacksize);
__sanitizer_finish_switch_fiber(NULL,&from_stack,&from_stacksize);
#endif // endif support for Clang ASAN API
#endif // endif has_feature
#endif
}


/*
** ____ MACHINE STATE INITIALIZATION ________________________________
*/
Expand Down Expand Up @@ -558,4 +603,3 @@ pth_mctx_set(pth_mctx_t *mctx, void (*func)(void),
#else
#error "unknown mctx method"
#endif

10 changes: 10 additions & 0 deletions pth_sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ intern void *pth_scheduler(void *dummy)
int sig;
pth_t t;

pth_debug5("Finished switch to pth_scheduler first time 0x%p, size %u, FROM stack 0x%p, size %u",pth_sched->stack,pth_sched->stacksize,from_stack,from_stacksize);

/*
* bootstrapping
*/
Expand Down Expand Up @@ -248,7 +250,15 @@ intern void *pth_scheduler(void *dummy)

/* ** ENTERING THREAD ** - by switching the machine context */
pth_current->dispatches++;

/* Msutherl: annotations for Clang api. Nothing happens under the hood if
* support not detected by autoconf.
*/
wrapper_start_fiber_switch(pth_current->stack,pth_current->stacksize);
pth_mctx_switch(&pth_sched->mctx, &pth_current->mctx);
wrapper_finish_fiber_switch();
pth_debug5("Finished switch back to pth_sched stack 0x%p, size %u, FROM stack 0x%p, size %u",
pth_sched->stack,pth_sched->stacksize,from_stack,from_stacksize);

/* update scheduler times */
pth_time_set(&snapshot, PTH_TIME_NOW);
Expand Down

0 comments on commit 58691ee

Please sign in to comment.