2013-04-30 95 views
-1

我正在虛擬機中運行程序。我正在執行一個循環,在某個時候,我調用了strcat。在一個數字(這個數字在不同的執行之間改變)之後,我收到了分段錯誤。strcat造成循環中的段錯誤

我試圖調試它:

(gdb) backtrace 

0 0x001a3d5d in strcat() from /lib/tls/i686/cmov/libc.so.6 

1 0x080493f4 in ChangetoDnsNameFormat (dns=0xbffef313 "", 
    host=0xbffff3b8 "a.com", '.' <repeats 195 times>...) at my_dns.c:378 

2 0x08048c96 in nreplacehost (
    host=0xbffff3b8 "a.com", '.' <repeats 195 times>..., query_type=1, 
    ip=0xbffff354 "3.3.3.3") at my_dns.c:179 

3 0x080489a1 in main (argc=774778414, argv=0xbffff4d4) at my_dns.c:106 

(gdb) frame 1 

1 0x080493f4 in ChangetoDnsNameFormat (dns=0xbffef313 "", 
    host=0xbffff3b8 "a.com", '.' <repeats 195 times>...) at my_dns.c:378 
378  strcat((char*)host,"."); 

(gdb) print host 

6 = (unsigned char *) 0xbffff3b8 "a.com", '.' <repeats 195 times>... 

任何提示嗎?

這是我稱之爲strcat的

void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host) 
{ 
    int lock = 0 , i; 
    strcat((char*)host,"."); 

    for(i = 0 ; i < strlen((char*)host) ; i++) 
    { 
     if(host[i]=='.') 
     { 
      *dns++ = i-lock; 
      for(;lock<i;lock++) 
      { 
       *dns++=host[lock]; 
      } 
      lock++; //or lock=i+1; 
     } 
    } 
    *dns++='\0'; 
} 

這個函數調用成功的1000倍以上的功能。

+2

我們可以看到ChangetoDnsNameFormat嗎?它可能有幫助 – lucasg 2013-04-30 07:12:52

+0

在這些情況下通常會出錯的地方在於你寫過數據結構的末尾。前兩次你很幸運,那個結構之後的內存仍然在你的地址空間中,但是在某些時候你寫的超出了進程本身的地址空間,那就是當內核用SIGSEGV敲你時。 – izak 2013-04-30 07:19:55

+1

你爲'host'分配了多少空間? – sapi 2013-04-30 07:21:05

回答

2
char * strcat (char * destination, const char * source); 

當調用strcat,所述source將被附加到destination串(的destination終止空字符將通過source第一個字符等所取代)。 destination必須有足夠的分配空間來包含連接的字符串。還要注意的是,sourcedestination必須以空終止的字符串

關於你的代碼

void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host) { 
    strcat((char*)host,".") 

由於您使用的參數host存儲連接字符串,則必須確保調用ChangetoDnsNameFormathostnull-terminated string並含有足夠分配的內存來存儲額外.前。

記住strcat((char*)host,".")等同於:

host[strlen((char*)host)] = '.'; 
host[strlen((char*)host)+1] = '\0'; 

這使得需要足夠大,空結尾的字符串比較明確。

回溯建議你要麼調用ChangetoDnsNameFormat不分配您的結尾點所需的空間,或者你缺少終止空字符hostdns

寫入未分配的內存位置是undefined behavior,因此它可能立即崩潰或不立即崩潰。如果它工作1000次並在第1001次時導致段錯誤,這並不令人驚訝

+0

更糟糕的是:「a.com」是*字符串常數*,根本不可寫。 – wildplasser 2013-04-30 10:58:06

+0

@wildplasser是的,這不是最相關的例子 – zakinster 2013-04-30 11:45:45

+0

主機被定義爲unsigned char [200]並且是scanf-ed,所以我想它沒有問題,並且dns是一個無符號字符*賦值如下:dns =(unsigned char *)&buf [sizeof(struct DNS_HEADER)],其中buf是一個無符號字符[65536]。我沒有看到內存問題。 – user2333227 2013-04-30 16:43:10

1

Strcat()追加到字符串的末尾。如果你一直調用它,而不檢查是否有空間添加你正在添加的素材,那麼你最終會跑掉字符串的末尾。在字符串末尾運行得足夠遠,並且您可能會到達進程地址空間的末尾;操作系統會向你發送一個SIGSEGV。

通過上面的gdb trace的外觀,你正在添加「。」。反覆發生,直到發生。你沒有給我足夠的代碼來確定你到底是什麼類型的編碼錯誤。

1

如果您繼續追加到字符串的末尾,您將超出緩衝區的大小,因此可能會導致段錯誤。

0

更重要的是,你似乎根本不需要strcat()。只要改變strlen((char*)host)strlen((char*)host) + 1(或計算一次,並存儲在一個局部變量爲C strlen需要遍歷整個字符串),並更改如果條件來

if(host[i]=='.' || host[i]=='\0') 

對待像字符串的結尾點你現在不再需要追加。

0
#include <stdio.h> 
#include <string.h> 

void my_change(char* dns, char* host); 
void hexdump(char *src, size_t len); 

    /* function which does exactly the same as 
    ** ChangetoDnsNameFormat() but without strcat() 
    ** or enormous amounts of strlen() calls 
    ** the caller should take care that 
    ** *) dns is at least one byte larger than host 
    ** *) host is properly terminated. 
    */ 
void my_change(char *dns, char *host) 
{ 
unsigned char *dst = (unsigned char*) dns 
     , *src = (unsigned char*) host 
     , *tick; 

for (tick=dst++; *dst = *src++; dst++) { 
     if (*dst == '.') { *tick = (dst-tick-1); tick = dst; } 
     } 
*tick = (dst-tick-1); 
} 

void hexdump(char *src, size_t len) 
{ 
size_t idx; 
for (idx =0; idx < len; idx++) { 
     fprintf(stderr, " %2x", src[idx] % 0xff); 
     } 
fputc('\n', stderr); 
} 


/* And test it ... */ 

int main (void) 
{ 

char source[] = "www.stackoverflow.com"; 
char target[1+sizeof source] = ""; 

my_change(target, source); 

printf("Source:%s\n", source); 
hexdump(source, strlen(source)); 

printf("Myname:%s\n", target); 
hexdump(target, strlen(target)); 

return 0; 
}