execve后,前一个进程addr的内存是否释放了?

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

在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;
}

仔细阅读execve(2) (and also Advanced Linux Programming to get a broader view). Read about virtual memory, paging, MMUs, processes的文档。

execvesystem call is installing a fresh new virtual address space in your process (so the old virtual address space of the program doing execve successfully disappears, being overwritten by the new one), so you don't share any data with the previous one (and a successful execve does not return, since the new program is started). Your new program would be able to later change the virtual address space, e.g. with mmap(2)...

新虚拟地址space中argv个字符串的地址与execve的参数地址无关;字符串内容相同。旧虚拟地址 space 和新虚拟地址之间没有 data shared,但是新程序(和程序环境)的参数已复制。另请阅读 ASLR

execve 的参数被 字符串 复制(压入它们的副本)到新虚拟地址 space 的新调用堆栈上它的起始函数(crt0 which calls main). Of course you should not free any argv[i] - that would be undefined behavior.

中的_start

因此 int a; argv[1]=(char*)&a; ... execveargv 是未定义的行为,因为你不能保证 [=25 地址处的内存区域=] 是一个正确的以 null 结尾的字符串。了解 endianness & ABI.

所以 execve 想要一个 NULL 终止数组 argv 适当的 字符串 (不是任意指针),另一个 NULL 终止 env 个字符串数组,每个字符串应以零字节终止。从旧地址 space 通过 argvenv 复制到新地址的总内存 space 有一个相当小的限制 ARG_MAX(通常为 128Kbytes) .

您可能或许 使用共享内存(参见shm_overview(7)) to share memory between various processes (and you'll synchronize with semaphores, see sem_overview(7)...); but you often would prefer other inter-process communication techniques (e.g. pipe(7)-s, fifo(7)-s, socket(7)-s 等...)。

顺便说一句,也使用 strace(1) to understand which system calls are involved by your program, and use proc(5),特别是 运行 cat /proc/$$/mapscat /proc/$pidofyourprogram/maps 了解有关虚拟地址的更多信息 space。

您甚至可以将两个 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);

这将向您展示虚拟地址 space 的视图。当然,更严肃的程序应该 fopen 一个 /proc/1234/maps 文件并循环 fgets 读取每一行,直到 EOF 然后 fclose.

耐心点,阅读这里的所有参考资料,然后 time to learn more about POSIX programming. Studying some free software source code (e.g. on http://github.com/ 你可以选择一些有趣的项目...),为他们做出贡献应该是值得的。