【问题标题】:How does using the try statement avoid a race condition?使用 try 语句如何避免竞争条件?
【发布时间】:2013-01-29 02:05:18
【问题描述】:

判断文件是否存在时,使用try语句如何避免“竞态条件”?

我问这个问题是因为高度支持的answer(更新:它已被删除)似乎暗示使用os.path.exists() 创造了一个原本不存在的机会。

给出的例子是:

try:
   with open(filename): pass
except IOError:
   print 'Oh dear.'

但我不明白与以下相比如何避免竞争条件:

if not os.path.exists(filename):
    print 'Oh dear.'

调用os.path.exists(filename) 如何让攻击者对文件做一些他们无法做到的事情?

【问题讨论】:

    标签: python race-condition


    【解决方案1】:

    当然,竞争条件是在您的程序和在文件上运行的其他一些代码之间(竞争条件总是需要至少两个并行进程或线程,有关详细信息,请参阅this)。这意味着使用 open() 而不是 exists() 可能只在两种情况下有帮助:

    1. 您检查是否存在由某个后台进程创建或删除的文件(但是,如果您在 Web 服务器中运行,这通常意味着您的进程有许多副本并行运行以处理 HTTP 请求,因此对于即使没有其他程序,网络应用竞争条件也是可能的)。
    2. 可能有一些恶意程序正在运行,它试图通过在您期望文件存在的时候破坏文件来使您的代码崩溃。

    exists() 只执行一次检查。如果文件存在,它可能会在exists() 返回True 后一微秒被删除。如果文件不存在,它可能会立即创建。

    但是,open() 不仅测试文件是否存在,还打开文件(并且原子地执行这两个操作,因此在检查和打开之间不会发生任何事情)。通常文件在有人打开时无法删除。这意味着在with 内部,您可能完全确定:文件现在确实存在,因为它已打开。虽然只有在with内部才成立,而且文件仍然可以在with块退出后立即被删除,但将需要文件存在的代码放在with内部保证代码不会失败。

    【讨论】:

      【解决方案2】:

      这是一个使用示例:

      try:
          with open('filename') as f:
              do_stuff_that_depends_on_the_existence_of_the_file(f)
      except IOError as e:
          print 'Trouble opening file'
      

      如果您以任何访问权限打开文件,则操作系统将保证该文件存在,否则它将失败并出现错误。如果访问是独占的,则任何其他争用该文件的进程要么被您阻止,要么被您阻止。

      try 只是一种检测打开文件行为的错误或成功的方法,因为 Python 中的文件 I/O API 通常没有返回码(使用异常代替)。所以要真正回答你的问题,避免竞争条件的不是try,而是open。它在 C(Python 所基于)中基本相同,但没有例外。阅读this了解更多信息。

      请注意,您可能希望执行取决于对 try 块内文件的访问权限的代码。关闭文件后,将无法保证其存在。

      调用os.path.exists 只是在文件可​​能存在或可能不存在的时刻给出一个快照,并且一旦os.path.exists 返回,您就不知道文件的存在。恶意代码或意外逻辑可能会在您不期望的情况下删除或更改文件。这类似于在驶入道路之前转头检查道路是否畅通。一旦你回头,你就只能猜测你不再看的地方发生了什么。保持文件打开保证了扩展的一致状态,这在驾驶时是不可能的(无论好坏)。 :)

      由于os.path.exists 的快照性质,您建议检查文件不存在而不是使用try/open 仍然不够。不幸的是,我不知道在所有情况下都无法阻止在目录中创建文件,所以我认为最好检查文件是否存在,而不是不存在。

      【讨论】:

        【解决方案3】:

        我认为您要问的是特定的比赛条件:

        1. 文件已打开
        2. 上下文切换,文件被删除
        3. 上下文被切换回并尝试对“打开的”文件进行文件操作

        在这种情况下,您受到“保护”的方式是将所有文件处理代码放在 try 块中,如果文件在任何时候变得不可访问/损坏,您的文件操作将能够“优雅地”失败通过catch 块。

        请注意,现代操作系统当然不会发生这种情况,当文件被“删除”时,直到文件上所有打开的句柄都被解析(释放)后才会发生删除

        【讨论】:

          猜你喜欢
          • 2019-06-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-30
          • 2010-09-25
          • 1970-01-01
          相关资源
          最近更新 更多