static char *sh_malloc(size_t size)
{
    ossl_ssize_t list, slist;
    size_t i;
    char *chunk;

    list = sh.freelist_size - 1;
    for (i = sh.minsize; i < size; i <<= 1)
        list--;
    if (list < 0)
        return NULL;

    /* try to find a larger entry to split */
    for (slist = list; slist >= 0; slist--)
        if (sh.freelist[slist] != NULL)
            break;
    if (slist < 0)
        return NULL;

    /* split larger entry */
    while (slist != list) {
        char *temp = sh.freelist[slist];

        /* remove from bigger list */
        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
        sh_clearbit(temp, slist, sh.bittable);
        sh_remove_from_list(temp);
        OPENSSL_assert(temp != sh.freelist[slist]);

        /* done with bigger list */
        slist++;

        /* add to smaller list */
        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
        sh_setbit(temp, slist, sh.bittable);
        sh_add_to_list(&sh.freelist[slist], temp);
        OPENSSL_assert(sh.freelist[slist] == temp);

        /* split in 2 */
        temp += sh.arena_size >> slist;
        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
        sh_setbit(temp, slist, sh.bittable);
        sh_add_to_list(&sh.freelist[slist], temp);
        OPENSSL_assert(sh.freelist[slist] == temp);

        OPENSSL_assert(temp-(sh.arena_size >> slist) == sh_find_my_buddy(temp, slist));
    }

    /* peel off memory to hand back */
    chunk = sh.freelist[list];
    OPENSSL_assert(sh_testbit(chunk, list, sh.bittable));
    sh_setbit(chunk, list, sh.bitmalloc);
    sh_remove_from_list(chunk);

    OPENSSL_assert(WITHIN_ARENA(chunk));

    return chunk;
}