2016-08-21 3 views
1

가변 길이 문자열을 인쇄하려고하면 세그먼테이션 오류가 발생합니다. printf 또는 로그 파일에서 문자열을 인쇄하면 문자열이 제대로 인쇄됩니다. 또 다른 문제는 동일한 테스트가 다른 시스템에서 제대로 작동하는 일부 시스템에서만 충돌이 발생한다는 것입니다. 나는 정말로 왜 혼란 스럽다.문자열을 인쇄하려고 할 때 Seg 오류가 발생했습니다.

편집 : 충돌을 일으키는 완전한 작업 코드 아래에 붙여 넣습니다. 충돌은 Centos 6.3 및 Centos 6.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); 
} 

를 CentOS 5에 보이지 않는 것은 충돌하는 코드이다.

stats-> mark_sent_time, stats-> mark_received_time을 인쇄하려고 할 때 vfprintf()에서 충돌이 발생합니다. gdb에 문자열을 출력 할 때 불평하지 않습니다.

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

:

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가

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

그것은 이렇게 설정된 다음

(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 바이트의 배열 도시 무엇 이 함수는 타임 스탬프를 strin에 복사합니다. g "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); 
} 

역 추적 :

(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

문제를 재현 할 수있는 충분한 코드를 제공해 주시겠습니까? 어쩌면'FILE * '이 유효하지 않을 수도 있습니다. –

+0

파일에 인쇄하는 코드를 제거했지만 표준 출력으로 인쇄하려고 할 때 다음 vprintf에서 충돌합니다. – Nikhil

+0

해당 테스트를 직접 복제 할 수 있다면 문제를 파악할 수 있습니다. –

답변

2

%zu을 사용하면 형식 문자열에 uint64_t 변수가 표시됩니다.

대상이 64 비트인데 %zusize_t이고 (적어도 내 64 비트 시스템에서는)이 64 비트입니다. 그러나 32 비트 시스템에서 (적어도 나를 위해) size_t은 32 비트이지만 uint64_t 변수는 여전히 va_list 구조에 64 비트를 배치합니다. %zu은 32 비트 만 사용하므로 다음 매개 변수 대신 사용되는 va_list에 32 비트 값이 남습니다.

"%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); 

당신이 무엇을 기대하고있다.나는 당신이 아마 그러나 strftime에 대한 %u, 당신은 아마 그런 다음, strftime 전화에 fmt%%03u를 사용해야 숫자로 일주일의 하루는 tv.tv_usec 소비하는 snprintf 라인으로 이월하는 strftime 라인에 %03u를 원하는 생각 snprintf의 경우에는 %03u 만 포함됩니다.

관련 문제