Skip to content
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

macOS で job_start を使い一定サイズ以上の文字列を送信すると SEGV する #1161

Closed
heavenshell opened this issue Mar 31, 2018 · 6 comments

Comments

@heavenshell
Copy link
Member

heavenshell commented Mar 31, 2018

報告の内容

macOS で job_start を使用して一定サイズのファイルを in_iobuffer で外部プログラムの STDIN に突っ込んだ際に SEGV が発生する。

再現手順

  1. test.vim を開く
  2. :so % で autocmd を有効にする
  3. :e sample.txt で開く
  4. <S-g>oa<ESC> でファイル末尾に行き Insert モードで適当に文字を入力し ESC をし、InsertLeave が発生してバッファの内容を stdin.py に送信する

期待する動作は {"count": 15801} という文字数を数えたものが Vim に返ってくるが、
macOS では SEGV が発生しました。

なお文字数が 15800 以下だと発生しません。
また Linux では 15801 文字以上でも発生しません(適当に文字数を 10 倍とかでかいサイズにしても起きなかったです)。

パッチ

https://gist.github.com/heavenshell/c6c6d019e2aa284623509b0dd106f634#file-src_channel-c-diff

質問

channel_write_input(channel); を辿って行くと channel_write_in() -> ch_close_part()FD を閉じているように見えます。
閉じた後に FD_CLR(in_part->ch_fd, wfds); を呼ぶと SEGV するように見えました(in_part->ch_fd の値は -1)。

単純に INVALID_FD の判定で良いのでしょうか?
直接の変更は vim/vim@3c51840#diff-3eef145ca58a199bac70eef155e806aeR4094 こちらの対応によるものだと思いますが、Terminal に影響があるのかがよくわかってないです…。

パッチの添削をお願いしたいです。

Vimのバージョン

8.0.1655(3/31 時点の最新をビルド)

OSの種類/ディストリ/バージョン

  • macOS Sierra(El Capitan)

Linux(Ubuntu 16.04)でも確認しましたが、こちらの環境では発生しなかっため、macOS 特有の不具合かもしれません。

使用している or 関係していそうなプラグイン

特になし

その他

FD_CLR の実体は https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/sys/_types/_fd_def.h#L62 こちらです。

@mattn
Copy link
Member

mattn commented Mar 31, 2018

chanel_write_input では close されて fd が -1 になるので __DARWIN_FD_CLR で添え字のチェックしてないので落ちた、という事だと思います。このパッチで合ってると思います。

@heavenshell
Copy link
Member Author

sent patch.
vim/vim#2769

ドキドキ。

@ichizok
Copy link
Member

ichizok commented Apr 2, 2018

glibc, *BSD, solaris あたりを見てみましたが、FD_* で添字チェックしている実装はないですね。
POSIX的には fd < 0 の場合は未定義動作(=利用者側の責任)なので、わざわざ実装側でやらないのでしょう。

@mattn
Copy link
Member

mattn commented Apr 2, 2018

ちなみに Windows は添え字ではないので落ちない実装でした。

#ifndef FD_CLR
#define FD_CLR(fd,set)							\
  do {									\
	u_int __i;							\
	for(__i = 0; __i < ((fd_set *)(set))->fd_count; __i++) {	\
		if (((fd_set *)(set))->fd_array[__i] == fd) {		\
			while (__i < ((fd_set *)(set))->fd_count - 1) {	\
				((fd_set *)(set))->fd_array[__i] =	\
				 ((fd_set *)(set))->fd_array[__i + 1];	\
				__i++;					\
			}						\
			((fd_set *)(set))->fd_count--;			\
			break;						\
		}							\
	}								\
  } while(0)
#endif /* !FD_CLR */

@h-east
Copy link
Member

h-east commented Apr 3, 2018

8.0.1657
vim/vim@9af9778

in_part->ch_fdのクリアはchannel_write_input()を使用するコードになりました。

@heavenshell
Copy link
Member Author

ありがとうございます。なるほど。これでいいんですね。
再現手順試したら、完璧でした。
問題解決したので閉じます。

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

No branches or pull requests

5 participants