2010-03-22 2 views
7

Я пытаюсь выследить очень странный сбой. Что странно, так это обходной путь, который кто-то обнаружил и который я не могу объяснить.Как может exec изменить поведение программы exec'ed

Обойти это небольшая программа, которую я буду называть «бегуна»:

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 

int main(int argc, char *argv[]) 
{ 
    if (argc == 1) 
    { 
     fprintf(stderr, "Usage: %s prog [args ...]\n", argv[0]); 
     return 1; 
    } 

    execvp(argv[1], argv + 1); 

    fprintf(stderr, "execv failed: %s\n", strerror(errno)); 

    // If exec returns because the program is not found or we 
    // don't have the appropriate permission 
    return 255; 
} 

Как вы можете видеть, все это делает программа использовать execvp заменить себя с другой программой.

программа падает, когда она непосредственно вызывается из командной строки:

/path/to/prog args # this crashes 

но прекрасно работает, когда она косвенно вызывается через мой бегун прокладки:

/path/to/runner /path/to/prog args # works successfully 

для жизни меня, Я могу понять, как наличие дополнительного exec может изменить поведение выполняемой программы (так как вы можете видеть, что программа не меняет среду).

Некоторые фоне аварии. Сама авария происходит во время выполнения C++. В частности, когда программа делает throw, ошибочная версия ошибочно думает, что нет соответствующего улова (хотя есть) и вызывает terminate. Когда я вызываю программу через бегун, исключение будет правильно поймано.

Мой вопрос - любая идея, почему дополнительный exec изменяет поведение программы exec'ed?

+0

Я не знаю: Но работает ли execvp рабочий каталог? Какие аргументы вы передаете? –

+0

@MartinYork - AFAIK, 'execvp' никогда не меняет рабочий каталог (для которого требуется вызов' chdir', а runner этого не делает). Конкретные аргументы не имеют значения; описанное поведение не зависит от конкретных аргументов, переданных программе. –

+1

Это делает то же самое, если вы используете 'execv()' вместо 'execvp()'? – caf

ответ

3

Возможно, файлы .so, загруженные бегуном, заставляют рунита работать правильно. Попробуйте ldd'ing каждого из двоичных файлов и посмотрите, загружаются ли какие-либо библиотеки в разные версии/местоположения.

+1

Проблема заключается в том, что 'ld-linux.so.2' сопоставляет определенный общий объект в адресном пространстве перед основным двоичным или после (фактическая ошибка в другом месте, но из-за обстоятельств ошибка появляется только тогда, когда SO сопоставляется с более низкий адрес, затем главный двоичный файл). –

0

Как выстрел в темноте: double-exec может изменить порядок переменных окружения в ОЗУ.

Окружающая среда - структура памяти с указателями; ядро копирует эту структуру в адресное пространство нового процесса. Фактический порядок элементов в ОЗУ может измениться во время этой копии (переменные среды не являются семантически упорядоченными, но адреса в ОЗУ имеют порядок). С двумя exec() порядок может быть изменен дважды.

То, что изменение порядка строк в ОЗУ обнаруживает ошибку, несколько причудливо, но произошло нечто странное.

+0

Спасибо за предложение, но это, похоже, не так. Я сбросил блок исходной среды, и у них одинаковый порядок в обоих. –

0

Интересно, передаете ли вы что-то другое в argv [0] для оболочки. Я не вижу, очевидно, из того, что вы пишете выше, но возможно, что вы устанавливаете argv [0] в фактический первый аргумент для программы, тогда как оболочка устанавливает его на свое имя (например, полный или короткий путь)

+0

@MarkR - спасибо за ваше предложение. Я изменил runner так, чтобы 'argv [0]' не включал путь. К сожалению, я все еще вижу такое же поведение. –

1

Возможно, вызываемая программа имеет утечку памяти. Попробуйте запустить его с помощью valgrind или другого инструмента проверки памяти. После того, как у вас есть ошибка памяти, все остальное - неопределенное поведение (и, следовательно, все может случиться).

+0

Другие, кроме нормального, все еще доступные в выходных блоках, Valgrind не обнаруживает никаких ошибок в версии, которая заканчивается (или версия, которая не заканчивается в этом отношении). –

0

Я предполагаю, что две вещи, которые вы могли бы сравнить между версиями «working» и «crashing» - открывать дескрипторы файлов и обработчики сигналов, поскольку они передаются exec.

Я не вижу, как они являются проблемой/быть разными, но, возможно, стоит их устранить.

Смежные вопросы