Сбой удаленного сценария CGI на основе C в __libc_start_main()

У меня есть сценарий CGI, написанный на C. Я знаю, что это неортодоксально в наше время, но у меня есть свои причины. Кроме того, он скомпилирован с помощью -static, поэтому мне не нужно беспокоиться об общих библиотеках моего веб-провайдера. Скрипт работает нормально уже больше года, но недавно сломался. Также общеизвестно, что отладить проблему очень сложно, потому что скрипт дает сбой в службе моего веб-провайдера, и я не получаю много информации. Но я получаю дампы ядра.

Проблема, которую я вижу: На удаленном сервере происходит сбой сценария CGI, и ошибка, по-видимому, исходит из кода запуска, т. е. того, что выполняется до того, как моя функция main() когда-либо будет достигнута ( __libc_start_main()).

Я создал SSCCE, иллюстрирующий проблему, с именем hey.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  printf("Content-type: text/plain\n\n");
  printf("Hey, is this thing on?\n");
  printf("query string: '%s'\n", getenv("REQUEST_URI"));
  return 0;
}

Скомпилировано на 64-битном Linux с помощью gcc:

gcc -g -Wall hey.c -o hey.cgi -static

Работает нормально из подсказки:

$ REQUEST_URI="q=querystring" ./hey.cgi
Content-type: text/plain

Hey, is this thing on?
query string: 'q=querystring'

Когда я запускаю его локально на установке Apache (например, http://localserver/cgi-bin/hey.cgi?q=query), веб-страница показывает:

Hey, is this thing on?
query string: '/cgi-bin/hey.cgi?q=query'

Однако, когда я помещаю этот двоичный файл в каталог Apache cgi-bin моего веб-провайдера, я получаю 500 Internal Server Error. После сбоя сервер оставляет пронумерованные дампы ядра, которые я затем загружаю и проверяю с помощью gdb:

Core was generated by `hey.cgi'.
Program terminated with signal 11, Segmentation fault.
#0  0x000000000041b763 in __syscall_error ()
(gdb) bt
#0  0x000000000041b763 in __syscall_error ()
#1  0x0000000000402569 in __libc_message ()
#2  0x000000000040283c in __libc_fatal ()
#3  0x0000000000401355 in __libc_start_main ()
#4  0x0000000000401081 in _start ()

Я знаю, что много низкоуровневых деталей, но, надеюсь, проблема очевидна для кого-то из Stack Overflow. Спасибо.

Более подробная информация в соответствии с комментариями: я проверил с помощью простого скрипта Python CGI (и os.environ[]), что REQUEST_URI определен. Я думаю, что это основа протокола CGI, но я не эксперт.

file сообщает о статически связанном двоичном файле x86-64; ldd сообщает «не динамический исполняемый файл». Libtool никогда не вступает в игру — я использую один вызов команды gcc для создания всего сценария.

Идеально было бы компилировать скрипт на сервере. Если бы у меня был такой доступ, у меня, вероятно, было бы достаточно гибкости, чтобы избежать этого подхода. Я не беспокоюсь о защите источника; это было просто лучшее решение, которое я мог найти для своей проблемы. Рассматриваемая программа представляет собой пользовательскую поисковую систему для моего сайта, состоящую примерно из 20 строк C для взаимодействия с библиотекой под названием SWISH-E. Мой веб-провайдер не предоставляет слишком много возможностей, но я смог это сделать.

Другие решения включают в себя: перенос на другой хостинг (много хлопот); найти чистое решение на основе PHP, которое будет поддерживаться на моем хосте (я исследую это через mnoGoSearch).


person Multimedia Mike    schedule 30.11.2013    source источник
comment
Вы уверены, что REQUEST_URI существует на сервере вашего провайдера? в противном случае getenv вернет значение null, и его чтение будет иметь неопределенное поведение.   -  person jcm    schedule 01.12.2013
comment
Вы уверены, что двоичный файл действительно статичен? libtool печально известен тем, что отказывается соблюдать -static, и также может случиться так, что некоторые динамические библиотеки будут использоваться, если вам не хватает их статических версий в системе, где вы компилируете. Используйте ldd, file и т. д. для проверки.   -  person R.. GitHub STOP HELPING ICE    schedule 01.12.2013
comment
Вы действительно должны скомпилировать этот код на машине, где вы хотите, чтобы он работал, вместо того, чтобы компилировать на одной машине, а затем загружать двоичный файл на другую. На вашем сервере не установлен gcc?   -  person r3mainer    schedule 01.12.2013
comment
Возможно, ОП пытается защитить свой исходный код. Вот почему он использует C (в отличие от более распространенных языков сценариев, таких как PHP, PERL и т. д.) и компилирует на своем собственном сервере. Самый простой способ отладить это — заставить программу записывать информацию в файл журнала в различных точках программы, чтобы вы могли видеть, как далеко она продвинулась, прежде чем она умрет.   -  person mti2935    schedule 01.12.2013
comment
Спасибо за все комментарии. Я обновил свой вопрос с ответами и пояснениями.   -  person Multimedia Mike    schedule 01.12.2013


Ответы (1)


Я нашел решение и хотел опубликовать его, так как эти вопросы о переполнении стека могут оказаться в топе результатов Google.

В конце концов, я планирую решить эту проблему, перенеся эту часть функциональности на другой сервер или платформу, где у меня будет больше возможностей для отладки. Тем временем я решил, что, поскольку проблема, похоже, связана с компиляцией с -static, и поскольку я не могу установить необходимую общую библиотеку на систему общего хостинга в стандартный каталог lib, вместо этого я выберу динамический подход. Я загрузил необходимый общий объект в тот же каталог, что и мой скомпилированный сценарий, и переработал свой сценарий CGI на основе C, чтобы использовать dlopen/dlsym для динамического открытия общего объекта, извлечения необходимых указателей функций и вызова этих указателей.

Этот подход работает (хотя я держу пальцы скрещенными, чтобы он снова не сломался таинственным образом), пока я ищу другие решения. Если кто-то еще столкнется с этой странной комбинацией проблем, возможно, это поможет.

person Multimedia Mike    schedule 06.12.2013