Andre's Blog
Perfection is when there is nothing left to take away
Microsoft: More steam, more noise - let the world think we are moving!

Microsoft declared standard memory manipulation functions, such as memcpy, not secure and deprecated. The motivation behind this is that modern developers are not smart or careful enough to ensure that the destination buffer has sufficient room, which results in buffer overruns:

http://blogs.msdn.com/sdl/archive/2008/10/22/good-hygiene-and-banned-apis.aspx

http://blogs.msdn.com/sdl/archive/2009/05/14/please-join-me-in-welcoming-memcpy-to-the-sdl-rogues-gallery.aspx

Banning functions from the memcpy family is like banning knives in the kitchen or nail guns on a construction site and replacing them with plastic knives and hammers.

Let's put this analogy to the test. This small test program copies a 128 byte buffer 50M times to the destination buffer and prints elapsed time, in milliseconds, at the end.

#define MYSIZE 128
	
char *src, *dst;
DWORD stime = GetTickCount();

src = new char[MYSIZE];
dst = new char[MYSIZE];
	
memset(src, 'A', MYSIZE);
	
stime = GetTickCount();
	
for(int i = 0; i < 50000000ul; i++)
    memcpy(dst, src, MYSIZE);
		
printf("elapsed: %d\n", GetTickCount()-stime);

On my 1.8MHz machine, this code takes about 3.5 seconds to complete. Replacing memcpy with memcpy_s increases run time to 5.5 seconds.

Let's look under the covers what is going on. Instead of generating a call to memcpy, the compiler produces code similar to what's shown below, which copies 32 4-byte words from the source pointed to by the esi register to the destination pointed to by edi.

memcpy(dst, src, MYSIZE);
  mov         ecx,20h       ; set up the counter
  mov         esi,ebx       ; source
  mov         edi,ebp       ; destination
  rep movs    dword ptr es:[edi],dword ptr [esi]  ; copy 4-byte words 

When memcpy_s is being called, an actual call instruction is generated:

memcpy_s(dst, MYSIZE, src, MYSIZE);
  push        80h           ; source size  
  push        esi           ; source
  push        80h           ; destination size
  push        ebx           ; destination
  call        ebp           ; call memcpy_s
  add         esp,10h       ; clean up the stack

, which is, combined with other size validation checks in memcpy_s, explains longer run time. It is also worth mentioning that this optimization that expands memcpy, as if it's an inline function, will be used when the amount of copied data is up to 4096 bytes.

Note also that the memcpy return value has also been changed from the pointer to the destination buffer to a useless errno value, which is appropriately commented in the memcpy_s source. This makes it impossible to use memcpy_s as a drop-in replacement for memcpy.

Conclusion

Functions like memcpy are written in assembly, and by very talented people. Don't take my word for it and take a look at the source. You don't have to understand the assembly language - there are plenty comments in the code showing how much the developer cared about how well this function will perform.

Stunts like banning memcpy are not designed to improve security - a developer who can't ensure that the destination buffer is large enough can and will overrun the buffer by passing the wrong destination size to memcpy_s. The true goal of this announcement is to give the public impression that Microsoft is doing something to make their products more secure.

I am amazed to think that Microsoft will spend a ton of money on walking millions lines of their code, replacing "deprecated" functions with code that will be just as vulnerable and will take longer to run. It's also very likely that they will end up introducing new bugs into otherwise stable code because new functions are not drop-in replacements.

Comments:
Posted Sun May 17 04:56:15 EDT 2009 by you're clueless

The slowdown is not due to the memset.

Posted Sun May 17 21:23:32 EDT 2009 by Andre

Yes I was. Thank you for pointing this out.

Name:

Comment: