strcpy(s+3,s);
printf("%s",s);
输出结果是1231234234
不理解这是为什么?
------------------------------------------------
已知strcpy函数如下所示:
char * strcpy(char *dest, char *source)
{
char *temp = dest;
while((*dest++ = *source++) != '\0');
return temp;
}
现在不去调用库函数,自定义一个函数,参数和内容与库函数strcpy一样,程序会朋崩溃。
解答:
这问题必须要去逆向库函数才能说明白的...真是懒得弄了...太繁琐...
.text:004013B3 mov [esp+90h+var_90], eax
.text:004013B6 call strcpy ; DWORD 75A18D6E
.text:004013BB lea eax, [esp+90h+var_74] ; "123" + "1234123"
;strcpy() in msvcrt.dll, Windows only!
msvcrt.dll:75A18D6E msvcrt__mbscpy:
msvcrt.dll:75A18D6E push edi
msvcrt.dll:75A18D6F mov edi, [esp+8]
msvcrt.dll:75A18D73 jmp short loc_75A18DAC
msvcrt.dll:75A18DAC loc_75A18DAC:
msvcrt.dll:75A18DAC mov ecx, [esp+0Ch] ; &"1234"
msvcrt.dll:75A18DB0 test ecx, 3
msvcrt.dll:75A18DB6 jnz short loc_75A18E17 ; !(ecx & 3)
msvcrt.dll:75A18DB8 mov edx, 7EFEFEFFh
msvcrt.dll:75A18DBD mov eax, [ecx] ; &"1234"
msvcrt.dll:75A18DBF add edx, eax
msvcrt.dll:75A18DC1 xor eax, 0FFFFFFFFh
msvcrt.dll:75A18DC4 xor eax, edx
msvcrt.dll:75A18DC6 mov edx, [ecx] ; &"1234"
msvcrt.dll:75A18DC8 add ecx, 4 ; &ecx + 1 (向后移动了一个地址)
msvcrt.dll:75A18DCB test eax, 81010100h
;msvcrt.dll:75A18DD0 jnz short loc_75A18DD9
msvcrt.dll:75A18DD2 mov [edi], edx ; "1234"
msvcrt.dll:75A18DD4 add edi, 4 ; &edi + 1 (向后移动了一个地址)
msvcrt.dll:75A18DD7 jmp short loc_75A18DB8
;back to loc_75A18DB8
msvcrt.dll:75A18DB8 mov edx, 7EFEFEFFh
msvcrt.dll:75A18DBD mov eax, [ecx] ; &"234"
msvcrt.dll:75A18DBF add edx, eax
msvcrt.dll:75A18DC1 xor eax, 0FFFFFFFFh
msvcrt.dll:75A18DC4 xor eax, edx
msvcrt.dll:75A18DC6 mov edx, [ecx] ; &"234"
msvcrt.dll:75A18DC8 add ecx, 4
msvcrt.dll:75A18DCB test eax, 81010100h
msvcrt.dll:75A18DD0 jnz short loc_75A18DD9
msvcrt.dll:75A18DD9 loc_75A18DD9:
msvcrt.dll:75A18DD9 test dl, dl
msvcrt.dll:75A18DDB jz short loc_75A18E0F
msvcrt.dll:75A18DDD test dh, dh
msvcrt.dll:75A18DDF jz short loc_75A18DF6
msvcrt.dll:75A18DE1 test edx, 0FF0000h
msvcrt.dll:75A18DE7 jnz short loc_75A18DFF
msvcrt.dll:75A18DFF loc_75A18DFF:
msvcrt.dll:75A18DFF test edx, 0FF000000h
msvcrt.dll:75A18E05 jnz short loc_75A18DD2
msvcrt.dll:75A18E07 mov [edi], edx ; "234"
msvcrt.dll:75A18E09 mov eax, [esp+8] ; "1234234"
msvcrt.dll:75A18E0D pop edi ; return "1234234"
msvcrt.dll:75A18E0E retn
实在懒得解说了,精力不比当年啊...重要的步骤我都用;注释成伪C代码风格了...自己研究吧...
而你自己写的那个strcpy,如@binux所说,s在累加的时候,会把结尾符'\0'覆盖掉,所以循环永远也结束不了的,会把栈直接压崩~单步跟一下就会明白是怎么回事了~
另外,必须要指出的是,strcpy按照要求是不允许dst和src有内存重叠的!
=========================
内存区重叠了,strcpy的结果不确定。
分析了下反汇编的代码,出现问题的关键原因在于,strcpy并不是逐个字符进行复制,而是一次复制4个字节。
第一次复制4个字节,src指向字符“1”,dst指向字符“4”,复制的字符为“1234”,所以第一次复制后的结果为“1231234”;到这一步是容易理解的。
之后src+4,指向新字符串的第二个字符“2”,dst+4,指向新字符串末尾,接下来就出现问题了:
由于内存已经被改写,接下来复制了新串末尾的“234”三个字符,然后结束。
所以最终的字符串为“1231234234”。
其实这里面还有一个问题,如果字符串后面的内存中没有出现0的话,strcpy会一直复制下去,并不会结束。
如果把代码改一下:
char s[100]="1234";
s[7] = 'B';
s[11] = 'U';
s[15] = 'P';
s[19] = 'T';
strcpy(s+3,s);
printf("%s",s);
输出结果是 1231234234B34BU4BUPBUPTUPT
====================================
由后往前移指copy~
char* strcpy_safe(char* dst,const char* src)
{
size_t len = strlen(src);
char* cp = dst;
if(dst == NULL)
{
return NULL;
}
if(dst<=src || (char*)dst >= ((char*)src + len))
{
while(*src)
{
*dst++ = *src++;
}
*dst = '/0';
return cp;
}
else
{
dst = (char*)dst + len;
*dst-- = '/0';
src = (char*)src + len - 1;
while(len--)
{
*dst-- = *src--;
}
return cp;
}
}
==============================
#include <stddef.h>
#include <string.h>
#include <memcopy.h>
#include <bp-checks.h>
#undef strcpy
/* Copy SRC to DEST. */
char *
strcpy (dest, src)
char *dest;
const char *src;
{
reg_char c;
char *__unbounded s = (char *__unbounded) CHECK_BOUNDS_LOW (src);
const ptrdiff_t off = CHECK_BOUNDS_LOW (dest) - s - 1;
size_t n;
do
{
c = *s++;
s[off] = c;
}
while (c != '\0');
n = s - src;
(void) CHECK_BOUNDS_HIGH (src + n);
(void) CHECK_BOUNDS_HIGH (dest + n);
return dest;
}
libc_hidden_builtin_def (strcpy)
这个应该是源码。