linux c clone 的栈空间大小最小为16字节 (linux 64bit)

背景

想在一个进程里面调用system(),但是它会继承文件句柄,内存映射等,还是同步调用,不太适合。因此想要一个轻量级的异步system。

clone()是在C语言库中定义的一个封装函数,它负责建立心轻量级进程的堆栈并且对编程者隐藏的clone()系统调用。实现clone()系统调用 的sys_clone()服务例程没有fn和arg参数。实际上,封装函数把fn指针存放在子进程堆栈的某个位置处,该位置就是该封装函数本身返回地址存 放的位置。arg指针正好存放在子进程堆栈中fn的下面。当封装函数结束时,CPU从堆栈中取出返回地址,然后执行fn(arg)函数。

采用clone+execvp的方式。

问题

clone(fn, stack_top, flags, arg, ...) 栈空间大小应该为多少呢?

调查

网上有很多通过malloc好几兆的内存,从进程监控器看 分配在父进程空间。何时释放分配的内存说法不一。

我的结论

只要父进程的16字节栈空间即可;小于这个值会coredump,只在ubuntu 18.04 (gcc 7.3.0)上测试了。

测试代码


#define _GNU_SOURCE //clone
#include  //clone
#include  //SIGCHILD
#include  //waitpid need flag SIGCHILD
#include  //getpid
#include 
#include 
#include 
#include 

int var = 0;

char* dump_stack(unsigned char *stk, int size) {
	static char buf[128];
	int i;

	char *ptr = buf, *end = buf+sizeof(buf)-1;
	for (i = 0; i < size && ptr < end; ++i) {
		ptr += snprintf(ptr, end-ptr, "%02x ", stk[i]);
	}
	*end = 0;
	
	return buf;
}

int fn(void *arg) {
	char buf[128] = "";
	var = 2; //alloc mem page on-write
	printf("in fn: pid %u var %d dump stack %p:\n%s==\n", getpid(),  var,
		   arg, dump_stack((unsigned char*)arg, 16)); //arg point to different physical mem addr

	char* argv[] = {"-ah",  "-l", "--color=auto", NULL};
	//execvp("ls",  argv );
	return 0;
}

int main() {
	const int stk_size = 16;  //minimal stack space to  run fn(arg)
	char stack[stk_size];
	memset(stack, 0, stk_size);

	//clone(fn, stack_top, flags, arg, ...)
	#if 1
	char *arg = "aa";
	int child_pid = clone(fn,
						  stack+stk_size,
						  SIGCHLD,
						  stack);
	#else
	int child_pid = clone((int (*)(void *))system,
						  stack+stk_size,
						  SIGCHLD,
						  "ls");
	#endif
 
	
	printf("child pid %u (%s) dump stack %p:\n%s==\n", child_pid,  strerror(errno),
		   stack, dump_stack(stack, stk_size)); //parent process see the changed stack contents.

	int status = 0;
	pid_t pid = 0;

	pid = waitpid(-1,  &status, 0); //wait some child finish

	printf("main pid %u  chid pid %u var %d\n", getpid(), pid,  var);	
}

/*
(gdb) x /16xb stack
0x7fffffffde60:	0x7a	0x48	0x55	0x55	0x55	0x55	0x00	0x00
0x7fffffffde68:	0x0e	0x4b	0x55	0x55	0x55	0x55	0x00	0x00
(gdb) p fn
$2 = {int (void *)} 0x55555555487a 
(gdb) p arg
$3 = 0x555555554b0e "aa"
*/

 

你可能感兴趣的:(C,标准库,system)