Добавить массив, используя apr_array_push в D - PullRequest
1 голос
/ 16 ноября 2010

Я пишу программу на D, которая использует svn, и я столкнулся с чем-то, что я не могу понять, как преобразовать в синтаксис D. Я попробовал его, но он сломался.

Пример того, что я пытаюсь выполнить в C:

svn_auth_provider_object_t provider;
providers = apr_array_make(pool, 1, sizeof(svn_auth_provider_object_t*));
svn_auth_get_simple_provider2(&provider, null, null, pool);
*(svn_auth_provider_object_t**)apr_array_push (providers) = provider;
svn_auth_open(&auth_baton, providers, pool);

Насколько я знаю, этот код работает просто отлично. Я нашел несколько примеров, сделанных почти одинаково. Вот моя попытка скопировать это в D:

svn_auth_provider_object_t provider;
providers = apr_array_make(pool, 1, svn_auth_provider_object_t.sizeof);
svn_auth_get_simple_provider2(&provider, null, null, pool);
void* newSlot = apr_array_push(m);
newSlot = provider;
svn_auth_open(&auth_baton, providers, pool);

Это вызывает ошибку сегментации в svn_auth_open. Мое лучшее предположение состоит в том, что содержимое провайдера не заканчивается указателем, удерживаемым newSlot. И я не уверен, почему это так.

Дополнительный код:

/// Code taken from Apache's APR libary which is licensed under Apache License, Version 2.0

struct apr_array_header_t {
    apr_pool_t* pool;
    int elt_size;
    int nelts;
    int nalloc;
    char* elts;
};

struct svn_auth_provider_object_t
{
    svn_auth_provider_t *vtable;
    void *provider_baton;
}

APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr)
{
    if (arr->nelts == arr->nalloc) {
        int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2;
        char *new_data;

        new_data = apr_palloc(arr->pool, arr->elt_size * new_size);

        memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size);
        memset(new_data + arr->nalloc * arr->elt_size, 0,
               arr->elt_size * (new_size - arr->nalloc));
        arr->elts = new_data;
        arr->nalloc = new_size;
    }

    ++arr->nelts;
    return arr->elts + (arr->elt_size * (arr->nelts - 1));
}

#define APR_ARRAY_IDX(ary,i,type) (((type *)(ary)->elts)[i])
#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))

void
svn_auth_open(svn_auth_baton_t **auth_baton,
              apr_array_header_t *providers,
              apr_pool_t *pool)
{
  svn_auth_baton_t *ab;
  svn_auth_provider_object_t *provider;
  int i;

  /* Build the auth_baton. */
  ab = apr_pcalloc(pool, sizeof(*ab));
  ab->tables = apr_hash_make(pool);
  ab->parameters = apr_hash_make(pool);
  ab->creds_cache = apr_hash_make(pool);
  ab->pool = pool;

  /* Register each provider in order.  Providers of different
     credentials will be automatically sorted into different tables by
     register_provider(). */
  for (i = 0; i < providers->nelts; i++)
    {
      provider_set_t *table;
      provider = APR_ARRAY_IDX(providers, i, svn_auth_provider_object_t *);

      /* Add it to the appropriate table in the auth_baton */
      table = apr_hash_get(ab->tables,
                           provider->vtable->cred_kind, APR_HASH_KEY_STRING);
      if (! table)
        {
          table = apr_pcalloc(pool, sizeof(*table));
          table->providers
            = apr_array_make(pool, 1, sizeof(svn_auth_provider_object_t *));

          apr_hash_set(ab->tables,
                       provider->vtable->cred_kind, APR_HASH_KEY_STRING,
                       table);
        }
      APR_ARRAY_PUSH(table->providers, svn_auth_provider_object_t *)
        = provider;
    }

  *auth_baton = ab;
}

Мое лучшее предположение состоит в том, что segfault происходит в APR_ARRAY_IDX. Все остальное имеет действительный адрес памяти.

Дополнительная информация: Это тоже не работает:

providers = apr_array_make(pool, 1, svn_auth_provider_object_t.sizeof);
svn_auth_provider_object_t* newSlot = cast(svn_auth_provider_object_t*) apr_array_push(providers);
svn_auth_get_simple_provider2(&newSlot, null, null, pool);
svn_auth_open(&auth_baton, providers, pool);

Так что это исключает мою теорию о том, что данные не шли в нужное место. Однако, если я закомментирую толчок строки массива и просто отправлю массив пустым, он будет работать нормально. Таким образом, это не segfault:

providers = apr_array_make(pool, 1, svn_auth_provider_object_t.sizeof);
svn_auth_open(&auth_baton, providers, pool);

Я также знаю, что это не svn_auth_get_simple_provider2, потому что это тоже segfaults ...

providers = apr_array_make(pool, 1, svn_auth_provider_object_t.sizeof);
svn_auth_provider_object_t* newSlot = cast(svn_auth_provider_object_t*) apr_array_push(providers);
svn_auth_get_ssl_server_trust_file_provider(&newSlot, pool);
svn_auth_open(&auth_baton, providers, pool);

1 Ответ

3 голосов
/ 17 ноября 2010

На первый взгляд, первое назначение newSlot не работает, поскольку следующая строка перезаписывает его, устанавливая его на null.Попробуйте:

auto newSlot = cast(svn_auth_provider_object_t**)apr_array_push(m);
*newSlot = provider;

Это привело бы к ошибке времени компиляции, если бы не было void*.

Я думаю, что единственная часть версии C, которая не действительнаD - актерский состав.

...