在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;
}
答案 0 :(得分:2)
仔细阅读 execve(2)(以及Advanced Linux Programming的文档以获取更广泛的视图)。阅读virtual memory,paging,MMU s,processes。
execve
system call正在virtual address space中安装全新的process (因此,该程序的旧虚拟地址空间正在{ {1}}成功消失,被新的一个覆盖),因此您不会与之前的数据共享任何数据(并且成功的execve
不会返回,因为新程序已启动)。您的新程序以后可以更改虚拟地址空间,例如与mmap(2) ...
新虚拟地址空间中execve
个字符串的地址独立于argv
的参数地址;字符串内容是相同的。旧虚拟地址空间与新虚拟地址空间之间没有数据 共享,但新程序(和程序环境)的参数是复制。另请阅读ASLR
execve
的参数是字符串在新虚拟地址空间的新新调用堆栈上复制(推送其副本)以获取其启动函数(execve
在crt0中调用_start
)。当然,您不应main
任何free
我argv[
- undefined behavior。
因此,]
... int a; argv[1]=(char*)&a;
与execve
是未定义的行为,因为您无法保证argv
地址处的内存区域是正确的以null结尾的字符串。阅读endianness&amp; ABI
因此a
需要execve
终止正确字符串的数组NULL
(非任意指针),而另一个argv
终止{{1}字符串数组,每个字符串应以零字节结束。从旧地址空间复制到新地址空间的总内存空间有一个相当小的限制NULL
(通常为128K字节)通过env
&amp; ARG_MAX
。
您可能 使用共享内存(请参阅shm_overview(7))在各个进程之间共享内存(并且您将与信号量同步,请参阅sem_overview(7) ... );但是您经常更喜欢其他inter-process communication技术(例如pipe(7) - s,fifo(7) - s,socket(7) - s等等。)
顺便说一下,还可以使用strace(1)来了解您的计划涉及哪些系统调用,并使用proc(5),特别是通过运行argv
和env
{{ 1}} 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
。
请耐心等待,阅读此处的所有参考资料,并time了解有关POSIX编程的更多信息。研究一些free software源代码(例如在http://github.com/上,您可以选择一些有趣的项目......)并为它们做出贡献应该是值得的。