diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index 072f64ae63a6f168e0984d613c259c9100de5851..ada7972cbd6ce77eee84c09f83beb15d8959b3be 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -1073,15 +1073,22 @@ fiber_stack_destroy(struct fiber *fiber, struct slab_cache *slabc) * to setup the original protection back in * background. * + * For now lets keep such slab referenced and + * leaked: if mprotect failed we must not allow + * to reuse such slab with PROT_NONE'ed page + * inside. + * * Note that in case if we're called from * fiber_stack_create() the @a mprotect_flags is * the same as the slab been created with, so * calling mprotect for VMA with same flags * won't fail. */ - diag_log(); + say_syserror("fiber: Can't put guard page to slab. " + "Leak %zu bytes", (size_t)fiber->stack_size); + } else { + slab_put(slabc, fiber->stack_slab); } - slab_put(slabc, fiber->stack_slab); } } diff --git a/test/unit/fiber_stack.c b/test/unit/fiber_stack.c index 103dfaf0d498056820d1c3fecd6f4b57c730ccc3..41abe376417111d6827012b16db299fdfc899f65 100644 --- a/test/unit/fiber_stack.c +++ b/test/unit/fiber_stack.c @@ -15,11 +15,13 @@ noop_f(va_list ap) static int main_f(va_list ap) { + struct slab_cache *slabc = &cord()->slabc; + size_t used_before, used_after; struct errinj *inj; struct fiber *fiber; header(); - plan(4); + plan(6); /* * Set non-default stack size to prevent reusing of an @@ -47,8 +49,7 @@ main_f(va_list ap) ok(diag_get() != NULL, "mprotect: diag is armed after error"); /* - * Check madvise. We can't test the fiber destroy - * path since it is cleaning error. + * Check madvise error on fiber creation. */ diag_clear(diag_get()); inj = errinj(ERRINJ_FIBER_MADVISE, ERRINJ_BOOL); @@ -59,6 +60,35 @@ main_f(va_list ap) ok(fiber != NULL, "madvise: non critical error on madvise hint"); ok(diag_get() != NULL, "madvise: diag is armed after error"); + /* + * Check if we leak on fiber destruction. + * We will print an error and result get + * compared by testing engine. + */ + fiber_attr_delete(fiber_attr); + fiber_attr = fiber_attr_new(); + fiber_attr->flags |= FIBER_CUSTOM_STACK; + fiber_attr->stack_size = 64 << 10; + + diag_clear(diag_get()); + + used_before = slabc->allocated.stats.used; + + fiber = fiber_new_ex("test_madvise", fiber_attr, noop_f); + ok(fiber != NULL, "fiber with custom stack"); + fiber_set_joinable(fiber, true); + + inj = errinj(ERRINJ_FIBER_MPROTECT, ERRINJ_INT); + inj->iparam = PROT_READ | PROT_WRITE; + + fiber_start(fiber); + fiber_join(fiber); + inj->iparam = -1; + + used_after = slabc->allocated.stats.used; + ok(used_after > used_before, "expected leak detected"); + + fiber_attr_delete(fiber_attr); footer(); ev_break(loop(), EVBREAK_ALL); diff --git a/test/unit/fiber_stack.result b/test/unit/fiber_stack.result index 43ff74b2f56b47eb12441d1804c0083597c86825..7cae4e96c9e4492f56280b637385adbdedf56405 100644 --- a/test/unit/fiber_stack.result +++ b/test/unit/fiber_stack.result @@ -1,8 +1,11 @@ SystemError fiber mprotect failed: Cannot allocate memory +fiber: Can't put guard page to slab. Leak 57344 bytes: Cannot allocate memory *** main_f *** -1..4 +1..6 ok 1 - mprotect: failed to setup fiber guard page ok 2 - mprotect: diag is armed after error ok 3 - madvise: non critical error on madvise hint ok 4 - madvise: diag is armed after error +ok 5 - fiber with custom stack +ok 6 - expected leak detected *** main_f: done ***