mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-24 05:21:20 -08:00
threading: safer handling of overflows in frame and binding stacks
Previously, the dummy tag was written behind the stack
boundary. Also added race condition protection to non-inlined
ecl_bds_bind/push. The memory barriers have been reworked,
too. AO_store_full has been replaced by AO_full_nop. This is
sufficient to insert the required memory barrier instructions and
is implemented in a simpler way by libatomic_ops in some cases.
This commit is contained in:
parent
fc29c08d93
commit
bad90d0f65
3 changed files with 53 additions and 18 deletions
|
|
@ -320,8 +320,16 @@ ecl_bds_bind(cl_env_ptr env, cl_object s, cl_object v)
|
|||
index = invalid_or_too_large_binding_index(env,s);
|
||||
}
|
||||
location = env->thread_local_bindings + index;
|
||||
slot = ++env->bds_top;
|
||||
if (slot >= env->bds_limit) slot = ecl_bds_overflow();
|
||||
slot = env->bds_top+1;
|
||||
if (slot >= env->bds_limit){
|
||||
slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
}
|
||||
AO_nop_full();
|
||||
ecl_disable_interrupts_env(env);
|
||||
slot->symbol = s;
|
||||
slot->value = *location;
|
||||
|
|
@ -349,8 +357,16 @@ ecl_bds_push(cl_env_ptr env, cl_object s)
|
|||
index = invalid_or_too_large_binding_index(env,s);
|
||||
}
|
||||
location = env->thread_local_bindings + index;
|
||||
slot = ++env->bds_top;
|
||||
if (slot >= env->bds_limit) slot = ecl_bds_overflow();
|
||||
slot = env->bds_top+1;
|
||||
if (slot >= env->bds_limit){
|
||||
slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
}
|
||||
AO_nop_full();
|
||||
ecl_disable_interrupts_env(env);
|
||||
slot->symbol = s;
|
||||
slot->value = *location;
|
||||
|
|
@ -544,15 +560,20 @@ _ecl_frs_push(register cl_env_ptr env, register cl_object val)
|
|||
{
|
||||
/* We store a dummy tag first, to make sure that it is safe to
|
||||
* interrupt this method with a call to ecl_unwind. Otherwise, a
|
||||
* stray ECL_PROTECT_TAG will lead to segfaults. AO_store_full is
|
||||
* stray ECL_PROTECT_TAG will lead to segfaults. AO_nop_full is
|
||||
* needed to ensure that the CPU doesn't reorder the memory
|
||||
* stores. */
|
||||
AO_store_full((AO_t*)&(env->frs_top+1)->frs_val,(AO_t)ECL_DUMMY_TAG);
|
||||
ecl_frame_ptr output = ++env->frs_top;
|
||||
if (output >= env->frs_limit) {
|
||||
ecl_frame_ptr output = env->frs_top+1;
|
||||
if (output >= env->frs_limit){
|
||||
frs_overflow();
|
||||
output = env->frs_top;
|
||||
output->frs_val = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
output->frs_val = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->frs_top;
|
||||
}
|
||||
AO_nop_full();
|
||||
output->frs_bds_top_index = env->bds_top - env->bds_org;
|
||||
output->frs_ihs = env->ihs_top;
|
||||
output->frs_sp = ECL_STACK_INDEX(env);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#else
|
||||
# define AO_load(x) (x)
|
||||
# define AO_store(x,y) ((x)=(y))
|
||||
# define AO_store_full(x,y) ((x)=(y))
|
||||
# define AO_nop_full(x,y)
|
||||
#endif
|
||||
|
||||
#endif /* ECL_ATOMIC_OPS_H */
|
||||
|
|
|
|||
|
|
@ -81,12 +81,19 @@ static inline void ecl_bds_bind_inl(cl_env_ptr env, cl_object s, cl_object v)
|
|||
ecl_bds_bind(env,s,v);
|
||||
} else {
|
||||
location = env->thread_local_bindings + index;
|
||||
/* First, we push a dummy symbol in the stack to
|
||||
* prevent segfaults when we are interrupted with a
|
||||
* call to ecl_bds_unwind. */
|
||||
AO_store_full((AO_t*)&(env->bds_top+1)->symbol,(AO_t)ECL_DUMMY_TAG);
|
||||
slot = ++env->bds_top;
|
||||
if (slot >= env->bds_limit) slot = ecl_bds_overflow();
|
||||
slot = env->bds_top+1;
|
||||
if (slot >= env->bds_limit){
|
||||
slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
/* First, we push a dummy symbol in the stack to
|
||||
* prevent segfaults when we are interrupted with a
|
||||
* call to ecl_bds_unwind. */
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
}
|
||||
AO_nop_full();
|
||||
/* Then we disable interrupts to ensure that
|
||||
* ecl_bds_unwind doesn't overwrite the symbol with
|
||||
* some random value. */
|
||||
|
|
@ -117,9 +124,16 @@ static inline void ecl_bds_push_inl(cl_env_ptr env, cl_object s)
|
|||
ecl_bds_push(env, s);
|
||||
} else {
|
||||
location = env->thread_local_bindings + index;
|
||||
AO_store_full((AO_t*)&(env->bds_top+1)->symbol,(AO_t)ECL_DUMMY_TAG);
|
||||
slot = ++env->bds_top;
|
||||
if (slot >= env->bds_limit) slot = ecl_bds_overflow();
|
||||
slot = env->bds_top+1;
|
||||
if (slot >= env->bds_limit){
|
||||
slot = ecl_bds_overflow();
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
} else {
|
||||
slot->symbol = ECL_DUMMY_TAG;
|
||||
AO_nop_full();
|
||||
++env->bds_top;
|
||||
}
|
||||
AO_nop_full();
|
||||
ecl_disable_interrupts_env(env);
|
||||
slot->symbol = s;
|
||||
slot->value = *location;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue