コードに適切なエラー処理を実装することが重要です。次の 2 つのコードを比較してください。
A:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#define BUFSIZE 1024
int incr=0;
int loop=1;
void runTicks(const char *n) {
time_t t;
char buf[BUFSIZE+1];
pid_t pid;
int counter;
pid=getpid();
counter=0;
while(loop) {
sleep(1);
t=time(NULL);
strftime(buf,BUFSIZE,"%Y.%m.%d %H:%M:%S",localtime(&t));
printf("%s[%d] %s\n",n,pid,buf);
counter+=incr;
if(counter>5) memcpy((void *)1,buf,1); /* this line is for causing SEGV */
}
}
void handler(int s) {
if(s==SIGCHLD) {
printf("Received SIGCHLD\n");
loop=0;
}
}
void setHandler() {
struct sigaction sa;
sa.sa_handler=handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags=SA_NOCLDSTOP;
if(sigaction(SIGCHLD,&sa,NULL)!=0) {
printf("Cannot set signal handler, there is no purpose in running the test\n");
exit(0);
}
}
int main() {
pid_t pid;
printf("start\n");
pid=fork();
if(pid==-1) {
printf("fork failed\n");
exit(10);
}
if(pid==0) {
printf("child\n");
incr=1;
usleep(500000);
runTicks("C");
exit(1);
} else {
printf("parent spawned child pid=%d\n",pid);
setHandler();
runTicks("P");
exit(0);
}
}
B:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#define BUFSIZE 1024
int incr=0;
int loop=1;
void runTicks(const char *n) {
time_t t;
char buf[BUFSIZE+1];
pid_t pid;
int counter;
pid=getpid();
counter=0;
while(loop) {
sleep(1);
t=time(NULL);
strftime(buf,BUFSIZE,"%Y.%m.%d %H:%M:%S",localtime(&t));
printf("%s[%d] %s\n",n,pid,buf);
counter+=incr;
if(counter>5) memcpy((void *)1,buf,1); /* this line is for causing SEGV */
}
}
void handler(int s) {
if(s==SIGCHLD) {
int status;
printf("Received SIGCHLD\n");
wait(&status);
printf("Exit code from child: %d\n",status);
if(status!=0) exit(status);
loop=0;
}
}
void setHandler() {
struct sigaction sa;
sa.sa_handler=handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags=SA_NOCLDSTOP;
if(sigaction(SIGCHLD,&sa,NULL)!=0) {
printf("Cannot set signal handler, there is no purpose in running the test\n");
exit(0);
}
}
int main() {
pid_t pid;
printf("start\n");
pid=fork();
if(pid==-1) {
printf("fork failed\n");
exit(10);
}
if(pid==0) {
printf("child\n");
incr=1;
usleep(500000);
runTicks("C");
exit(1);
} else {
printf("parent spawned child pid=%d\n",pid);
setHandler();
runTicks("P");
exit(0);
}
}
最初に valgrind なしでそれらを実行し、両方のプログラムの終了コードを比較します。次に、それらを valgrind で実行して楽しんでください。
このような構造を使用すると、子プロセスからのセグメンテーション違反をキャッチするために、valgrind の下で実行する必要さえありません。