PowerShellからssh経由でLinuxに入って任意のコマンドを実行する。
これを可能にするため、sshをラップしたモジュールを以前書きました。
sshでLinuxサーバーにログインする手間をかけることなく、ぽちっとLinux上のCapisranoを実行したりとか自由にできます。
裏ではPowerShellからssh実行してコマンドを発行しているわけですが、今回ssh自体ができなくなる問題にあったので、対処をご紹介します。
すぐに解決できましたが、んーって悩んだのと、sshだけじゃなくGitでも起こりえるので。
エラーメッセージ
sshを実行すると、このエラーですぐに終了してしまいます。Git.exeなどでも一緒です。
0 [main] us 0 init_cheap: VirtualAlloc pointer is null, Win32 error 487 AllocationBase 0x0, BaseAddress 0x68560000, RegionSize 0x390000, State 0x10000 C:\Program Files\Git\bin\sh.exe: *** Couldn't reserve space for cygwin's heap, Win32 error 0
原因
sshも内部でCygwinを使っているのですが、これが参照する msys-1.0.dll に問題があります。
この辺とかが参考になります。
何も考えずに作っていると、みんな同じアドレスにロードしようとして、アドレスの再計算が発生するからシャレにならないよってことでした。
この辺にも言及があります。
副作用が引き金となる問題のうち、一般によく知られている例は、Windows NT 4.0 の Service Pack 4 で発生したものです。多くのカスタマから、SP4 をインストールした後、アプリケーションでメモリのアクセス違反が発生するという報告がありました。私が調べたほぼ全てのケースで、クラッシュしたアプリケーションは、再割り当てのため、呼び出しによって開放または移動されたメモリ アドレスを使っていました。旧バージョンのヒープ マネージャでは、プログラマはアクセス違反を起こさずに、たいていこのコーディング上のエラーを逃れることができました。SP4 では、そのバグがすぐに表面化してしまうのです。副作用 DLL Hell は、新しい DLL のバグではなく、DLL の副作用(よくある例では DLL の持つ既存のバグ)に依存しているアプリケーションによって起こります。そして、その副作用はサービスパックなどによって解消してしまう可能性がある訳です。 アプリケーションが依存する副作用は、SP4 のメモリ バグのようなコーディング エラーではない場合もあります。例えば、クラスのデータ メンバをドキュメント化せずに使っているプログラマがたくさんいます。今後のバージョンでは、そのメンバをプライベートにするか、あるいは別の構造体に移動するかもしれません。
あとはこれでしょうか。
ベースアドレスが設定されていない3つのDLLを同一プロセス空間にロード 1つのEXEファイルがベースアドレスを設定していない複数のDLLを利用する場合, プロセス(EXEファイル)が実行を開始する度にリロケーションが実行されます. このため,DLLの数が多ければ多いほど,起動時間が遅くなることになります. このオーバヘッドを回避するには,各DLLのベースアドレスをあらかじめ衝突しないアドレスに設定しておく必要があります.
ようは、msys-1.0.dllのアドレス割り当て問題。
対処
いくつかパターンがあります。
Stack Overflowではこのような方法が提示されています。
Windows再起動
msys-1.0.dllが利用するメモリのアドレス空間割り当ての問題なので、うまく行く場合はもちろんありますよね。ダメな場合はダメですし、一時しのぎですけど。
msys-1.0.dll の差し替え
もし自分の環境で、msys-1.0.dllが複数あった場合、差し替えてうまく行く場合があります。私の場合はダメでしたが。
ようは、この問題が起こっていないmsys-1.0.dllにめぐりあれば治ったように見えるってことです。これも一時しのぎ。
環境変数の pathを別のmsys-1.0.dll が優先して参照されるように変更してみる
これもdllの差し替えと意図していることは一緒です。
msys-1.0.dllを複数持っている場合に、ファイルの読み込みで利用される環境変数の $env:PATH *1 で、C:\Program Files (x86)\git\binなどを優先して指すことで、もしそのパスに正常なmsys-1.0.dllがあればうまくいくと。
これまた一時しのぎ。
やるなら rebase
一時しのぎではなく、問題の根本を対処すればいいのです。
で、利用するのが rebase.exe です。rebaseといっても、 git rebaseとはまったく違います。Windowsのrebaseです。
これですね。
私も自分のお仕事で作っているライブラリ類はNT 3.1時代にrebaseの重要性を懇々と説かれたので、特に共有するようなDLLはもれなくrebaseしています。
このmsys-1.0.dllの問題に関して、msysgitのIssue #133でやり取りを見つけることができます。
今回 rebase で行うのは、レジストリ操作のようなWindows OSに変化を与えるわけではなく、msys-1.0.dllが利用するメモリアドレスを変更するだけです。
復旧手順
手順を紹介します。
- rebase.exeがあるパスで、PowerShellかcmdを起動する
- msys-1.0.dllに対して、次のrebaseコマンドを実行する。*2
rebase -b 0x30000000 msys-1.0.dll
以上です。
私の場合は、 chocolateyで、 msysgitとposhgitを入れて、sourcetreeを利用している環境で起こりました。
msys-1.0.dllもrebase.exeもC:\Program Files (x86)\git\binにあったので、PowerShellを起動したパスはC:\Program Files (x86)\git\binです。
まとめ
はい。rebaseこれまで知らなかったのですが、大事です。
問題さえわかっていればすぐに直せるので、もし知らなくて見ていただいた方は安心していただければ。
sshは他のPCからでも....ですが、Git.exeもできないのは困りますからね。