Ошибка сегментации при доступе к статической функции через возвращенный указатель - PullRequest
9 голосов
/ 12 сентября 2011

У меня следующая структура:

struct sys_config_s
{
  char server_addr[256];
  char listen_port[100];
  char server_port[100];
  char logfile[PATH_MAX];
  char pidfile[PATH_MAX];
  char libfile[PATH_MAX];
  int  debug_flag;
  unsigned long connect_delay;
};
typedef struct sys_config_s sys_config_t;

У меня также есть функция, определенная в статической библиотеке (назовем ее A.lib):

sys_config_t* sys_get_config(void)
{
  static sys_config_t config;
  return &config;
}

Затем у меня естьпрограмма (назовем это B) и динамическая библиотека (назовем это C).Оба B и C связаны с A.lib.Во время выполнения B открывает C через dlopen(), а затем получает адрес функции C func() через вызов dlsym().

void func(void)
{
  sys_get_config()->connect_delay = 1000;
}

Приведенный выше код является телом функции func() C ипри достижении он выдает ошибку сегментации.Сегфоут происходит только при запуске вне gdb.

Почему это происходит?

РЕДАКТИРОВАТЬ: Создание sys_config_t config глобальной переменной не помогает.

Ответы [ 2 ]

1 голос
/ 12 сентября 2011

Решение тривиально.Каким-то образом из-за несоответствия заголовка константа PATH_MAX была определена по-разному в единицах компиляции B и C.Мне нужно быть более осторожным в будущем.( facepalms )

0 голосов
/ 12 сентября 2011

Нет никакой разницы между переменной, являющейся статической-локальной, или статической-глобальной переменной. Статическая переменная - это STATIC, что означает, что по требованию вызова функции она не выделяется в стеке в текущем функциональном фрейме, а скорее в одном из ранее существующих сегментов памяти, определенных в двоичных заголовках исполняемого файла.

В этом я уверен на 100%. Вопрос, где именно в каком сегменте они точно размещены и правильно ли они распределяются, - это еще одна проблема. Я видел похожие проблемы с разделением глобальных / статических переменных между модулями, но обычно суть проблемы была очень специфичной для точной настройки.

Пожалуйста, примите во внимание, что пример кода невелик, и я давно работал на этих платформах. То, что я написал выше, может быть неправильно сформулировано или даже неправильно в некоторых моментах!

Я думаю, что важно то, что вы получаете этот segfault в C при касании этой строки. Установка целочисленного поля в константу не могла завершиться неудачей, никогда, при условии, что целевой адрес действителен и не защищен от записи. Это оставляет два варианта: - либо ваша функция sys_get_config () потерпела крах - или вернул неверный указатель.

Так как вы говорите, что segfault возникает здесь, а не в sys_get_config, остается только последняя точка: сломанный указатель.

Добавьте в sys_get_config некоторый тривиальный printf, который будет выводить адрес, который будет возвращен, а затем сделать то же самое в вызывающей функции "func". Проверьте, не является ли оно пустым, а также проверьте, совпадает ли оно в sys_get_config с тем, что после возврата, просто чтобы убедиться, что соглашения о вызовах правильные и т. Д. Хорошей идеей для создания двойной / тройной проверки является также добавление внутри Модуль "A" - копия функции sys_get_config (с другим именем, конечно) и проверка того, совпадают ли адреса, возвращенные из sys_get_config и его копии. Если это не так - что-то пошло не так во время ссылки

Существует также очень малая вероятность того, что загрузка модуля была отложена, и вы пытаетесь сослаться на память модуля, который еще не был полностью инициализирован ... Я работал над linux очень давно, но я помню, этот длопен имеет различные варианты загрузки. Но вы написали, что получили адрес с помощью dlsym, поэтому я полагаю, что модуль загрузился, так как у вас есть конечный адрес символа ..

...