1

自動テストに使用するために、bash スクリプトで valgrind を実行しています。エラー時に終了コードを返し、子をトレースするオプションを既に追加しました。

/usr/bin/valgrind --error-exitcode=1 --trace-children=yes ./test_prog

私のプログラムは他のプロセスをフォークし、端末でさまざまなプロセスを実行している valgrind の出力を確認できます。問題は、親プロセスにエラーがある場合にのみ終了コード オプションが機能するように見えることです。子プロセスの 1 つでエラー (SIGSEGV) が発生しても、valgrind の終了コードは 0 のままであるため、複数のプロセスの自動テストには使用できません。

親valgrindが子のエラーをキャッチして返すオプションはありますか?私はすでにマニュアルページを調べました。この問題には、子の出力を端末に grep してエラー メッセージを表示するなど、別の解決策があるのではないでしょうか?

前もって感謝します。

4

1 に答える 1

0

コードに適切なエラー処理を実装することが重要です。次の 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 の下で実行する必要さえありません。

于 2013-11-15T21:38:36.390 に答える