Security-Enhanced CRT,边界与潜规则

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;
}

参考阅读:

1, _snwprintf_s的潜规则https://blog.dynox.cn/?p=791
2,   Security Features in the CRT:
      https://msdn.microsoft.com/zh-cn/library/vstudio/8ef0s5kh(v=vs.110).aspx

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注