-1

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

4

5 回答 5

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

当您调用strcat时,source将被附加到destination字符串中(终止的空字符destination将被替换为的第一个字符,source依此类推)。destination必须有足够的分配空间来包含连接的字符串。另请注意,source和都destination必须是以空字符结尾的字符串

关于你的代码

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

由于您使用参数host来存储连接的字符串,因此在调用之前必须确保ChangetoDnsNameFormathost是一个以null 结尾的字符串并且包含足够的分配内存来存储额外的..

请记住,这strcat((char*)host,".")相当于:

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

这使得对足够大的、以 null 结尾的字符串的需求非常明确。

您的回溯表明您要么在调用时未分配尾随点所需的空间,要么在orChangetoDnsNameFormat中缺少终止空字符。hostdns

写入未分配的内存位置是未定义的行为,因此它可能会或可能不会立即崩溃。如果它工作 1000 次并在第 1001 次导致段错误,这并不奇怪

于 2013-04-30T07:21:34.243 回答
1

Strcat() 追加到字符串的末尾。如果您继续调用它,而不检查您要添加的材料是否有空间,您最终会跑出字符串的末尾。从字符串的末尾跑得足够远,您可能会到达进程地址空间的末尾;然后操作系统会向您发送一个 SIGSEGV。

从上面的 gdb 跟踪来看,您正在添加“。” 重复直到发生这种情况。您没有显示足够的代码让我确定是哪种编码错误让您走到了这一步。

于 2013-04-30T07:21:06.393 回答
1

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

于 2013-04-30T07:22:12.913 回答
0

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

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

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

于 2013-04-30T10:47:10.170 回答
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;
}
于 2013-04-30T14:28:04.690 回答