strcat导致循环中的分段错误

时间:2013-04-30 07:11:08

标签: c loops segmentation-fault

我正在虚拟机中运行程序。我正在执行一个循环,在某些时候,我调用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次。

5 个答案:

答案 0 :(得分:2)

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

当您致电strcat时,source将附加到destination字符串(destination的终止空字符将被{{的第一个字符替换1}}等等)。 source必须有足够的分配空间才能包含连接字符串。另请注意, destinationsource必须是以空字符结尾的字符串

关于您的代码

destination

由于您使用参数void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host) { strcat((char*)host,".") 来存储连接字符串,因此必须在调用host之前确保ChangetoDnsNameFormatnull-terminated string并且包含足够的已分配内存来存储额外的host

请注意,.相当于:

strcat((char*)host,".")

这使得需要一个足够大的,以null结尾的字符串非常明确。

您的回溯表示您要么调用host[strlen((char*)host)] = '.'; host[strlen((char*)host)+1] = '\0'; 而没有分配尾随点所需的空间,要么您错过ChangetoDnsNameFormat或{{{}}中的终止空字符1}}。

写入未分配的内存位置为undefined behavior,因此它可能会立即崩溃,也可能不会立即崩溃。如果它工作1000次并在第1001次导致段错误就不足为奇了

答案 1 :(得分:1)

Strcat()附加到字符串的末尾。如果你继续调用它,而不检查你正在添加的材料是否有空间,你最终会在字符串的末尾运行。在字符串的末尾运行足够远,你可能会到达进程的地址空间的末尾;然后,操作系统将向您发送SIGSEGV。

通过上面gdb跟踪的外观,您正在添加“。”反复发生这种情况。您没有为我显示足够的代码来确定到目前为止哪种编码错误。

答案 2 :(得分:1)

如果继续追加到字符串的末尾,则会超出缓冲区的大小,从而可能导致分段错误。

答案 3 :(得分:0)

更重要的是,您似乎根本不需要strcat()。只需将strlen((char*)host)更改为strlen((char*)host) + 1(或计算一次并存储在局部变量中,因为C strlen需要迭代整个字符串)并将if条件更改为

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

将字符串的结尾视为您现在不再需要追加的点。

答案 4 :(得分: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;
}