New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VimからPythonを使うと落ちる #594

Closed
koron opened this Issue Jul 20, 2014 · 57 comments

Comments

Projects
None yet
6 participants
@koron
Member

koron commented Jul 20, 2014

正確なタイトルは「Vim 64bit からPython 32bit を使おうとすると落ちる」

なんも言わずに落ちた。以下、詳細な状況

  • OS は Windows 7 (64bit)
  • Vim は64bit
  • Python は 2.7.6/3.4.0 の 32/64bit 系4バージョンインストール済み
  • Path は 2.7.6 の 64bit に通ってる

手順:

  1. C:\Windows\System32\python27.dllpython27.dll~ にリネームして読めないように
  2. gvim を起動して py import sys; print(sys.version) を実行
  3. 落ちた。システムデバッガも拾ってくれない

備考:

  • python34.dll のほうで同様に py3 import sys; print(sys.version) した時は、落ちずにDLLが読めないとエラーが出た

修正方針

  • Py_NoSiteFlag を立てる at before Py_Initialize()
  • go fail; した後は、pythonを使えないように、フラグ管理する in Python_Init()
  • import site は各モジュールの初期化の最終段階で、自前でやる at begin/end of populate_module()

@koron koron added kind/bug labels Jul 20, 2014

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

32bit 版 Vim から 64bit Python を読むのは未テスト。

Member

koron commented Jul 20, 2014

32bit 版 Vim から 64bit Python を読むのは未テスト。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

#66 からの派生

Member

koron commented Jul 20, 2014

#66 からの派生

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

デバッガで追って確認したんだけど
32bit の DLL に対して LoadLibrary と GetProcAddress は成功しちゃうのね。
すごい。

Member

koron commented Jul 20, 2014

デバッガで追って確認したんだけど
32bit の DLL に対して LoadLibrary と GetProcAddress は成功しちゃうのね。
すごい。

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 20, 2014

Member

それたぶん tortoisehg か mercurial 付属の dll を読み込んでませんか

Member

ynkdir commented Jul 20, 2014

それたぶん tortoisehg か mercurial 付属の dll を読み込んでませんか

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

あざす! そうっぽいですね。

いま「64から32読めるわけねーだろ」と思って
仮に読めるとしたらどんな仕組みで読んでるのがググってましたが
集まるのは逆の証拠ばかりでしたw

Member

koron commented Jul 20, 2014

あざす! そうっぽいですね。

いま「64から32読めるわけねーだろ」と思って
仮に読めるとしたらどんな仕組みで読んでるのがググってましたが
集まるのは逆の証拠ばかりでしたw

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

#66 から転載


確認はしてませんがこれだと思います。

Python-2.7.8/Python/pythonrun.c

/* Import the site module (not into __main__ though) */

static void
initsite(void)
{
    PyObject *m;
    m = PyImport_ImportModule("site");
    if (m == NULL) {
        PyErr_Print();
        Py_Finalize();
        exit(1);
    }
    else {
        Py_DECREF(m);
    }
}
Member

koron commented Jul 20, 2014

#66 から転載


確認はしてませんがこれだと思います。

Python-2.7.8/Python/pythonrun.c

/* Import the site module (not into __main__ though) */

static void
initsite(void)
{
    PyObject *m;
    m = PyImport_ImportModule("site");
    if (m == NULL) {
        PyErr_Print();
        Py_Finalize();
        exit(1);
    }
    else {
        Py_DECREF(m);
    }
}
@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

さらに #66 より転載


py2exe は python27.dll に細工してました。
python27.dll の winver(1000) というリソースを変更してます。
python はレジストリの HKLM\Software\Python\PythonCore{WINVER} に PYTHONPATH を取りにいくので py2exe の dll は普通には使えない。

Member

koron commented Jul 20, 2014

さらに #66 より転載


py2exe は python27.dll に細工してました。
python27.dll の winver(1000) というリソースを変更してます。
python はレジストリの HKLM\Software\Python\PythonCore{WINVER} に PYTHONPATH を取りにいくので py2exe の dll は普通には使えない。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

その後に確認したこと。

  1. system と Mercurial の python27.dll を inhibit して Vimから Python実行 → DLLロードエラーで正しく止まった
  2. system の python27.dll だけを inhibit して、インストールしてある Python 2.7.6 を実行 → Mercurlal の Python 2.7.5 が実行された
Member

koron commented Jul 20, 2014

その後に確認したこと。

  1. system と Mercurial の python27.dll を inhibit して Vimから Python実行 → DLLロードエラーで正しく止まった
  2. system の python27.dll だけを inhibit して、インストールしてある Python 2.7.6 を実行 → Mercurlal の Python 2.7.5 が実行された
@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

現状の理解と疑問

  • デバッガが拾わないことから exit が呼ばれている可能性が高い
  • ynkdir さんが上げてくれた initsite で止まってる可能性が濃厚
  • だとしたらあるケースが落ちないのが不明: あるケース=system の python27.dll だけを inhibit して、インストールしてある Python 2.7.6 を実行
Member

koron commented Jul 20, 2014

現状の理解と疑問

  • デバッガが拾わないことから exit が呼ばれている可能性が高い
  • ynkdir さんが上げてくれた initsite で止まってる可能性が濃厚
  • だとしたらあるケースが落ちないのが不明: あるケース=system の python27.dll だけを inhibit して、インストールしてある Python 2.7.6 を実行
@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

PYTHONPATHか…

Member

koron commented Jul 20, 2014

PYTHONPATHか…

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 20, 2014

Member

vim.exe で試すと出るメッセージはこれです "ImportError: No module named site"

Member

ynkdir commented Jul 20, 2014

vim.exe で試すと出るメッセージはこれです "ImportError: No module named site"

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

PYTHONPATH に関してさらにやったこと:

  1. Mercurial の python27.dll を活かし system のは inhibit
  2. 環境変数 PYTHONPATH に HKLM\SOFTWARE\Python\PythonCore\2.7\PythonPath からコピった値を設定
  3. Vimを 起動し import sys; print(sys.version) を実行 → Mercurial のPython 2.7.5 が実行されるのを確認

以上からわかったこと:

  • python27.dll は必須モジュール(site)のロードに失敗すると exit してしまう
  • 必須モジュールの読み込みPATHは最終的にレジストリにfallbackするが、py2exe を通した python27.dll はそのfallback機構が機能しない
    • 参照しているレジストリは HKLM\SOFTWARE\Python\PythonCore\2.7\PythonPath
    • 環境変数 PYTHONPATH が設定されていれば fallback 機構は動作しない

こんな感じですかね?

Member

koron commented Jul 20, 2014

PYTHONPATH に関してさらにやったこと:

  1. Mercurial の python27.dll を活かし system のは inhibit
  2. 環境変数 PYTHONPATH に HKLM\SOFTWARE\Python\PythonCore\2.7\PythonPath からコピった値を設定
  3. Vimを 起動し import sys; print(sys.version) を実行 → Mercurial のPython 2.7.5 が実行されるのを確認

以上からわかったこと:

  • python27.dll は必須モジュール(site)のロードに失敗すると exit してしまう
  • 必須モジュールの読み込みPATHは最終的にレジストリにfallbackするが、py2exe を通した python27.dll はそのfallback機構が機能しない
    • 参照しているレジストリは HKLM\SOFTWARE\Python\PythonCore\2.7\PythonPath
    • 環境変数 PYTHONPATH が設定されていれば fallback 機構は動作しない

こんな感じですかね?

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

crt0dat.c の doexit (exitの本体) 見てる。介入できないか、と。

Member

koron commented Jul 20, 2014

crt0dat.c の doexit (exitの本体) 見てる。介入できないか、と。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

ExitProcess をフックすれば止められそうだけど、atexit が全部実行されちゃうからなぁ…

Member

koron commented Jul 20, 2014

ExitProcess をフックすれば止められそうだけど、atexit が全部実行されちゃうからなぁ…

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

もうこうなると FAQ 化しちゃうのが良さ気かなぁ…

Member

koron commented Jul 20, 2014

もうこうなると FAQ 化しちゃうのが良さ気かなぁ…

@k-takata

This comment has been minimized.

Show comment
Hide comment
@k-takata

k-takata Jul 20, 2014

Member

msvcr*.dll にリンクしているので exit にフックを仕掛けることはできそうですが、そこまでするかという感じが。

Member

k-takata commented Jul 20, 2014

msvcr*.dll にリンクしているので exit にフックを仕掛けることはできそうですが、そこまでするかという感じが。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

Vim自身は msvcr100.dll で Python は msvcr90.dll なんですよね…
こういう時ってどうなるんです?

Member

koron commented Jul 20, 2014

Vim自身は msvcr100.dll で Python は msvcr90.dll なんですよね…
こういう時ってどうなるんです?

@k-takata

This comment has been minimized.

Show comment
Hide comment
@k-takata

k-takata Jul 20, 2014

Member

python*.dll が msvcr90.dll を参照する際に使っているインポートテーブルを書き換えることになりますので、python が呼ぶ exit だけをフックできるはずです。

Member

k-takata commented Jul 20, 2014

python*.dll が msvcr90.dll を参照する際に使っているインポートテーブルを書き換えることになりますので、python が呼ぶ exit だけをフックできるはずです。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

Pythonのソース見た。

initsite() は デフォで import site するもので、
Py_NoSiteFlag を立てればデフォではしなくなる。
実際 Module/main.c でも -S オプションで立ててる。

これ…立てるべきだろうか? ってVimから立てられるかこれ?

Member

koron commented Jul 20, 2014

Pythonのソース見た。

initsite() は デフォで import site するもので、
Py_NoSiteFlag を立てればデフォではしなくなる。
実際 Module/main.c でも -S オプションで立ててる。

これ…立てるべきだろうか? ってVimから立てられるかこれ?

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

https://gist.github.com/koron/aa53ddf11510e9d8942d

こんなパッチを試したら PythonMod_Init がコケて
2回めの Python_Init の呼び出しがエラーになるというw

Member

koron commented Jul 20, 2014

https://gist.github.com/koron/aa53ddf11510e9d8942d

こんなパッチを試したら PythonMod_Init がコケて
2回めの Python_Init の呼び出しがエラーになるというw

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

こんなパッチを試したら

これは 「Mercurial の python 使おうとしたら」 の意味。

Member

koron commented Jul 20, 2014

こんなパッチを試したら

これは 「Mercurial の python 使おうとしたら」 の意味。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

以下の条件を満たせればやる価値あり

  • go fail 後のエラーハンドリングをしっかりする
  • if_python において NoSite の副作用が無いことを確認できる
Member

koron commented Jul 20, 2014

以下の条件を満たせればやる価値あり

  • go fail 後のエラーハンドリングをしっかりする
  • if_python において NoSite の副作用が無いことを確認できる
@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

実際に失敗しているのは if_py_both.h の PyImport_ImportModule("os") だった。
PYTHONPATH が無いから当然か。

Member

koron commented Jul 20, 2014

実際に失敗しているのは if_py_both.h の PyImport_ImportModule("os") だった。
PYTHONPATH が無いから当然か。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

https://twitter.com/methane/status/490875720445345793 より

pip install とかでインストールした、標準ライブラリ以外のライブラリがほぼ import できなくなる。

びみょーw 落ちるよりはマシかもだけど…

Member

koron commented Jul 20, 2014

https://twitter.com/methane/status/490875720445345793 より

pip install とかでインストールした、標準ライブラリ以外のライブラリがほぼ import できなくなる。

びみょーw 落ちるよりはマシかもだけど…

@mattn

This comment has been minimized.

Show comment
Hide comment
@mattn

mattn Jul 20, 2014

Member

exit フックするより m = PyImport_ImportModule("site"); 自前で実行してエラーなら python 無効でいいと思う。

Member

mattn commented Jul 20, 2014

exit フックするより m = PyImport_ImportModule("site"); 自前で実行してエラーなら python 無効でいいと思う。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

方針決定

  • Py_NoSiteFlag を立てる at before Py_Initialize()
  • go fail; した後は、pythonを使えないように、フラグ管理する in Python_Init()
  • import site は各モジュールの初期化の最終段階で、自前でやる at begin/end of populate_module()
Member

koron commented Jul 20, 2014

方針決定

  • Py_NoSiteFlag を立てる at before Py_Initialize()
  • go fail; した後は、pythonを使えないように、フラグ管理する in Python_Init()
  • import site は各モジュールの初期化の最終段階で、自前でやる at begin/end of populate_module()
@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 20, 2014

Member

@mattn 同じこと考えてた。

Member

koron commented Jul 20, 2014

@mattn 同じこと考えてた。

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 21, 2014

Member

python3 も exit してませんか。 python 3.4.1 見てます。

Member

ynkdir commented Jul 21, 2014

python3 も exit してませんか。 python 3.4.1 見てます。

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 21, 2014

Member

python 3.2 から exit してるみたいです

Member

ynkdir commented Jul 21, 2014

python 3.2 から exit してるみたいです

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 21, 2014

Member

memo: cx_Freeze は pythonXX.dll に細工なし。

Member

ynkdir commented Jul 21, 2014

memo: cx_Freeze は pythonXX.dll に細工なし。

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 21, 2014

Member

Issue13533: Would like Py_Initialize to play friendly with host app
http://bugs.python.org/issue13533

Member

ynkdir commented Jul 21, 2014

Issue13533: Would like Py_Initialize to play friendly with host app
http://bugs.python.org/issue13533

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 21, 2014

Member

@ynkdir Thanks! svn にある 3.0 あたりのソース見て「え、ウソ?ないの?」って思ってとりあえず2.xだけ出しとくかーでした。
もうちょい議論が進んだら送ります。

Member

koron commented Jul 21, 2014

@ynkdir Thanks! svn にある 3.0 あたりのソース見て「え、ウソ?ないの?」って思ってとりあえず2.xだけ出しとくかーでした。
もうちょい議論が進んだら送ります。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 21, 2014

Member

Issue13533: Would like Py_Initialize to play friendly with host app

くっそ… exit() しちゃうほうが not friedly だっつーのw

Member

koron commented Jul 21, 2014

Issue13533: Would like Py_Initialize to play friendly with host app

くっそ… exit() しちゃうほうが not friedly だっつーのw

@h-east

This comment has been minimized.

Show comment
Hide comment
Member

h-east commented Jul 23, 2014

@mattn mattn closed this Jul 23, 2014

@k-takata

This comment has been minimized.

Show comment
Hide comment
@k-takata

k-takata Jul 24, 2014

Member

Python 3.xがまだ直っていないのでは?

Member

k-takata commented Jul 24, 2014

Python 3.xがまだ直っていないのでは?

@mattn

This comment has been minimized.

Show comment
Hide comment
@mattn

mattn Jul 24, 2014

Member

python3の方はエラーが出るんですよね?

Member

mattn commented Jul 24, 2014

python3の方はエラーが出るんですよね?

@k-takata

This comment has been minimized.

Show comment
Hide comment
@k-takata

k-takata Jul 24, 2014

Member

mercurial 付属の dll は 2.7 なので、3.4 の dll は無いため 3.4 ではエラーになっているのだと思います。
3.4 のオフィシャルでない dll があれば、3.4 でもエラーにならず落ちるのかもしれません。

Member

k-takata commented Jul 24, 2014

mercurial 付属の dll は 2.7 なので、3.4 の dll は無いため 3.4 ではエラーになっているのだと思います。
3.4 のオフィシャルでない dll があれば、3.4 でもエラーにならず落ちるのかもしれません。

@mattn

This comment has been minimized.

Show comment
Hide comment
@mattn

mattn Jul 24, 2014

Member

だれか確認出来る人いますか?

Member

mattn commented Jul 24, 2014

だれか確認出来る人いますか?

@mattn mattn reopened this Jul 24, 2014

@tyru

This comment has been minimized.

Show comment
Hide comment
@tyru

tyru Jul 24, 2014

Member

以前はTortoiseHgのDLLが2.7だったので再現できましたが、
3.4となるとPython3でpy2exeで適当なPythonスクリプトをexe化すればpython34.dllも一緒に吐かれそうですね。
それをPATHに含めれば検証できそうです。
2014/07/24 9:20 "mattn" notifications@github.com:

Reopened #594 #594.


Reply to this email directly or view it on GitHub
#594 (comment).

Member

tyru commented Jul 24, 2014

以前はTortoiseHgのDLLが2.7だったので再現できましたが、
3.4となるとPython3でpy2exeで適当なPythonスクリプトをexe化すればpython34.dllも一緒に吐かれそうですね。
それをPATHに含めれば検証できそうです。
2014/07/24 9:20 "mattn" notifications@github.com:

Reopened #594 #594.


Reply to this email directly or view it on GitHub
#594 (comment).

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 24, 2014

Member

python34.dll があって python3 のライブラリ等がないときは abort() するみたいです。
Fatal Python error: Py_Initialize: unable to load the file system codec ImportError: No module named 'encodings'

Member

ynkdir commented Jul 24, 2014

python34.dll があって python3 のライブラリ等がないときは abort() するみたいです。
Fatal Python error: Py_Initialize: unable to load the file system codec ImportError: No module named 'encodings'

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 24, 2014

Member

ああテストするだけならsite.pyを退避すれは良いんだわw
今になって気がついた。

Member

koron commented Jul 24, 2014

ああテストするだけならsite.pyを退避すれは良いんだわw
今になって気がついた。

@k-takata

This comment has been minimized.

Show comment
Hide comment
@k-takata

k-takata Jul 24, 2014

Member

python34.dll があって python3 のライブラリ等がないときは abort() するみたいです。

python33.dll でもそうなることが確認できました。
@koron さんのpython3用パッチでabortしなくなるかどうかは未確認。

ああテストするだけならsite.pyを退避すれは良いんだわw

そんな手があったとは。*.pycも退避しないと。

Member

k-takata commented Jul 24, 2014

python34.dll があって python3 のライブラリ等がないときは abort() するみたいです。

python33.dll でもそうなることが確認できました。
@koron さんのpython3用パッチでabortしなくなるかどうかは未確認。

ああテストするだけならsite.pyを退避すれは良いんだわw

そんな手があったとは。*.pycも退避しないと。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 24, 2014

Member

@ynkdir

Issue13533: Would like Py_Initialize to play friendly with host app
http://bugs.python.org/issue13533

教えてもらったコレを読む限り、
2.x系は2.7から、3.x系は3.3から変更になったように読めるんですが
3.2からと判断した根拠はソースまでみた結果でしょうか?

Member

koron commented Jul 24, 2014

@ynkdir

Issue13533: Would like Py_Initialize to play friendly with host app
http://bugs.python.org/issue13533

教えてもらったコレを読む限り、
2.x系は2.7から、3.x系は3.3から変更になったように読めるんですが
3.2からと判断した根拠はソースまでみた結果でしょうか?

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 24, 2014

Member

3.2からと判断した根拠はソースまでみた結果でしょうか?

はい

Member

ynkdir commented Jul 24, 2014

3.2からと判断した根拠はソースまでみた結果でしょうか?

はい

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 24, 2014

Member

@ynkdir ありがとうございます!

Member

koron commented Jul 24, 2014

@ynkdir ありがとうございます!

@ynkdir

This comment has been minimized.

Show comment
Hide comment
@ynkdir

ynkdir Jul 24, 2014

Member

あーただ、↑にも書いてますが python3 の場合は initsite の前に codec の初期化で落ちるのでこれは回避できなさげです

Member

ynkdir commented Jul 24, 2014

あーただ、↑にも書いてますが python3 の場合は initsite の前に codec の初期化で落ちるのでこれは回避できなさげです

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 24, 2014

Member

ありゃま。2.7ではinitsiteのあとにcodecの初期化してたみたいでしたね…変わったのか。

Member

koron commented Jul 24, 2014

ありゃま。2.7ではinitsiteのあとにcodecの初期化してたみたいでしたね…変わったのか。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 24, 2014

Member

ん? ということは py2exec したモノでもcodecは初期化できるのでは?

Member

koron commented Jul 24, 2014

ん? ということは py2exec したモノでもcodecは初期化できるのでは?

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Jul 24, 2014

Member

いや違うか。

  • PYTHONPATHの設定が不正で読み込めない

ってケースでしたね。

Member

koron commented Jul 24, 2014

いや違うか。

  • PYTHONPATHの設定が不正で読み込めない

ってケースでしたね。

@koron

This comment has been minimized.

Show comment
Hide comment
@koron

koron Aug 14, 2014

Member

#610 に継続しました。こちらは閉じます。

Member

koron commented Aug 14, 2014

#610 に継続しました。こちらは閉じます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment