为什么过早访问ReadFileEx的输入缓冲区会导致数据损坏?

时间:2013-02-27 16:28:09

标签: c winapi readfile corruption

ReadFileEx's documentation说:

  

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

这是我第一次听说读取导致腐败的数据 所以我的问题是,为什么会发生这种情况? 读取操作如何可能导致数据损坏? 下面发生了什么导致了这个?

更新

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

  

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

也许这与答案有关?

3 个答案:

答案 0 :(得分:2)

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

实现

ReadFileEx以使用NtReadFile(或多或少它只是一个薄的包装器)。 NtReadFile做了很多事情,但它使用IoBuildAsynchronousFsdRequest(或IoBuildSynchronousFsdRequest)来执行其任务。来自this article我们知道:

  

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

(重点是我的)

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

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

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

  

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

至少这清楚表明ReadFile(用户未提供缓冲区)将分配一个页面并且锁定它(好吧已经说过了)这篇文章我也链接了......)。仍然需要了解腐败(如果有的话,我非常同意@David)是否也会出现用户定义的缓冲区(如果@Ben指出,页面上的锁定,大多数情况下是不可能的)。 / p>

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

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

  

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

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

答案 1 :(得分:1)

最有可能的是,从I / O缓冲区读取时的损坏是由竞争条件引起的 - 当您从缓冲区读取缓冲区时,缓冲区可能会被部分填充,并且未指定填充缓冲区的顺序。此外,Windows可以在拥有缓冲区期间在其中存储任何内容 - 您无法保证看到先前的内容或文件中的数据。

您可以确定的是与缓冲区读取时的访问冲突无关,因为继续访问同一页面中的其他数据是完全合法的。禁止使用缓冲区本身。现在,当文件打开直接无缓冲I / O(FILE_FLAG_NO_BUFFERING),并且卷扇区大小是内存页面大小的倍数时,则需要缓冲区对应到一系列完整的页面,所以内核在那一点上有更多的自由。但这是一组非常特殊的条件,扇区大小超过内存页面大小的情况很少。

答案 2 :(得分:0)

有两句话。首先:

  

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

其次是:

  

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

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

  1. 在读取期间访问输入缓冲区可能会破坏该缓冲区,
  2. 在阅读过程中不要读取,写入,重新分配或释放缓冲区。
  3. 因此,当我解释文档时,它没有声明在读取操作期间从缓冲区读取可能会破坏它。