2016-08-21 2 views
1

Я пытаюсь распечатать строку переменной длины. Когда я печатаю строку с помощью printf или в файле журнала, строка печатается в порядке. Другая проблема заключается в том, что я вижу крах только на какой-то машине, где один и тот же тест отлично работает в другом. Я действительно смущен, почему.Ошибка Seg при попытке распечатать строку

EDIT: полный рабочий код, который вызывает сбой, я вставляю ниже. Crash с Centos 6.3 и Centos 6.5. Крэш не видел в CentOS 5

#include <stdio.h> 
#include <stdarg.h> 
#include <stdint.h> 
#include <sys/time.h> 
#include <time.h> 

typedef struct { 
    uint64_t total_bytes_sent; 
    uint64_t total_bytes_received; 
    uint64_t total_blocks_sent; 
    uint64_t total_blocks_received; 
    uint64_t total_commands_sent; 
    uint64_t total_commands_received; 
    uint64_t time_to_process_data; 
    char  mark_sent_time[64]; 
    char  mark_received_time[64]; 
} csperf_stats_t; 

void 
csperf_stats_printf(const char *format, ...) 
{ 
    /* Write to file */ 
    va_list args; 

    /* Write to stdout */ 
    va_start(args, format); 
    vfprintf(stdout, format, args); 
    va_end(args); 
} 

void 
ansperf_stats_display(csperf_stats_t *stats) 
{ 
    if (!stats) { 
     return; 
    } 

    stats->total_blocks_sent = 1000; 
    stats->total_blocks_received = 2000; 
    stats->time_to_process_data = 22; 

    csperf_stats_printf("%3d %15s %10s %10zu %10zu %10zu  %10s " 
      "%10s\n\n", 
       0, "hi", "testing.", 
      stats->total_blocks_sent, stats->total_blocks_received, 
      stats->time_to_process_data, 
      "crash", "test"); 
} 

/* Get time in millisecond */ 
uint64_t 
csperf_network_get_time(char *buf) 
{ 
    char   fmt[64]; 
    struct tm  *tm; 
    struct timeval tv; 
    uint64_t s; 

    gettimeofday(&tv, NULL); 

    if (buf) { 
     if((tm = localtime(&tv.tv_sec)) != NULL) { 
      strftime(fmt, sizeof(fmt), "%Y-%m-%d %H:%M:%S.%03u", tm); 
      snprintf(buf, sizeof(fmt), fmt, tv.tv_usec); 
     } 
    } 
    s = tv.tv_sec * 1000LL; 
    return(s + tv.tv_usec/1000LL); 
} 

int main() 
{ 
    csperf_stats_t stats = { 0 }; 
    csperf_network_get_time(stats.mark_sent_time); 
    csperf_network_get_time(stats.mark_received_time); 
    printf("%s%s\n", stats.mark_sent_time, stats.mark_received_time); 
    ansperf_stats_display(&stats); 
} 

Ниже приведен фрагмент кода, где происходит сбой.

Это сбой в vfprintf(), когда он пытается распечатать статистику -> mark_sent_time, stats-> mark_received_time. когда я печатаю строку в gdb, она не жалуется.

void 
csperf_stats_printf(FILE *fd, const char *format, ...) 
{ 
    /* Write to file */ 
    va_list args; 

    va_start(args, format); 
    if (fd) { 
     vfprintf(fd, format, args); 
    } 
    va_end(args); 

    /* Write to stdout */ 
    va_start(args, format); 
    vfprintf(stdout, format, args); 
    va_end(args); 
} 

void 
ansperf_stats_display(csperf_stats_t *stats, FILE *fd) 
{ 
    static int header_displayed = 0; 
    static int cycle = 0; 
    char total_bytes_sent_str[50]; 
    char total_bytes_recv_str[50]; 

    if (!stats) { 
     return; 
    } 

    if (!header_displayed) { 
     csperf_stats_printf(fd, "%s%s", header, seperator_line); 
     header_displayed = 1; 
    } 

    csperf_common_calculate_size(total_bytes_sent_str, 
      stats->total_bytes_sent); 
    csperf_common_calculate_size(total_bytes_recv_str, 
      stats->total_bytes_received); 

    csperf_stats_printf(fd, "%3d %15s %10s %10zu %10zu %10zu  %10s " 
      "%10s\n\n", ++cycle, 
      total_bytes_sent_str, total_bytes_recv_str, 
      stats->total_blocks_sent, stats->total_blocks_received, 
      stats->time_to_process_data, 
      stats->mark_sent_time, stats->mark_received_time); 
} 

Это то, что GDB показывает

(gdb) p stats->mark_sent_time 
No symbol "stats" in current context. 
(gdb) f 2 
#2 0x08051f56 in ansperf_stats_display (stats=0x892ded4, fd=0x892e888) at /home/nikhil/csperf/src/csperf_stats.c:55 
55   csperf_stats_printf(fd, "%3d %15s %10s %10zu %10zu %10zu  %100s " 
(gdb) p stats->mark_sent_time 
$1 = "20160821 21325800007", '\000' <repeats 79 times> 
(gdb) p stats->mark_recei9ved_time 
There is no member named mark_recei9ved_time. 
(gdb) p stats->mark_received_time 
$2 = "20160821 21325800007", '\000' <repeats 79 times> 

Строка представляет собой массив из 100 байт следующим образом

char  mark_sent_time[100]; 
char  mark_received_time[100]; 

Он устанавливается так:

command->echo_timestamp = csperf_network_get_time(
     client->stats.mark_sent_time); 

Эта функция копирует метку времени в полосу г "mark_sent_time"

uint64_t 
csperf_network_get_time(char *buf) 
{ 
    char   fmt[64]; 
    struct tm  *tm; 
    struct timeval tv; 
    uint64_t s; 

    gettimeofday(&tv, NULL); 

    if (buf) { 
     if((tm = localtime(&tv.tv_sec)) != NULL) { 
      strftime(fmt, sizeof(fmt), "%Y-%m-%d %H:%M:%S.%03u", tm); 
      snprintf(buf, sizeof(fmt), fmt, tv.tv_usec); 
     } 
    } 
    s = tv.tv_sec * 1000LL; 
    return(s + tv.tv_usec/1000LL); 
} 

Backtrace:

(gdb) bt 
#0 0x002b535e in _IO_vfprintf_internal (s=Cannot access memory at address 0xffffffff 
) at vfprintf.c:1603 
#1 0x08051de7 in csperf_stats_printf (fd=0x892e888, format=0x8079a6c "%3d %15s %10s %10zu %10zu %10zu  %100s %100s \n\n") at /home/nikhil/csperf/src/csperf_stats.c:23 
#2 0x08051f56 in ansperf_stats_display (stats=0x892ded4, fd=0x892e888) at /home/nikhil/csperf/src/csperf_stats.c:55 

#3 0x08050ad3 in csperf_client_shutdown (client=0x892deb0) at /home/nikhil/csperf/src/csperf_client.c:67 

Что мне не хватает?

+1

Можете ли вы дать нам достаточно кода, чтобы воспроизвести проблему? Возможно, 'ФАЙЛ *' недействителен. –

+0

Я удалил код, который печатает его в файл, но он сбой в следующем vprintf при попытке печати на stdout – Nikhil

+0

Если бы я мог сам повторить этот тест, возможно, я выясню проблему. –

ответ

2

Проблема заключается в использовании вами %zu для отображения переменной uint64_t в вашей строке формата.

На 64-битной цели это нормально %zu для size_t и (по крайней мере, на моей 64-разрядной системе) это 64-разрядная. Однако в 32-битной системе (по крайней мере для меня) size_t 32-битный, но переменная uint64_t по-прежнему помещает 64 бита в структуру va_list. %zu потребляет только 32 бита, и это оставляет 32-битное значение в va_list, которое используется вместо следующего параметра.

Замените использование "%zu" на "%" PRIu64, когда вы печатаете переменную uint64_t (как минимум 3 места в вашем примере).

Для того, чтобы получить доступ к PRIu64, может потребоваться включить заголовок <inttypes.h>.

.... И как я уже говорил в комментарии, я не думаю, что это:

strftime(fmt, sizeof(fmt), "%Y-%m-%d %H:%M:%S.%03u", tm); 
snprintf(buf, sizeof(fmt), fmt, tv.tv_usec); 

делает то, что вы ожидаете.Я думаю, что вы, вероятно, хотите %03u в strftime линии переносятся в snprintf линию, чтобы потреблять tv.tv_usec, однако %u для strftime это день недели, как цифры, вы, вероятно, следует использовать %%03u в strftime вызова, то ваш fmt для snprintf будет содержать только %03u.

Смежные вопросы