通过Ruby / DL调用OpenProcessToken时的Segfault

时间:2014-05-07 00:07:47

标签: ruby windows rubydl

请参阅下面的更新

我一直在尝试修复Ruby库在UAC上下文中与另一个程序通信的能力,并且需要创建一个与当前用户具有相同安全属性的共享文件映射。我正在使用Ruby / dl并尝试将其用于Ruby 1.9.3是导致我的问题的原因。

在advapi31中调用OpenProcessToken函数会导致分段错误。您将在下面找到一个最小的示例,这会导致我的计算机出现分段错误。我收到的错误文本是here,这里也是错误文本打印到命令行后出现的错误框的屏幕截图:

Ruby problem dialog box

require 'dl'
require 'dl/import'
require 'dl/types'

module Win
  extend DL::Importer

  dlload 'kernel32', 'advapi32'

  include DL::Win32Types

  # args: none
  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx
  extern 'HANDLE GetCurrentProcess()'

  # args: hProcessHandle, dwDesiredAccess, (out) phNewTokenHandle
  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx
  extern 'BOOL OpenProcessToken(HANDLE, DWORD, PHANDLE)'

  # args: hObject
  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
  extern 'BOOL CloseHandle(HANDLE)'

  # args: none
  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360(v=vs.85).aspx
  extern 'DWORD GetLastError()'

  def self.open_process_token
    token_handle = DL::CPtr.malloc(DL::SIZEOF_VOIDP, DL::RUBY_FREE)
    raise_error_if_zero(OpenProcessToken(Win.GetCurrentProcess, 0x8, token_handle.ref))
    raise_error_if_zero(CloseHandle(token_handle))
  end

  def self.raise_error_if_zero(result)
    if result == 0
      raise "Windows error: #{Win.GetLastError}"
    end
  end
end

Win.open_process_token

更新

将Ruby更新到1.9.3p545(使用RubyInstaller)允许我运行上面提供的示例,但我仍然遇到问题。我创建了一个包含文件的Gist here,当使用1.9.3p545运行时会产生分段错误(虽然这次没有解释器没有响应并生成如上所示的对话框。)我试过这个(和在我的机器上以及另一个安装了相同版本的Ruby的相同结果。由于我之前没有提到它,我正在运行Windows 7 Pro 64位,对于我测试的其他计算机也是如此。

我注意到一些可能意味着更深层次问题的事情,不一定与OpenProcessToken有关。以下任何一项都可以单独阻止段错误:

  • 将第3行从runner.rb复制到mwe.rb的底部并直接运行mwe.rb。
  • 评论mwe.rb的第5行或者注释掉一些大量的errors.rb(例如,注释掉第37到99行不会导致段错误。)
  • 评论runner.rb的第3行,实际上只需要其他文件并退出。
  • 在Pageant :: Win中注释掉以下内容的组合,结果是没有段错误:
    • 致电extern
    • 致电struct
    • 常量
    • 班级方法

在最后一种情况下,没有必要注释掉特定类别的所有项目。例如,如果我注释掉TOKEN_USERSECURITY_ATTRIBUTES,则会避免出现段错误。我还可以通过评论TOKEN_USER和与extern相关联的IsValidSecurityDescriptor语句来阻止段错误。我尝试了其他几种导致相同行为的组合。

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:0)

这个错误不是因为ruby而是因为你的代码。

您在open_process_token方法中对DL :: CPtr类型的变量使用了不合适的方法ref。

方法open_process_token

def self.open_process_token
  token_handle = DL::CPtr.malloc(DL::SIZEOF_VOIDP, DL::RUBY_FREE)
  OpenProcessToken(Win.GetCurrentProcess, 0x8, token_handle.ref)
end

应该是

def self.open_process_token
  ptoken_handle = DL::CPtr.malloc(DL::SIZEOF_VOIDP, DL::RUBY_FREE)
  OpenProcessToken(Win.GetCurrentProcess, 0x8, ptoken_handle)
  token_handle = ptoken_handle.ptr.to_i
end

(感谢Heesob Park this上的{{3}}非问题。)