Как dlerror () может вернуть NULL, если dlopen () завершится неудачно? - PullRequest
2 голосов
/ 17 декабря 2011

Я работаю в системе, которая автоматически загружает все библиотеки *.so модулей, вызывая скрипт.

Я попытался обновить один из модулей для поддержки XML-RPC. Я использовал библиотеку ibxmlrpc-c3-dev в Ubuntu 10.10. Проблема в том, что dlopen() терпит неудачу после моих изменений и dlerror() возвращает NULL. Компиляция не возвращает никаких ошибок.

Как я могу отладить и исправить эту проблему? Ниже приведен код:

#include "stdlib.h"
#include "stdio.h"
#ifndef WIN32
#include "unistd.h"
#endif

#include "xmlrpc-c/base.h"
#include "xmlrpc-c/server.h"
#include "xmlrpc-c/server_abyss.h"

#include "config.h"  /* information about this build environment */

И, я добавил эту функцию, большинство строк закомментированы, даже если dlopen() не удается:

int RPC_Server(int           const port) {

   // xmlrpc_server_abyss_parms serverparm;
    //xmlrpc_registry * registryP;
    xmlrpc_env env;



    xmlrpc_env_init(&env);

    //registryP = xmlrpc_registry_new(&env);

   // xmlrpc_registry_add_method(
    //    &env, registryP, NULL, "sample.add", &sample_add, NULL);

    /* In the modern form of the Abyss API, we supply parameters in memory
       like a normal API.  We select the modern form by setting
       config_file_name to NULL:
    */
  //  serverparm.config_file_name = NULint
    RPC_Server(int           const port) {

       // xmlrpc_server_abyss_parms serverparm;
        //xmlrpc_registry * registryP;
        xmlrpc_env env;



        xmlrpc_env_init(&env);

        //registryP = xmlrpc_registry_new(&env);

       // xmlrpc_registry_add_method(
        //    &env, registryP, NULL, "sample.add", &sample_add, NULL);

        /* In the modern form of the Abyss API, we supply parameters in memory
           like a normal API.  We select the modern form by setting
           config_file_name to NULL:
        */
      //  serverparm.config_file_name = NULL;
       // serverparm.registryP        = registryP;
       // serverparm.port_number      = port;
       // serverparm.log_file_name    = "/tmp/xmlrpc_log";

       // printf("Running XML-RPC server...\n");

       // xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name));

        /* xmlrpc_server_abyss() never returns */

        return 0;
    }L;
   // serverparm.registryP        = registryP;
   // serverparm.port_number      = port;
   // serverparm.log_file_name    = "/tmp/xmlrpc_log";

   // printf("Running XML-RPC server...\n");

   // xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name));

    /* xmlrpc_server_abyss() never returns */

    return 0;
}

и этот код используется для загрузки модулей

#ifndef RTLD_NOW

#define RTLD_NOW DL_LAZY
#endif   
void* handle;
char* error;


handle=dlopen(mod->binary_file, RTLD_NOW); 

if (!handle){
LOG( " could not open file [%s]: %s\n",
    mod_cfg->binary_file, dlerror() );
return 0;
}

Ответы [ 4 ]

3 голосов
/ 18 декабря 2011

В этом коде:

handle=dlopen(mod->binary_file, RTLD_NOW); 

if (!handle) {
    LOG( " could not open file [%s]: %s\n",
         mod_cfg->binary_file, dlerror() );

наиболее вероятный способ, которым я могу придумать, чтобы dlerror() возвратил NULL, это если сам LOG вызывает одну из dl* подпрограмм (который очистит состояние ошибки, которое возвращает dlerror).

Итак,

  • покажет нам, что макрос LOG (если он действительно является макросом)) расширяется до и
  • запускает программу под GDB, устанавливает точки останова на dlopen, dlmopen, dlsym и dlvsym и наблюдает, что один из них называется после ваш звонок на dlopen выше и до вашего звонка на dlerror.
2 голосов
/ 17 декабря 2011

Я бы использовал отладчик как gdb.

Если вы не можете использовать его, попробуйте использовать strace или ltrace для процесса, выполняющего dlopen

Кроме того, очистите errno перед вызовом dlopen и отобразите его (или распечатайте в отладчике) сразу после сбоя dlopen.

Проверьте с помощью file, objdump и nm -D, что ваш dlopen -ed *.so файл имеет все необходимые свойства (например, символы).

Возможно, адресное пространство памяти процесса, выполняющего dlopen, настолько заполнено (или достигло некоторых ограничений ресурсов), что некоторые внутренние malloc внутри libdl.so не работают (например, то, которое используется dlerror).

0 голосов
/ 10 июня 2019
handle=dlopen(mod->binary_file, RTLD_NOW); 

if (!handle){
string errmsg = string(dlerror());
LOG( " could not open file [%s]: %s\n",
    mod_cfg->binary_file, errmsg.c_str() );
return 0;
}

Я сталкиваюсь с той же проблемой при использовании BoostLog, и выше мое решение. Я полагаю, что LOG влияет на dlerror ().

0 голосов
/ 17 декабря 2011

Прежде всего, вы обязательно должны использовать dlerror.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...