我正在虚拟机中运行程序。我正在执行一个循环,在某些时候,我调用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次。
答案 0 :(得分:2)
char * strcat ( char * destination, const char * source );
当您致电strcat
时,source
将附加到destination
字符串(destination
的终止空字符将被{{的第一个字符替换1}}等等)。 source
必须有足够的分配空间才能包含连接字符串。另请注意, destination
和source
必须是以空字符结尾的字符串。
关于您的代码
destination
由于您使用参数void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host) {
strcat((char*)host,".")
来存储连接字符串,因此必须在调用host
之前确保ChangetoDnsNameFormat
是null-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;
}