0

以下のアップデートをご覧ください

UAC コンテキストを介して別のプログラムと通信する Ruby ライブラリの機能を修正しようとしており、現在のユーザーと同じセキュリティ属性を持つ共有ファイル マップを作成する必要があります。私は Ruby/dl を使用していますが、これを Ruby 1.9.3 で動作させようとしていることが問題の原因です。

advapi31 でOpenProcessToken関数を呼び出すと、セグメンテーション違反が発生します。以下に最小限の例を示します。これにより、私のマシンでセグメンテーション エラーが発生しました。受け取ったエラーのテキストはこちらです。エラー テキストがコマンド ラインに出力された後に表示されるエラー ボックスのスクリーンショットもここにあります

Rubyの問題ダイアログボックス

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

アップデート

(RubyInstaller を使用して) Ruby を 1.9.3p545 に更新すると、上記の例を実行できましたが、引き続き問題が発生します。ここで、1.9.3p545 で実行するとセグメンテーション エラーが発生するファイルを含むGist を作成しました(ただし、今回はインタプリタが応答しなくなり、上記のダイアログ ボックスが表示されることはありません)。同じバージョンの Ruby がインストールされた別のマシンと同様に、同じ結果が得られます。以前は言及しなかったので、私は Windows 7 Pro 64 ビットを実行しています。同じことが、テストした他のコンピューターにも当てはまります。

必ずしも OpenProcessToken に関連しているとは限らない、より深い問題を暗示している可能性があるいくつかのことに気付きました。次のいずれかによって、個別にセグメンテーション違反を防ぐことができます。

  • 行 3 を runner.rb から mwe.rb の下部にコピーし、mwe.rb を直接実行します。
  • mwe.rb の 5 行目をコメント アウトするか、errors.rb のいくつかの大きなサブセットをコメント アウトします (たとえば、37 行目から 99 行目をコメント アウトすると、segfault は発生しません)。
  • runner.rb の 3 行目をコメントアウトして、実際には他のファイルのみを要求して終了します。
  • Pageant::Win 内から次の組み合わせをコメントアウトすると、segfault は発生しません。
    • への呼び出しextern
    • への呼び出しstruct
    • 定数
    • クラス メソッド

最後のケースでは、特定のカテゴリのすべての項目をコメント化する必要はありません。たとえば、 と をコメントアウトするTOKEN_USERと、セグメンテーション違反が回避されSECURITY_ATTRIBUTESます。また、コメント アウトTOKEN_USERと にextern関連付けられたステートメントによってセグメンテーション違反を防ぐこともできIsValidSecurityDescriptorます。同じ動作になる他のいくつかの組み合わせを試しました。

どんな助けでも大歓迎です。

4

1 に答える 1

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に感謝します。)

于 2014-05-10T21:52:06.873 に答える