2013/01/08(火)sigprocmaskの検証

Linux実装は pthread*のマスクと sigprocmask()とは同じって書いてた。。
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>

#define gettid() syscall(SYS_gettid)

// 0: sigprocmask at process, 1:thr1, 
#define DF_CHGMASK_ID 2
//#define DF_USE_PTHREADMASK
//#define DF_INITIAL_MASK (SIGSEGV)
//#define DF_INITIAL_MASK (SIGABRT)
#define DF_INITIAL_MASK (12)


void abt_handler(int n, siginfo_t *pSigInf, void *pContext)
{
struct sigaction sa;

	printf("I am dead...[%d][parent:%d][tid=%d][thread_id=%ld]", getpid(), getppid(), gettid(), (long)pthread_self());
	memset(&sa,0,sizeof(struct sigaction));
//_exit(1);
	sigemptyset(&sa.sa_mask);
//	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_handler = SIG_DFL;
//	sigaction(SIGABRT,&sa,NULL);
//	raise(SIGABRT);
}

void register_handler()
{
struct sigaction sa;

	memset(&sa,0,sizeof(struct sigaction));
	sigemptyset(&sa.sa_mask);
	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_sigaction = abt_handler;
//	sigaction(SIGABRT,&sa,NULL);
	sigaction( 12,&sa,NULL);
}


struct st_signals_st {
	int signo;
	const char *pcSignal ;
	} st_signals[] = {
			{SIGHUP,    "SIGHUP"},
			{SIGINT,    "SIGINT"},
			{SIGQUIT,   "SIGQUIT"},
			{SIGILL,    "SIGILL"},
			{SIGTRAP,   "SIGTRAP"},
			{SIGABRT,   "SIGABRT"},
			{SIGIOT,    "SIGIOT"},
			{SIGBUS,    "SIGBUS"},
			{SIGFPE,    "SIGFPE"},
			{SIGKILL,   "SIGKILL"},
			{SIGUSR1,   "SIGUSR1"},
			{SIGSEGV,   "SIGSEGV"},
			{SIGUSR2,   "SIGUSR2"},
			{SIGPIPE,   "SIGPIPE"},
			{SIGALRM,   "SIGALRM"},
			{SIGTERM,   "SIGTERM"},
			{SIGSTKFLT, "SIGSTKFLT"},
			{SIGCHLD,   "SIGCHLD"},
			{SIGCONT,   "SIGCONT"},
			{SIGSTOP,   "SIGSTOP"},
			{SIGTSTP,   "SIGTSTP"},
			{SIGTTIN,   "SIGTTIN"},
			{SIGTTOU,   "SIGTTOU"},
			{SIGURG,    "SIGURG"},
			{SIGXCPU,   "SIGXCPU"},
			{SIGXFSZ,   "SIGXFSZ"},
			{SIGVTALRM, "SIGVTALRM"},
			{SIGPROF,   "SIGPROF"},
			{SIGWINCH,  "SIGWINCH"},
			{SIGIO,     "SIGIO"},
			{SIGPOLL,   "SIGPOLL"},
			{SIGPWR,    "SIGPWR"},
			{SIGSYS,    "SIGSYS"},
			{0, NULL}
		} ;

void dump_sigmask(const char* pMsg, sigset_t* sig_mask)
{
struct st_signals_st* pStSignal = st_signals ;
int i;
	puts(pMsg);
	while( pStSignal->pcSignal ){
		if (sigismember( sig_mask, pStSignal->signo )) {
			putchar('1');
		}
		else {
			putchar('0');
		}
		pStSignal++;
	}
	putchar('_');
	for (i=SIGRTMIN; i<=SIGRTMAX; i++) {
		if (sigismember( sig_mask, i )) {
			putchar('1');
		}
		else {
			putchar('0');
		}
	}
	puts("");
return ;
}


void* thr1(void* arg)
{
sigset_t sig_mask ;

	sleep(1);
printf("[%d/ppid=%d/tid=%d/self=%ld] wakeup thr1!\n", getpid(), getppid(), gettid(), (long)pthread_self());
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);

#if (DF_CHGMASK_ID==1)
	sigfillset(&sig_mask);
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
#endif
		perror ("main(): failure set...");
	}
#endif
	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);

#if (DF_CHGMASK_ID==1)
	sigemptyset(&sig_mask);
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
#endif
		perror ("main(): failure set...");
	}
#endif
	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);
	sleep(10);
}

void* thr2(void* arg)
{
sigset_t sig_mask ;

	register_handler();
//	sigaddset(&sig_mask, DF_INITIAL_MASK) ;

	sigemptyset(&sig_mask);
	sigaddset(&sig_mask, 12) ;
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) {
#endif
		perror ("thr2(): Dead set...");
	}


	sleep(2);
printf("[%d/ppid=%d/tid=%d/self=%ld] wakeup thr2!\n", getpid(), getppid(), gettid(), (long)pthread_self());
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	system("echo thr2 is spawn $$ ; sleep 17");

	sleep(3);
}



int
main(int argc, char *argv[])
{
int status=0;
int fd;
pthread_t child[2];
sigset_t sig_mask ;

	sigfillset(&sig_mask);
	if (sigprocmask(SIG_BLOCK, &sig_mask, NULL)) {
		perror ("main(): Dead set...");
	}
/*
	sigaddset(&sig_mask, DF_INITIAL_MASK) ;
	if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) {
		perror ("main(): Dead set...");
	}
*/
//	register_handler();

	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);



/* スレッド生成 */
	pthread_create(&child[0], NULL, thr1, NULL );
	pthread_create(&child[1], NULL, thr2, NULL );

	sleep(4);	

#if (DF_CHGMASK_ID==0)
	sigemptyset(&sig_mask);
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
		perror ("main(): failure set...");
	}
#endif
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	sleep(4);	

#if (DF_CHGMASK_ID==0)
	sigfillset(&sig_mask);
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
		perror ("main(): failure set...");
	}
#endif
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	sleep(4);	
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	status = pthread_join(child[0], NULL);
	if (status<0) {
		printf("pthread_join(0) returns: %d\n", status);
	}
	status = pthread_join(child[1], NULL);
	if (status<0) {
		printf("pthread_join(0) returns: %d\n", status);
	}
return 0;
}

2013/01/08(火)sigactionを触ってみる。

backtraceを取れるか確認する(PwerPC 32bitでのみ確認)

glibcに、backtrace()函数があって、便利だなぁ、と。
自分で書かなくて良いんだねぇ。組み込みRTOSで触ってた何か、は、スタックを手動で追っていたわ~。
コレも自動化しすぎて、スタックと思ったアドレスが別空間だとSIGSEGVでおちるけどな…
/*
 * sigaction sample program for powerpc32
 *  You can add more informations in segv_handler().
 *  In this fucntion, you have pointer of stacks, regs, contexts...
 *  If we can allow increase size of binary, we can continu using backtrace_symbols()/backtrace_symbols_fd().
 *  Please refer man-pages, info-pages and a lot of WEB-pages B)
 *
 * Author: 30/Aug./2012 YNK
 * NOTE: Don't use '=O2' because optimization makes no 'bl' instructions to call function.
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <execinfo.h>
#include <linux/sysctl.h>
#include <sys/ucontext.h>

int (*func_ptr)() = (void *)0x1234567;
int func1();
int func2();
void segv_handler(int n, siginfo_t *pSigInf, void *pContext);

int main(int argc,char ** argv)
{
struct sigaction sa;

	memset(&sa,0,sizeof(struct sigaction));
	sigemptyset(&sa.sa_mask);
	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_sigaction = segv_handler;
	sigaction(SIGSEGV,&sa,NULL);
	func1();
return 0;
}

int func1()
{
  func2();
return 0;
}

int func2()
{
  *(int*)0xBAD2DEAD = 2;
  func_ptr();
return 0;
}

void segv_handler(int n, siginfo_t *pSigInf, void *pContext)
{
int cnt, i;
void **arr = alloca(256 * sizeof(void *));
ucontext_t* pCon = (ucontext_t *)pContext;

	printf("*** segmentation fault! (No=%d)\n", n);
	printf("  An errno value: %d\n", pSigInf->si_errno );
	printf("  Signal code   : %d\n", pSigInf->si_code );
	printf("  access address  : %p\n", pSigInf->si_addr );

// struct defined in ptrace.h
	for(i=0;i<32;i++) {
		printf("GPRS%2d: 0x%08X\n", i, pCon->uc_mcontext.regs->gpr[i]);
	}
	printf("NIP=0x%08X  MSR=0x%08X\n", pCon->uc_mcontext.regs->nip, pCon->uc_mcontext.regs->msr );

	printf("\n\n *** backtrace address ***\n");
	cnt = backtrace(arr, 256);
	for(i=0;i<cnt;i++) {
		printf("\t%3d: 0x%08X\n", i, arr[i]);
	}
/* if included symbolx(compile with "-r dynamic") */
	backtrace_symbols_fd(arr, cnt, 2);

        abort();
}

[C]forkで子供を作る時の注意

2012/06/19Programming::Cimport

forkの動作

fork()を実行するプロセスのコピーを作る、とあります。
man pageの版によっては、glibcの特定バージョンから、clone()による実装に変わった*1とある。
そこには、ファイルデスクリプタもコピーされます。とあるではありませんか!。
ただし、0,1,2は一端クローズしてから開き直します、とありました。
これちょっとハマった気がするので、実際に検証してみましょう。
platformが異なりますが、とりあえずPC-Linux(VMですが)で検証です。

glibc 2.3.3 以降では、 NPTL スレッド実装の一部として提供されている glibc のfork() ラッパー関数は、 カーネルの fork() システムコールを起動するのではなく、clone(2) を起動する。 clone(2) に渡すフラグとして、伝統的な fork() システムコールと同じ効果が得られるようなフラグが指定される (fork() の呼び出しは、 flags に SIGCHLD だけを指定して clone(2) を呼び出すのと等価である)。 glibc のラッパー関数は pthread_atfork(3) を使って設定されている任意の fork ハンドラを起動する。
via http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/fork.2.html

*1 : 残念ながら、Cent-OS 5.7 patch非適用状態では、その文言がない。別途確認が必要→man page

確認コード例

少々長いですが、コードを貼り付けます。
エイヤっと作っているので、エラー処理とバッファ量などもテキトウです。

検証GCC version

gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-51)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

fork_exec.c

#include <stdio.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>


#define DEBUG_PRINT(fmt, ...)  \
        printf("%s(): "fmt, __func__, ## __VA_ARGS__)



const char* pExec_PG = "./infty.sh" ;

int proc_exec(char* argv[])
{
char* arg_nul[] = {NULL,} ;
int rc;

		DEBUG_PRINT( "%s\n", pExec_PG );
	if (argv == NULL) {
		rc = execvp( pExec_PG, arg_nul );
	}
	else {
		rc = execvp( pExec_PG, argv );
	}
return rc ;
}


int proc_dup(int* pid_child, char* argv[])
{
pid_t id;

	id = fork();
	if (id==-1) {	/* parent - error */
		DEBUG_PRINT( "%s", strerror(errno) );
	}
	else if( id==0 ) {	/* child - ok */
		DEBUG_PRINT( "created pid=%d, let's execv!", (int)getpid() );
		proc_exec( argv );
		// ここにはこないはず.
		DEBUG_PRINT( "Oops... Where is here ?" );
	}
	else {		/* parent - get child process */
		DEBUG_PRINT( "created success.\n");
	}
	if(pid_child)
		*pid_child = id ;
return id;
}

int main ( int argc, char*argv[])
{
int id1, id2 ;
int fd;
char buf[512];

	DEBUG_PRINT( "I am %d.\n", (int)getpid() );
	proc_dup(&id1,NULL);
	printf("create %d\n", id1);
	system("ps");
	sleep(5);

	fd = open("test", O_CREAT);
	if(fd<0) {
		printf("file open error");
	}

	proc_dup(&id2,NULL);
	system("ps");
	sleep(5);
	printf("create %d\n", id2);


	sprintf(buf, "lsof -c %d", (int)getpid());
	system(buf);

	sprintf(buf, "lsof -c %d", id1);
	system(buf);

	sprintf(buf, "lsof -c %d", id2);
	system(buf);

	close(fd);
	printf(" **** After close(fd) ****\n");
	sprintf(buf, "lsof -c %d", (int)getpid());
	system(buf);

	sprintf(buf, "lsof -c %d", id1);
	system(buf);

	sprintf(buf, "lsof -c %d", id2);
	system(buf);

	printf("run  kill %d %d  \n", id1, id2);
	sleep(60);
return 0;
}

infty.sh

#!/bin/sh
while true;
do
  lsof -p $$
  sleep 10;
done

実行結果

lsofコマンドを使っているので、特権ユーザで実行しましょう。
一般ユーザが使えるようなら、それでも構いません(自プロセスだけだから大丈夫かな?)
# ./fork_exe 
main(): I am 7630.
proc_dup(): created pid=7631, let's execv!proc_exec(): ./infty.sh
proc_dup(): created success.
create 7631
  PID TTY          TIME CMD
 7371 pts/0    00:00:00 su
 7374 pts/0    00:00:00 bash
 7630 pts/0    00:00:00 fork_exe
 7631 pts/0    00:00:00 infty.sh
 7632 pts/0    00:00:00 ps
 7633 pts/0    00:00:00 lsof
COMMAND   PID USER   FD   TYPE DEVICE     SIZE     NODE NAME
infty.sh 7631 root  cwd    DIR    8,3     4096  3110061 /home/yyy/tst_fork
infty.sh 7631 root  rtd    DIR    8,3     4096        2 /
infty.sh 7631 root  txt    REG    8,3   735804 13323587 /bin/bash
infty.sh 7631 root  mem    REG    8,3   129900  7791196 /lib/ld-2.5.so
infty.sh 7631 root  mem    REG    8,3  1693812  7791364 /lib/libc-2.5.so
infty.sh 7631 root  mem    REG    8,3    20668  7791420 /lib/libdl-2.5.so
infty.sh 7631 root  mem    REG    8,3    13084  7792317 /lib/libtermcap.so.2.0.8
infty.sh 7631 root  mem    REG    8,3    25462  8872255 /usr/lib/gconv/gconv-modules.cache
infty.sh 7631 root  mem    REG    8,3 56454576  8749247 /usr/lib/locale/locale-archive
infty.sh 7631 root    0u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root    1u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root    2u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root  255r   REG    8,3       55  3110065 /home/yyy/tst_fork/infty.sh
proc_dup(): created pid=7636, let's execv!proc_exec(): ./infty.sh
proc_dup(): created success.
  PID TTY          TIME CMD
 7371 pts/0    00:00:00 su
 7374 pts/0    00:00:00 bash
 7630 pts/0    00:00:00 fork_exe
 7631 pts/0    00:00:00 infty.sh
 7635 pts/0    00:00:00 sleep
 7636 pts/0    00:00:00 infty.sh
 7637 pts/0    00:00:00 ps
 7638 pts/0    00:00:00 lsof
COMMAND   PID USER   FD   TYPE DEVICE     SIZE     NODE NAME
infty.sh 7636 root  cwd    DIR    8,3     4096  3110061 /home/yyy/tst_fork
infty.sh 7636 root  rtd    DIR    8,3     4096        2 /
infty.sh 7636 root  txt    REG    8,3   735804 13323587 /bin/bash
infty.sh 7636 root  mem    REG    8,3   129900  7791196 /lib/ld-2.5.so
infty.sh 7636 root  mem    REG    8,3  1693812  7791364 /lib/libc-2.5.so
infty.sh 7636 root  mem    REG    8,3    20668  7791420 /lib/libdl-2.5.so
infty.sh 7636 root  mem    REG    8,3    13084  7792317 /lib/libtermcap.so.2.0.8
infty.sh 7636 root  mem    REG    8,3    25462  8872255 /usr/lib/gconv/gconv-modules.cache
infty.sh 7636 root  mem    REG    8,3 56454576  8749247 /usr/lib/locale/locale-archive
infty.sh 7636 root    0u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    1u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    2u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    3r   REG    8,3        0  3110063 /home/yyy/tst_fork/test
infty.sh 7636 root  255r   REG    8,3       55  3110065 /home/yyy/tst_fork/infty.sh
create 7636
COMMAND   PID USER   FD   TYPE DEVICE     SIZE     NODE NAME
infty.sh 7631 root  cwd    DIR    8,3     4096  3110061 /home/yyy/tst_fork
infty.sh 7631 root  rtd    DIR    8,3     4096        2 /
infty.sh 7631 root  txt    REG    8,3   735804 13323587 /bin/bash
infty.sh 7631 root  mem    REG    8,3   129900  7791196 /lib/ld-2.5.so
infty.sh 7631 root  mem    REG    8,3  1693812  7791364 /lib/libc-2.5.so
infty.sh 7631 root  mem    REG    8,3    20668  7791420 /lib/libdl-2.5.so
infty.sh 7631 root  mem    REG    8,3    13084  7792317 /lib/libtermcap.so.2.0.8
infty.sh 7631 root  mem    REG    8,3    25462  8872255 /usr/lib/gconv/gconv-modules.cache
infty.sh 7631 root  mem    REG    8,3 56454576  8749247 /usr/lib/locale/locale-archive
infty.sh 7631 root    0u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root    1u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root    2u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root  255r   REG    8,3       55  3110065 /home/yyy/tst_fork/infty.sh
 **** After close(fd) ****
run  kill 7631 7636  
COMMAND   PID USER   FD   TYPE DEVICE     SIZE     NODE NAME
infty.sh 7636 root  cwd    DIR    8,3     4096  3110061 /home/yyy/tst_fork
infty.sh 7636 root  rtd    DIR    8,3     4096        2 /
infty.sh 7636 root  txt    REG    8,3   735804 13323587 /bin/bash
infty.sh 7636 root  mem    REG    8,3   129900  7791196 /lib/ld-2.5.so
infty.sh 7636 root  mem    REG    8,3  1693812  7791364 /lib/libc-2.5.so
infty.sh 7636 root  mem    REG    8,3    20668  7791420 /lib/libdl-2.5.so
infty.sh 7636 root  mem    REG    8,3    13084  7792317 /lib/libtermcap.so.2.0.8
infty.sh 7636 root  mem    REG    8,3    25462  8872255 /usr/lib/gconv/gconv-modules.cache
infty.sh 7636 root  mem    REG    8,3 56454576  8749247 /usr/lib/locale/locale-archive
infty.sh 7636 root    0u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    1u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    2u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    3r   REG    8,3        0  3110063 /home/yyy/tst_fork/test
infty.sh 7636 root  255r   REG    8,3       55  3110065 /home/yyy/tst_fork/infty.sh
COMMAND   PID USER   FD   TYPE DEVICE     SIZE     NODE NAME
infty.sh 7631 root  cwd    DIR    8,3     4096  3110061 /home/yyy/tst_fork
infty.sh 7631 root  rtd    DIR    8,3     4096        2 /
infty.sh 7631 root  txt    REG    8,3   735804 13323587 /bin/bash
infty.sh 7631 root  mem    REG    8,3   129900  7791196 /lib/ld-2.5.so
infty.sh 7631 root  mem    REG    8,3  1693812  7791364 /lib/libc-2.5.so
infty.sh 7631 root  mem    REG    8,3    20668  7791420 /lib/libdl-2.5.so
infty.sh 7631 root  mem    REG    8,3    13084  7792317 /lib/libtermcap.so.2.0.8
infty.sh 7631 root  mem    REG    8,3    25462  8872255 /usr/lib/gconv/gconv-modules.cache
infty.sh 7631 root  mem    REG    8,3 56454576  8749247 /usr/lib/locale/locale-archive
infty.sh 7631 root    0u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root    1u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root    2u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root  255r   REG    8,3       55  3110065 /home/yyy/tst_fork/infty.sh
COMMAND   PID USER   FD   TYPE DEVICE     SIZE     NODE NAME
infty.sh 7636 root  cwd    DIR    8,3     4096  3110061 /home/yyy/tst_fork
infty.sh 7636 root  rtd    DIR    8,3     4096        2 /
infty.sh 7636 root  txt    REG    8,3   735804 13323587 /bin/bash
infty.sh 7636 root  mem    REG    8,3   129900  7791196 /lib/ld-2.5.so
infty.sh 7636 root  mem    REG    8,3  1693812  7791364 /lib/libc-2.5.so
infty.sh 7636 root  mem    REG    8,3    20668  7791420 /lib/libdl-2.5.so
infty.sh 7636 root  mem    REG    8,3    13084  7792317 /lib/libtermcap.so.2.0.8
infty.sh 7636 root  mem    REG    8,3    25462  8872255 /usr/lib/gconv/gconv-modules.cache
infty.sh 7636 root  mem    REG    8,3 56454576  8749247 /usr/lib/locale/locale-archive
infty.sh 7636 root    0u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    1u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    2u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    3r   REG    8,3        0  3110063 /home/yyy/tst_fork/test
infty.sh 7636 root  255r   REG    8,3       55  3110065 /home/yyy/tst_fork/infty.sh
COMMAND   PID USER   FD   TYPE DEVICE     SIZE     NODE NAME
infty.sh 7631 root  cwd    DIR    8,3     4096  3110061 /home/yyy/tst_fork
infty.sh 7631 root  rtd    DIR    8,3     4096        2 /
infty.sh 7631 root  txt    REG    8,3   735804 13323587 /bin/bash
infty.sh 7631 root  mem    REG    8,3   129900  7791196 /lib/ld-2.5.so
infty.sh 7631 root  mem    REG    8,3  1693812  7791364 /lib/libc-2.5.so
infty.sh 7631 root  mem    REG    8,3    20668  7791420 /lib/libdl-2.5.so
infty.sh 7631 root  mem    REG    8,3    13084  7792317 /lib/libtermcap.so.2.0.8
infty.sh 7631 root  mem    REG    8,3    25462  8872255 /usr/lib/gconv/gconv-modules.cache
infty.sh 7631 root  mem    REG    8,3 56454576  8749247 /usr/lib/locale/locale-archive
infty.sh 7631 root    0u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root    1u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root    2u   CHR  136,0                 2 /dev/pts/0
infty.sh 7631 root  255r   REG    8,3       55  3110065 /home/yyy/tst_fork/infty.sh
COMMAND   PID USER   FD   TYPE DEVICE     SIZE     NODE NAME
infty.sh 7636 root  cwd    DIR    8,3     4096  3110061 /home/yyy/tst_fork
infty.sh 7636 root  rtd    DIR    8,3     4096        2 /
infty.sh 7636 root  txt    REG    8,3   735804 13323587 /bin/bash
infty.sh 7636 root  mem    REG    8,3   129900  7791196 /lib/ld-2.5.so
infty.sh 7636 root  mem    REG    8,3  1693812  7791364 /lib/libc-2.5.so
infty.sh 7636 root  mem    REG    8,3    20668  7791420 /lib/libdl-2.5.so
infty.sh 7636 root  mem    REG    8,3    13084  7792317 /lib/libtermcap.so.2.0.8
infty.sh 7636 root  mem    REG    8,3    25462  8872255 /usr/lib/gconv/gconv-modules.cache
infty.sh 7636 root  mem    REG    8,3 56454576  8749247 /usr/lib/locale/locale-archive
infty.sh 7636 root    0u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    1u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    2u   CHR  136,0                 2 /dev/pts/0
infty.sh 7636 root    3r   REG    8,3        0  3110063 /home/yyy/tst_fork/test
infty.sh 7636 root  255r   REG    8,3       55  3110065 /home/yyy/tst_fork/infty.sh
'test'ファイルを、子プロセスが握っていることが見て取れます。
比較用に、open - close前後の状態を見せています。

対策

man 2 openによると
デフォルトでは、新しいファイルディスクリプタは execve(2) を実行した後もオープンされたままとなる (つまり、 fcntl(2) に説明がある FD_CLOEXEC ファイルディスクリプタフラグは最初は無効である; 後述の O_CLOEXEC フラグを使うとこのデフォルトを変更することができる)。
とあり、
O_CLOEXEC (Linux 2.6.23 以降)
新しいファイルディスクリプタに対して close-on-exec フラグを有効にする。 このフラグを指定することで、プログラムは FD_CLOEXEC フラグをセットするための fcntl(2) F_SETFD 操作を別途呼び出す必要がなくなる。また、ある種のマルチスレッドのプログラムはこのフラグの使用は 不可欠である。なぜなら、個別に FD_CLOEXEC フラグを設定する fcntl(2) F_SETFD 操作を呼び出したとしても、あるスレッドがファイルディスクリプタを オープンするのと同時に別のスレッドが fork(2) と execve(2) を実行するという競合条件を避けるのには十分ではないからである。
と、コレを使えというふうに読めますね。
これって、システム全体で、デフォルトで有効にしたい、とか、できないものなのか・・・。

関連事項

mutexなんかも気をつけないといけない話。
memologue

[C] malloc,vasprintf

2012/02/19Programming::Cimport
出直しLinux programming

malloc

mallocのman pageによると, 以下の記載があります.
とりあえず, vmさんがOOM killer発動しにくいようにしておいた方が良いでしょうね..
OOM killer自体も殺しておいた方が良いでしょう ;)
バグ
デフォルトでは、Linux は楽観的メモリ配置戦略を用いている。つまり、 malloc() が NULL でない値を返しても 、
そ のメモリが実際に利用可能であることが保証されない。これは本当にまずいバグである。システムがメモリ不足状
態になったとき、悪名高いメモリ不足解決器 (OOM killer) によって一つまたは複数のプロセスが削除される。突 然
あ るプロセスが削除されるのが望ましくない状況で使用されていて、しかもカーネルのバージョンが十分に最近のも
のであれば、このメモリを割り当て過ぎる動作 (overcommitting behavior) を以下のコマンドで無効にできる。
  # echo 2 > /proc/sys/vm/overcommit_memory
カーネルの付属文書の vm/overcommit-accounting と sysctl/vm.txt も参照のこと。

int vasprintf(char **strp, const char *fmt, va_list ap);

GNU拡張の関数。stdio.hで使える。
メモリ不足などのエラーは-1を返す。
strpにallocしてくれるのね、便利ですね。free()忘れないように。