Skip to content

Commit d9945cc

Browse files
akihikodakistefanhaRH
authored andcommitted
coroutine-ucontext: Save fake stack for pooled coroutine
Coroutine may be pooled even after COROUTINE_TERMINATE if CONFIG_COROUTINE_POOL is enabled and fake stack should be saved in such a case to keep AddressSanitizerUseAfterReturn working. Even worse, I'm seeing stack corruption without fake stack being saved. Signed-off-by: Akihiko Odaki <[email protected]> Reviewed-by: Marc-André Lureau <[email protected]> Signed-off-by: Stefan Hajnoczi <[email protected]> Message-ID: <[email protected]>
1 parent 09be347 commit d9945cc

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

util/coroutine-ucontext.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,11 @@ void finish_switch_fiber(void *fake_stack_save)
119119

120120
/* always_inline is required to avoid TSan runtime fatal errors. */
121121
static inline __attribute__((always_inline))
122-
void start_switch_fiber_asan(CoroutineAction action, void **fake_stack_save,
122+
void start_switch_fiber_asan(void **fake_stack_save,
123123
const void *bottom, size_t size)
124124
{
125125
#ifdef CONFIG_ASAN
126-
__sanitizer_start_switch_fiber(
127-
action == COROUTINE_TERMINATE ? NULL : fake_stack_save,
128-
bottom, size);
126+
__sanitizer_start_switch_fiber(fake_stack_save, bottom, size);
129127
#endif
130128
}
131129

@@ -165,7 +163,7 @@ static void coroutine_trampoline(int i0, int i1)
165163
if (!sigsetjmp(self->env, 0)) {
166164
CoroutineUContext *leaderp = get_ptr_leader();
167165

168-
start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save,
166+
start_switch_fiber_asan(&fake_stack_save,
169167
leaderp->stack, leaderp->stack_size);
170168
start_switch_fiber_tsan(&fake_stack_save, self, true); /* true=caller */
171169
siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
@@ -226,8 +224,7 @@ Coroutine *qemu_coroutine_new(void)
226224

227225
/* swapcontext() in, siglongjmp() back out */
228226
if (!sigsetjmp(old_env, 0)) {
229-
start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, co->stack,
230-
co->stack_size);
227+
start_switch_fiber_asan(&fake_stack_save, co->stack, co->stack_size);
231228
start_switch_fiber_tsan(&fake_stack_save,
232229
co, false); /* false=not caller */
233230

@@ -269,10 +266,28 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co)
269266
#endif
270267
#endif
271268

269+
#if defined(CONFIG_ASAN) && defined(CONFIG_COROUTINE_POOL)
270+
static void coroutine_fn terminate_asan(void *opaque)
271+
{
272+
CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, opaque);
273+
274+
set_current(opaque);
275+
start_switch_fiber_asan(NULL, to->stack, to->stack_size);
276+
G_STATIC_ASSERT(!IS_ENABLED(CONFIG_TSAN));
277+
siglongjmp(to->env, COROUTINE_ENTER);
278+
}
279+
#endif
280+
272281
void qemu_coroutine_delete(Coroutine *co_)
273282
{
274283
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
275284

285+
#if defined(CONFIG_ASAN) && defined(CONFIG_COROUTINE_POOL)
286+
co_->entry_arg = qemu_coroutine_self();
287+
co_->entry = terminate_asan;
288+
qemu_coroutine_switch(co_->entry_arg, co_, COROUTINE_ENTER);
289+
#endif
290+
276291
#ifdef CONFIG_VALGRIND_H
277292
valgrind_stack_deregister(co);
278293
#endif
@@ -305,8 +320,10 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
305320

306321
ret = sigsetjmp(from->env, 0);
307322
if (ret == 0) {
308-
start_switch_fiber_asan(action, &fake_stack_save, to->stack,
309-
to->stack_size);
323+
start_switch_fiber_asan(IS_ENABLED(CONFIG_COROUTINE_POOL) ||
324+
action != COROUTINE_TERMINATE ?
325+
&fake_stack_save : NULL,
326+
to->stack, to->stack_size);
310327
start_switch_fiber_tsan(&fake_stack_save,
311328
to, false); /* false=not caller */
312329
siglongjmp(to->env, action);

0 commit comments

Comments
 (0)