MoveVolatileMemory 函数

将源内存块的内容复制到目标内存块,并支持重叠源内存块和目标内存块。

重要

一些信息与预发布产品相关,在商业发行之前可能会发生实质性修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

参数

Param Destination [out]

指向复制块的目标起始地址的指针。

参数 Source [输入]

指向要复制的内存块起始地址的指针。

参数 Length [输入]

要复制的内存块的大小(以字节为单位)。

语法

volatile void* __cdecl
  MoveVolatileMemory (
    _Out_writes_bytes_all_(Length) volatile void* Destination,
    _In_reads_bytes_(Length) volatile const void* Source,
    SIZE_T Length
  );

备注

此 API 用于在开发人员需要确保发生所需复制操作(即不受编译器优化的影响)的情况下提供 MoveMemory 行为(即,将内存从一个位置复制到另一个位置)。 与 CopyVolatileMemory 不同,此 API 处理缓冲区和目标缓冲区重叠的情况。

每个 API 具有以下属性:

  • API 不会被识别为编译器内部函数,因此编译器永远不会优化调用(完全去除或用“等效”指令序列替换调用)。 这不同于 MoveMemory,后者受多项编译器优化的影响。
  • 当调用返回时,数据已从源复制到目标。 此函数内存对目标的访问只在函数中执行(即编译器无法在此函数外访问内存)。
  • 如果平台允许,API 可能会执行不一致的内存访问。
  • API 在复制操作期间可以多次访问内存位置。
  • MoveMemory 类似之处在于,当目标相互重叠时,它支持复制操作

注意

此函数适用于所有版本的 Windows,而不仅仅是最新版本。 需要使用最新的 SDK 从 winbase.h 标头获取函数声明。 还需要最新 SDK 中的库 (volatileaccessu.lib)。 但是,生成的二进制文件将能够很好地在较旧版本的 Windows 上运行。

示例

HEADER MyHeader;
UCHAR RawBuffer[100];

// Ensure that the shared memory (which could be constantly changing)
// is copied in to the local MyHeader variable.
// Note that the compiler is allowed to optimize away calls to
// MoveMemory/RtlMoveMemory so those functions are not guaranteed to actually
// make a local copy of data.
//
// MoveVolatileMemory does handle
// buffers that overlap with each other (MoveMemory semantics).
// Assume SharedMemory points to virtual memory that is also mapped in an untrusted process.
// Assume that untrusted process is changing the memory contents while you are accessing it.
PVOID SharedMemory;

MoveVolatileMemory(&MyHeader, SharedMemory, sizeof(MyHeader));

if (MyHeader.Size < 100) {
  // Because MyHeader is local and we are guaranteed we actually made
  // a local copy, we can be sure that the "Size" value will not change
  // between the previous bounds check and the below call to RtlFillMemory.
  // If RtlMoveMemory/RtlMoveMemory had been used to copy the data, it is possible
  // that a compiler may optimize away the call to MoveMemory and instead fetch
  // the “size” field of MyHeader directly from untrusted memory two times.
  // The first time it would be fetched for the bounds check, and the second
  // time it is fetched is for the call to FillMemory. It is possible the memory
  // could have changed between the two accesses resulting in the size check
  // being ineffective.

  FillMemory (RawBuffer, MyHeader.Size, 0);
}

要求

支持的最低客户端:Windows 11 Insider 预览版(待定)

标头:winbase.h(包括 Winbase.h)

Kernel-mode 库:volatileaccessk.lib

User-mode 库:volatileaccessu.lib

另请参阅