int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *),
                       int (*cmp_func) (const char *, const char *),
                       void (*free_func) (const char *, int, const char *))
{
    int ret = 0, i, push;
    NAME_FUNCS *name_funcs;

    if (!OBJ_NAME_init())
        return 0;

    CRYPTO_THREAD_write_lock(obj_lock);

    if (name_funcs_stack == NULL) {
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
        name_funcs_stack = sk_NAME_FUNCS_new_null();
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
    }
    if (name_funcs_stack == NULL) {
        /* ERROR */
        goto out;
    }
    ret = names_type_num;
    names_type_num++;
    for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
        name_funcs = OPENSSL_zalloc(sizeof(*name_funcs));
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
        if (name_funcs == NULL) {
            OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
            ret = 0;
            goto out;
        }
        name_funcs->hash_func = OPENSSL_LH_strhash;
        name_funcs->cmp_func = obj_strcmp;
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);

        push = sk_NAME_FUNCS_push(name_funcs_stack, name_funcs);
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);

        if (!push) {
            OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
            OPENSSL_free(name_funcs);
            ret = 0;
            goto out;
        }
    }
    name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
    if (hash_func != NULL)
        name_funcs->hash_func = hash_func;
    if (cmp_func != NULL)
        name_funcs->cmp_func = cmp_func;
    if (free_func != NULL)
        name_funcs->free_func = free_func;

out:
    CRYPTO_THREAD_unlock(obj_lock);
    return ret;
}