after execve, are memory in the previous process addr freed?

hel*_*hel 2 linux 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;
}
Run Code Online (Sandbox Code Playgroud)

Bas*_*tch 5

仔细阅读execve(2)的文档(以及Advanced Linux Programming以获得更广阔的视野)。阅读有关虚拟内存分页MMU进程的信息

execve 系统调用是安装一个全新的虚拟地址空间中的进程(所以程序做旧的虚拟地址空间execve 成功地消失,被新的不被覆盖),所以你不共享与前一个的任何数据(和成功execve不会返回,因为新程序已启动)。您的新程序稍后将能够更改虚拟地址空间,例如使用mmap(2) ...

地址argv在新的虚拟地址空间字符串是独立的参数的地址execve; 字符串内容相同。没有数据共享旧的虚拟地址空间和新的之间,而且参数的新程序(和程序环境)的复制。另请阅读有关ASLR 的信息

的参数execve是在其起始函数( 在crt0中调用)的新虚拟地址空间的新调用堆栈上复制的字符串(连同它们的副本被推送)。当然,你不应该有任何i - 那将是未定义的行为_startmainfreeargv[]

因此int a; argv[1]=(char*)&a;... execvewith argv, 是未定义的行为,因为您不能保证地址处的内存区域a是正确的以空字符结尾的字符串。阅读有关字节顺序ABI 的信息

所以execve 想要一个NULL终止argv的正确字符串数组(不是任意指针),以及另一个NULL 终止env的字符串数组,每个字符串应该以零字节终止。ARG_MAX通过argv&从旧地址空间复制到新地址空间的总内存空间有一个相当小的限制(通常为 128 KB)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);
Run Code Online (Sandbox Code Playgroud)

这将显示虚拟地址空间的视图。当然,更严肃的程序应该fopen是一个/proc/1234/maps文件,然后循环fgets读取每一行直到EOF那时fclose

请耐心阅读此处的所有参考资料,并花时间了解有关 POSIX 编程的更多信息。研究一些免费软件源代码(例如在http://github.com/ 上,您可以选择一些有趣的项目...)并为它们做出贡献应该是值得的。