5

ReadFileEx的文档说:

在读取操作正在使用缓冲区时访问输入缓冲区可能会导致读取到该缓冲区的数据损坏。在读取操作完成之前,应用程序不得读取、写入、重新分配或释放读取操作正在使用的输入缓冲区。

这是我第一次听说读取数据会导致损坏。
所以我的问题是,为什么会这样?读取操作如何可能导致数据损坏?
导致这种情况的原因是什么?

更新:

我注意到ReadFile's page上有一个有趣的句子:

ReadFile函数可能会失败ERROR_NOT_ENOUGH_QUOTA,这意味着调用进程的缓冲区无法被页面锁定。

也许这与答案有关?

4

3 回答 3

2

我不太确定,所以我很愿意接受评论,但我猜:

ReadFileEx实现使用NtReadFile(或多或少它只是围绕它的一个薄包装)。NtReadFile做了很多事情,但它使用IoBuildAsynchronousFsdRequest(或IoBuildSynchronousFsdRequest)来执行它的任务。从这篇文章我们知道:

如果目标设备对象设置为直接 i/o (DO_DIRECT_IO),则 IoBuildAsynchronousFsdRequest 创建一个 MDL 来描述缓冲区并锁定页面

(重点是我的)

然后我猜他们MmProbeAndLockPages用调用IoWriteAccess,这是由内核模式下的驱动程序完成的,然后用户提供的缓冲区(在用户模式下)甚至无法访问以进行读取。

我不知道如果你这样做会发生什么,可能会抛出一个 SEH 异常并且你的代码会失败。

编辑
正如已编辑问题中所指出的那样,即使该ReadFile函数也禁止用户从缓冲区中读取,直到操作完成并且它可能会返回ERROR_NOT_ENOUGH_QUOTA

ReadFile 函数可能会因 ERROR_NOT_ENOUGH_QUOTA 而失败,这意味着调用进程的缓冲区无法被页面锁定。

至少这清楚地表明ReadFile(缓冲区不是由用户提供的)将分配一个页面并将其锁定(好的,我在链接的文章中也说过......)。用户定义的缓冲区是否也会发生损坏(如果有的话,我非常同意@David),还有待了解(如@Ben 所指出的,页面上的锁定在大多数情况下是不可能的)。

我不认为它使用页面错误来检测缓冲区溢出仅仅是因为它在调用之前知道所需的数据量然后它可以分配一次。

那么为什么数据会被破坏呢? 毕竟这里的一切都可能是由于错误而不是数据损坏。这是一个很大的猜测,但有一个已知问题MmProbeAndLockPages

由于内存管理器中的争用条件,会出现此问题。当驱动程序调用 MmProbeAndLockPages 例程时,此例程可能会读取一些正在被另一个线程修改的数据。因此,会发生数据损坏。根据损坏数据的使用方式,应用程序或系统可能会崩溃。

很难说这个问题是否已经在非常低的水平上得到解决,或者如果应用程序做了一些奇怪的事情是否仍然可以利用......

于 2013-02-27T16:55:24.920 回答
1

Most likely, the corruption when you read from the I/O buffer results from the race condition -- the buffer may be partially filled in when you read from it, and the order in which it is filled in is unspecified. In addition, Windows could store anything in there during the time it owns the buffer -- you aren't guaranteed to see either the prior content or the data from the file.

What you can be sure of is that it isn't related to access violations when reading from the buffer, because it's perfectly legal to continue accessing other data in the same page. Only the buffer itself is forbidden to your use. Now, when the file is open for direct unbuffered I/O (FILE_FLAG_NO_BUFFERING), and the volume sector size is a multiple of the memory page size, then, the buffer is required to correspond to a sequence of complete pages, so the kernel has more freedom at that point. But that's a very particular set of conditions, and it's rare for the sector size to exceed the memory page size.

于 2013-02-27T16:59:39.460 回答
0

有两句话。首先:

在读取操作正在使用缓冲区时访问输入缓冲区可能会导致读取到该缓冲区的数据损坏。

其次是:

在读取操作完成之前,应用程序不得读取、写入、重新分配或释放读取操作正在使用的输入缓冲区。

该文档没有明确说明第二句中提到的每个动作都可能导致第一句中描述的损坏。它说:

  1. 在读取期间访问输入缓冲区可能会损坏该缓冲区,并且
  2. 在读取期间不要读取、写入、重新分配或释放缓冲区。

因此,当我解释文档时,它并没有说明在读取操作期间从缓冲区读取会损坏它。

于 2013-02-27T17:31:16.267 回答