Windows Security-Enhanced CRT 相关函数(即_s后辍函数)并不是对老函数的直接替代,其中不仅有更严格的参数检查,还会有buffer的重置操作等,使用的时候要格外小心,一定要仔细阅读MSDN描述或者VC runtime源码 (以Visual Studio 2008为例: C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src)。
下面不妨测试3个代码片段:
测试代码【C1】:
void main() {
char dst1[8];
memcpy(dst1, NULL, 0);
memcpy(NULL, NULL, 0);
}
测试代码【C2】:
void main() {
char dst1[8];
memcpy_s(dst1, 8, NULL, 0);
memcpy_s(NULL, 0, NULL, 0);
char *dst2 = (char *)malloc(0);
if (dst2) {
memcpy_s(dst2, 0, NULL, 0);
free(dst2);
}
}
测试代码【C3】:
void main() {
char dst1[8];
memcpy_s(NULL, 0, dst1, 8);
char *dst2 = (char *)malloc(0);
if (dst2) {
memcpy_s(dst2, 0, dst1, 8);
free(dst2);
}
}
这几段代码实际上什么也没有做,只是参数有变化而已,但测试中会发现【C3】会导致程序崩溃。具体原因就是因为memcpy_s进行了更严格的参数检测,可对参考memcpy_s的源码,引用自Visual Studio 2008 runtime source memcpy_s.c:
/***
* memcpy_s.c - contains memcpy_s routine
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* Purpose:
* memcpy_s() copies a source memory buffer to a destination buffer.
* Overlapping buffers are not treated specially, so propagation may occur.
*
*******************************************************************/
#include <cruntime.h>
#include <string.h>
#include <internal.h>
/***
* memcpy_s - Copy source buffer to destination buffer
*
* Purpose:
* memcpy_s() copies a source memory buffer to a destination memory buffer.
* This routine does NOT recognize overlapping buffers, and thus can lead
* to propagation.
*
* For cases where propagation must be avoided, memmove_s() must be used.
*
* Entry:
* void *dst = pointer to destination buffer
* size_t sizeInBytes = size in bytes of the destination buffer
* const void *src = pointer to source buffer
* size_t count = number of bytes to copy
*
* Exit:
* Returns 0 if everything is ok, else return the error code.
*
* Exceptions:
* Input parameters are validated. Refer to the validation section of the function.
* On error, the error code is returned and the destination buffer is zeroed.
*
*******************************************************************/
errno_t __cdecl memcpy_s(
void * dst,
size_t sizeInBytes,
const void * src,
size_t count
)
{
if (count == 0)
{
/* nothing to do */
return 0;
}
/* validation section */
_VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL);
if (src == NULL || sizeInBytes < count)
{
/* zeroes the destination buffer */
memset(dst, 0, sizeInBytes);
_VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL);
_VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE);
/* useless, but prefast is confused */
return EINVAL;
}
memcpy(dst, src, count);
return 0;
}
参考阅读: