vfprintf()抛出SegFault - 但输入定义明确?

时间:2014-11-25 12:10:09

标签: c

我在程序中获得以下功能:

void log(char* arg1, ...)
{
    time_t      t;
    struct tm   *tm;
    va_list     args;
    char        *fmt;
    char        curtime[TIME_STR_SIZE];
    FILE        *fd;

    va_start(args, arg1); // linux stdarg va_start req 2 args - va_lilst, parm_n


    fmt = va_arg(args, char*);

    if (lfd == NULL)
        fd = stderr;
    else
        fd = lfd;

   (void) time(&t);
   tm = localtime(&t);

   sprintf(curtime, "%02d.%02d.%d, %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec);

    fprintf(fd, "%s: ", curtime);
    vfprintf(fd, arg1, args);
    fprintf(fd, "\n");
    fflush(fd);

    va_end(args);
}

显然它需要一个输入参数列表并将它们写入文件。

但运行这部分代码会引发一个分段错误,我已经回溯到vfprintf:

(gdb) backtrace
#0  0x00007ffff4799db2 in __strlen_sse2 () from /lib64/libc.so.6
#1  0x00007ffff476220d in vfprintf () from /lib64/libc.so.6
#2  0x0000000000401b03 in log (arg1=0x40529d "%s gestartet: PID = %d") at logging.c:73
#3  0x00000000004045d4 in main (argc=10, argv=0x7fffffffdc98) at abgleich.c:589

运行gdb并打印参数时很好:

(gdb) print fd
$9 = (FILE *) 0x607010
(gdb) print fmt
$10 = 0x7fffffffe1a7 "/srv/workspace/abgleich/abgleich"
(gdb) print args
$11 = {{gp_offset = 16, fp_offset = 48, overflow_arg_area = 0x7fffffffda10, reg_save_area = 0x7fffffffd950}}

我很好奇为什么会抛出分段错误,因为它在这种情况下看起来是一个明确定义的输入。

该功能的调用部分如下:

log("%s gestartet: PID = %d", argv[0], getpid());

编辑:

我已按以下方式使用va_copy重写:

 va_start(args, arg1); // linux stdarg va_start req 2 args - va_lilst, parm_n
 va_copy(c_args, args);

 if (lfd == NULL)
     fd = stderr;
 else
     fd = lfd;

(void) time(&t);
tm = localtime(&t);

 /* strftime(curtime, TIME_STR_SIZE, "%d.%m.%y, %H:%M:%S\0", time_ptr); */
sprintf(curtime, "%02d.%02d.%d, %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
 fprintf(fd, "%s: ", curtime);
 vfprintf(fd, arg1, c_args);
 fprintf(fd, "\n");
 fflush(fd);

 va_end(args);

1 个答案:

答案 0 :(得分:3)

使用va_arg()"功能"在从va_list获得的va_start()上,va_list被修改,因此当传递给另一个函数时,它与您在开始时的不同。您可以将va_list视为指针,使用va_arg()就像增量运算符(++)。你可以这样称呼你的函数:

log("%s gestartet: PID = %d", argv[0], getpid());

但是vfprint很可能会这样看:

vfprintf(fd, "%s gestartet: PID = %d", /* argv[0], <-- REMOVED */ getpid());