после execve освобождается ли память в предыдущем адресе процесса?

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

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

int main(void)
{
    char filename[20] = "a.out";
    char str[20] = "hello\n";
    char *argv[3];

    argv[0] = filename;
    argv[1] = str;
    argv[2] = NULL;
    execve("/hel/a.out", argv, NULL);
    return 0;
}

/*   /hel/a.out code   */
#include <stdio.h>

int main(int argc, char *argv[], char *envp[])
{
    printf("%s\n", argv[1]);  /** Here, should the memory pointed by argv[1]
                               *  be freed after execve  has been called?
                               */ 
    return 0;
}

person hel    schedule 20.12.2015    source источник
comment
Вы действительно должны использовать strace   -  person Basile Starynkevitch    schedule 20.12.2015
comment
Да. Я поместил ваш код трассировки в main, и вывод получился немного сложным. Я изучаю расширенное программирование в среде UNIX и хочу закончить его, чтобы получить глобальную концепцию. После этого, возможно, пришло время для изучения каждой детали.   -  person hel    schedule 20.12.2015
comment
Возможно, я понял. Если а=13; (старший байт 00, младший байт 0d) argv[1] = (char *)(&a); Во втором основном правильном формате вывода, например: printf(%s, argv[1]); // print '\n' Скопируйте только строки аргументов и среды в новые места в execve. Я не знаю, прав я или нет. Спасибо за все ответы, и я изучу это глубоко позже.   -  person hel    schedule 20.12.2015


Ответы (1)


внимательно прочитайте документацию по execve(2) (а также Advanced Linux Programming, чтобы получить более широкий обзор). Прочтите о виртуальной памяти, пейджинг, MMU, процессы.

execve системный вызов устанавливает новую новую виртуальное адресное пространство в вашем процесс (поэтому старое виртуальное адресное пространство программы, выполняющей execve, успешно исчезает, перезаписываясь новым), поэтому вы не делитесь данными с предыдущим (и успешный execve не возвращается, так как запускается новая программа). Ваша новая программа сможет позже изменить виртуальное адресное пространство, например. с mmap(2)...

Адреса argv строк в новом виртуальном адресном пространстве не зависят от адресов аргументов execve; содержимое строки такое же. Никакие данные не разделяются между старым виртуальным адресным пространством и новым, но аргументы новой программы (и программной среды) копируются. Читайте также об ASLR

Аргументы execve копируются строки (с отправкой их копии) в новый свежий стек вызовов нового виртуального адресного пространства для его стартовой функции (_start в crt0, который вызывает main). Конечно, вы не должны free выполнять какие-либо argv[i] - это будет неопределенное поведение.

Следовательно, int a; argv[1]=(char*)&a; ... execve с argv — это неопределенное поведение, потому что вы не можете гарантировать, что зона памяти по адресу a является правильной строкой с завершающим нулем. Прочтите об порядке байтов и ABI.

Таким образом, execve нужен NULL завершенный массив argv правильных строк (не произвольных указателей) и другой NULL завершенный env массив строк, и каждая строка должна заканчиваться нулевым байтом. Существует довольно небольшое ограничение ARG_MAX (обычно 128 Кбайт) на общий объем памяти, скопированный из старого адресного пространства в новое через argv и env.

Вы могли бы возможно использовать общую память (см. shm_overview( 7)) для совместного использования памяти между различными процессами (и вы будете синхронизироваться с семафорами, см. sem_overview(7)...); но вы часто предпочитаете другие методы межпроцессного взаимодействия (например, pipe(7)-s, fifo(7)-s, socket(7)-s и т. д.).

Кстати, используйте также strace(1), чтобы понять, какая система вызывает задействованы вашей программой, и используйте proc(5), в частности, запустив cat /proc/$$/maps и cat /proc/$pidofyourprogram/maps, чтобы больше узнать о виртуальном адресном пространстве.

Вы даже можете поместить обе свои функции main (до execve в первую, перед return 0; во вторую) что-то вроде

 char cmd[64];
 snprintf(cmd, sizeof(cmd), "/bin/cat /proc/%d/maps", (int)getpid());
 printf("before running %s\n", cmd);
 fflush(NULL);
 int err = system(cmd);
 if (err) fprintf(stderr, "system failed err=%d\n", err);
 else printf("system %s done\n", cmd);

Это покажет вам представление виртуального адресного пространства. Конечно, более серьезная программа должна fopen /proc/1234/maps файл и зацикливаться на fgets, чтобы прочитать каждую строку до EOF, а затем fclose.

Будьте терпеливы, прочитайте все ссылки здесь и уделите времени, чтобы узнать больше о программировании POSIX. Изучение исходного кода некоторого бесплатного программного обеспечения (например, на http://github.com)./ вы можете выбрать несколько интересных проектов...) и участие в них должно быть полезным.

person Basile Starynkevitch    schedule 20.12.2015
comment
Да спасибо. Я правильно нахожу вывод a.out. Будет ли сохранена глобальная переменная, а локальная будет освобождена? Я снова прочитал execve(2) и ничего не нашел по этому поводу. - person hel; 20.12.2015
comment
Переменные находятся внутри виртуального адресного пространства. А так как заменена вся ВАС, то ваш вопрос не имеет смысла. Вам действительно нужно потратить несколько часов на чтение ссылок, которые я дал в своем ответе. - person Basile Starynkevitch; 20.12.2015
comment
Разные VAS после execve. независимый адрес, но такое же содержание строк. Я тестирую такой код 'int a = 3; argv[1] = (char *)' и в исходном файле a.out: ' printf(%d\n, *((int *)argv[1]));' На выходе случайное число. - person hel; 20.12.2015
comment
@hl: да, потому что execve копирует строку каждого argv, а (char*)&a не является правильной строкой (с нулевым завершением и, как правило, в кодировке UTF8, даже если execve не заботится о кодировке) - person Basile Starynkevitch; 20.12.2015
comment
a=3 и сохраняется (00-03). Если да, то можно ли правильно скопировать (00-03) в новый VAS? Поскольку два байта заканчиваются нулем. Но это случайное число. - person hel; 20.12.2015
comment
Пожалуйста, потратьте несколько часов на прочтение всех ссылок (а то у вас в голове сбивчивая картинка)... Попробуйте cat /proc/$$/maps эксперимент. Я не могу научить вас всему в нескольких абзацах. Вам понадобятся дни, чтобы изучить все это. Наберитесь терпения и начните работать самостоятельно. - person Basile Starynkevitch; 20.12.2015
comment
Я до сих пор не могу понять a = 3. можно ли его рассматривать как строку с завершающим нулем относительно 00-03? интервал а=3; argv[1]=(char*) Извините за беспокойство. И я узнаю больше об execve. - person hel; 20.12.2015
comment
Давайте продолжим обсуждение в чате. - person hel; 20.12.2015