strncpy()
is undefined if the source and destination strings overlap. Below is the x86 disassembly code of msvcr100.dll!strncpy
to see what behavior we can expect in certain scenarios.The function is longer than functionally required because, when it's possible, it uses
dword
size to access to the memory, otherwise it uses byte
size.In the disassembly code below, I highlighted the memory read and write instructions as well as the instructions increment the pointers to the source and destination strings. We will focus on the highlighted areas.
ESI
is the pointer in the source string, EDI
is the pointer in the destination string. Each time when the memory is read or written either the source or destination pointer is incremented. The value of the increment is either byte
or word
size.Let's assume the strings overlap. There are three possible scenarios.
Scenario #1. The pointer to the source string is greater than the pointer to the destination string. We copy the data from the higher memory address to the lower memory address, and we know the strings overlap. Therefore, we will overwrite data in the source string. Since the data is read before it is overwritten, it doesn't lead to misbehavior.
Scenario #2. The pointer to the source string is equal to the pointer to the destination string. Same as Scenario #1.
Scenario #3. The pointer to the destination string is greater than the pointer to the source string. We copy the data from the lower memory address to the higher memory address, and we know the strings overlap. The data in the source string is overwritten before it is read leading to misbehavior.
6E9A2AD0 mov ecx,dword ptr [esp+0Ch]
6E9A2AD4 push edi
6E9A2AD5 test ecx,ecx
6E9A2AD7 je 6E9A2B6F
6E9A2ADD push esi
6E9A2ADE push ebx
6E9A2ADF mov ebx,ecx
6E9A2AE1 mov esi,dword ptr [esp+14h]
6E9A2AE5 test esi,3
6E9A2AEB mov edi,dword ptr [esp+10h]
6E9A2AEF jne 6E9A2AFC
6E9A2AF1 shr ecx,2
6E9A2AF4 jne 6E9A2B7F
6E9A2AFA jmp 6E9A2B23
6E9A2AFC mov al,byte ptr [esi]
6E9A2AFE add esi,1
6E9A2B01 mov byte ptr [edi],al
6E9A2B03 add edi,1
6E9A2B06 sub ecx,1
6E9A2B09 je 6E9A2B36
6E9A2B0B test al,al
6E9A2B0D je 6E9A2B3E
6E9A2B0F test esi,3
6E9A2B15 jne 6E9A2AFC
6E9A2B17 mov ebx,ecx
6E9A2B19 shr ecx,2
6E9A2B1C jne 6E9A2B7F
6E9A2B1E and ebx,3
6E9A2B21 je 6E9A2B36
6E9A2B23 mov al,byte ptr [esi]
6E9A2B25 add esi,1
6E9A2B28 mov byte ptr [edi],al
6E9A2B2A add edi,1
6E9A2B2D test al,al
6E9A2B2F je 6E9A2B68
6E9A2B31 sub ebx,1
6E9A2B34 jne 6E9A2B23
6E9A2B36 mov eax,dword ptr [esp+10h]
6E9A2B3A pop ebx
6E9A2B3B pop esi
6E9A2B3C pop edi
6E9A2B3D ret
6E9A2B3E test edi,3
6E9A2B44 je 6E9A2B5C
6E9A2B46 mov byte ptr [edi],al
6E9A2B48 add edi,1
6E9A2B4B sub ecx,1
6E9A2B4E je 6E9A2BEC
6E9A2B54 test edi,3
6E9A2B5A jne 6E9A2B46
6E9A2B5C mov ebx,ecx
6E9A2B5E shr ecx,2
6E9A2B61 jne 6E9A2BD7
6E9A2B63 mov byte ptr [edi],al
6E9A2B65 add edi,1
6E9A2B68 sub ebx,1
6E9A2B6B jne 6E9A2B63
6E9A2B6D pop ebx
6E9A2B6E pop esi
6E9A2B6F mov eax,dword ptr [esp+8]
6E9A2B73 pop edi
6E9A2B74 ret
6E9A2B75 mov dword ptr [edi],edx
6E9A2B77 add edi,4
6E9A2B7A sub ecx,1
6E9A2B7D je 6E9A2B1E
6E9A2B7F mov edx,7EFEFEFFh
6E9A2B84 mov eax,dword ptr [esi]
6E9A2B86 add edx,eax
6E9A2B88 xor eax,0FFFFFFFFh
6E9A2B8B xor eax,edx
6E9A2B8D mov edx,dword ptr [esi]
6E9A2B8F add esi,4
6E9A2B92 test eax,81010100h
6E9A2B97 je 6E9A2B75
6E9A2B99 test dl,dl
6E9A2B9B je 6E9A2BC9
6E9A2B9D test dh,dh
6E9A2B9F je 6E9A2BBF
6E9A2BA1 test edx,0FF0000h
6E9A2BA7 je 6E9A2BB5
6E9A2BA9 test edx,0FF000000h
6E9A2BAF jne 6E9A2B75
6E9A2BB1 mov dword ptr [edi],edx
6E9A2BB3 jmp 6E9A2BCD
6E9A2BB5 and edx,0FFFFh
6E9A2BBB mov dword ptr [edi],edx
6E9A2BBD jmp 6E9A2BCD
6E9A2BBF and edx,0FFh
6E9A2BC5 mov dword ptr [edi],edx
6E9A2BC7 jmp 6E9A2BCD
6E9A2BC9 xor edx,edx
6E9A2BCB mov dword ptr [edi],edx
6E9A2BCD add edi,4
6E9A2BD0 xor eax,eax
6E9A2BD2 sub ecx,1
6E9A2BD5 je 6E9A2BE3
6E9A2BD7 xor eax,eax
6E9A2BD9 mov dword ptr [edi],eax
6E9A2BDB add edi,4
6E9A2BDE sub ecx,1
6E9A2BE1 jne 6E9A2BD9
6E9A2BE3 and ebx,3
6E9A2BE6 jne 6E9A2B63
6E9A2BEC mov eax,dword ptr [esp+10h]
6E9A2BF0 pop ebx
6E9A2BF1 pop esi
6E9A2BF2 pop edi
6E9A2BF3 ret
This is not what I recommend to rely on when you code, though. Not to mention there is a safer version of this function that is
strncpy_s()
.