Mergesort that has `man 3 qsort` ANSI C prototype
Better show your includes too, that makes evaluating your code easier and more meaningful.
Anyway, it's &lt;stdlib.h&gt;, &lt;stdio.h&gt; and &lt;string.h&gt;.
You know you can combine multiple conditions into a single expression with &amp;&amp;?
You can avoid all those casts if you use char* instead of void* internally.
Why don't you reuse a single allocation instead of doing n*log(n) ones, each local?
You know doing a single combined memcpy is far more efficient than multiple consecutive smaller ones?
If you only move the first nlft elements out of the way, you only need half the extra-space and save on copying.


Your test-program:


Your test-program doesn't seem to exercise your code...
You lost a newline at the end of your test-program.


Modified code:

#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

void* malloc_or_exit(size_t size) {
    void* result = malloc(size);

    if (!result &amp;&amp; size) {
        fprintf(
            stderr, "Failed to malloc %zu bytes: %s",
            size, strerror(errno)
        );
        exit(EXIT_FAILURE);
    }

    return result;
}

static void mergesort0_impl(
    char* as, char* xs, size_t n, size_t s,
    int (*cmp) (const void*, const void*)
) {
    if (n &lt; 2) return;

    const size_t nlft = n / 2;
    const size_t nrgt = n - nlft;

    char* ys = xs + nlft * s;

    mergesort0_impl(as, xs, nlft, s, cmp);
    mergesort0_impl(as, ys, nrgt, s, cmp);

    char* const bs = as + nlft * s;

    memcpy(as, xs, nlft * s);

    const char* i = as;
    const char* j = ys;
    for (; i != bs &amp;&amp; j != xs; xs += s) {
        if (cmp(i, j) &lt;= 0) {
            memcpy(xs, i, s);
            i += s;
        } else {
            memcpy(xs, j, s);
            j += s;
        }
    }
    if (i != bs)
        memcpy(xs, i, bs - i);
}

void mergesort0(
    void* xs, size_t n, size_t s,
    int (*cmp) (const void*, const void*)
) {
    if(n &lt; 2) return;
    void* as = malloc_or_exit(n / 2 * s);
    mergesort0_impl(as, xs, n, s, cmp);
    free(as);
}


#include &lt;stdio.h&gt;

void test(int nr, const int xs[], size_t n) {
    int* a = malloc_or_exit(2 * n * sizeof *xs);
    int* b = a + n;
    memcpy(a, xs, n * sizeof *xs);
    memcpy(b, xs, n * sizeof *xs);
    qsort(a, n, sizeof *a, compare_int);
    mergesort0(b, n, sizeof *b, compare_int);
    printf("Test %d %s: ", nr, !memcmp(a, b, n * sizeof *xs) ? "OK" : "FAILED");
    for (size_t i = 0; i &lt; n; ++i)
        printf("%d%c", xs[i], " \n"[i == n - 1]);
    free(a);
}

int main() {
    int xs[] = {1, 2, 3, 4, 5};
    int ys[] = {5, 4, 3, 2, 1};
    int zs[] = {3, 1, 2, 4, 5};
    int as[] = {1, 1, 1};
    int bs[] = {3, 2, 2};
    int nr = 0;
    #define TEST(a) test(nr++, a, sizeof a / sizeof *a)
    TEST(xs);
    TEST(ys);
    TEST(zs);
    TEST(as);
    TEST(bs);
    #undef TEST
}