sakura-editor / sakura

SAKURA Editor (Japanese text editor for MS Windows)
https://sakura-editor.github.io/
Other
1.25k stars 163 forks source link

64bit版で2GBより大きいサイズのテキストのコピペをする事が出来ない #1575

Open beru opened 3 years ago

beru commented 3 years ago

問題内容

64bit版で2GBより大きいサイズのテキストのコピペをする事が出来ません。

もし処理出来ないならエラーメッセージを出して処理を中断する事が望ましいです。ただし処理できるようにする方がよりベターだと思います。

そもそもそんな大きいサイズのテキストをコピペする事は一般的な用途では無いと思いますが、64bit版なら出来そうな事に対応していない点の調査をしていて気づきました。

再現手順

test.7z.zip

上記のファイルをダウンロードして test.7z にリネームした後に展開すると 3.81 GBのテキストファイルが得られます。中身は あいうえお の記述を単にコピペで連続させたものです。行数は8192行ですが1行のサイズが大きいです。

64bit版のサクラエディタであれば開くのに時間は掛かりますが開くこと自体は十分にメモリを積んでいれば問題なく行えます。

しかし全選択してコピーする操作(Ctrl + A, Ctrl + C)を行うといつまで経っても処理が完了しません。なのでタスクマネージャーなどで強制終了させざるを得ません。

再現頻度

常に再現します。

確認は 8a22482a42a6f9c94353c4c25af87b2bd45aa81d で行いました。

問題のカテゴリ

環境情報

Windows 10 Pro 64bit バージョン 20H2

サクラエディタ   v2.4.2.0 64bit dev Alpha Version
(GitHash 535b161f5e937856ced6640f7b32a65afd82d322)
(GitURL git@github.com:sakura-editor/sakura.git)

      Compile Info: V_A641928 WPR WIN601/I800/C000/N601
      Last Modified: 2021/3/9 01:42:51
berryzplus commented 3 years ago

報告されていないCMemoryの不具合と考えられます。

エディタに文字を表示するためのメモリ(上限は2GB、スレッドヒープに存在)  上限2GBは「1行あたり」の制約なので可能。  👇 コピーの前準備としてメモリにコピー(上限は2GB、スレッドヒープに新たに確保)  intでは3.81GBを表現できないので1メモリに詰め込もうとすると失敗します。

対策には以下3つが必要と思います。

  1. CMemoryの内部的なサイズ型をsize_tに変更する修正。(影響小)
  2. CMemoryに設定するデータ型をsize_tに変更する修正。(影響中)
  3. CMemoryが返却するサイズ型をsize_tに変更する修正。(影響極大)
beru commented 3 years ago

CNativeW : public CNative : protected CMemory という形の継承階層ですが、特に CNativeW は各所で使われているので影響範囲がとても広くて対処が難しいですね。例えば各行の実データの CDocLine::m_cLine とかでです。

1行の上限が2GBという制約は問題ないと思います。ただ64bitビルドでは4GBより大きいサイズのデータを各所で扱えるようにはしたいですね。

CMemorysize_t 型を使うと64bitビルドでインスタンスのサイズが増加してしまうのは嫌だなって思います。ただ大きなサイズのメモリを扱うために別の型を追加するのもちょっとどうなのか判断が付きかねます。。

berryzplus commented 3 years ago

CNativeW : public CNative : protected CMemory という形の継承階層ですが、特に CNativeW は各所で使われているので影響範囲がとても広くて対処が難しいですね。例えば各行の実データの CDocLine::m_cLine とかでです。

1行の上限が2GBという制約は問題ないと思います。ただ64bitビルドでは4GBより大きいサイズのデータを各所で扱えるようにはしたいですね。

CMemorysize_t 型を使うと64bitビルドでインスタンスのサイズが増加してしまうのは嫌だなって思います。ただ大きなサイズのメモリを扱うために別の型を追加するのもちょっとどうなのか判断が付きかねます。。

issueを解決する方向としては、 一時バッファの確保方法を変更して 2GB超 を確保できるようにするのと GlobalAlloc に 2GB超 のデータを渡せるようにする感じかな、と思っています。

CMemoryのインスタンスサイズを拡張してはならないとすると、 内部データを int から size_t に変えられないので、ややめんどうです。

C Run-Time の _HEAP_MAXREQ は 32bit でも INT_MAX より大きいので、 内部データを unsigned化 する作業はやったほうが良さそうです。

int 32bit版でも64bit版でも31bit利用可能。 uint32_t 32bit版でも64bit版でも32bit利用可能。

その前に CMemory::AllocBuffer の実装がなんかクサいのをなんとかしたいです。。。

beru commented 3 years ago

CMemoryのインスタンスサイズを拡張してはならないとすると、 内部データを int から size_t に変えられないので、ややめんどうです。

いや、拡張しても良いと思います。自分がCMemoryのインスタンスサイズを増やしたくない理由は

ですが、仮に CMemory のメンバー m_nRawLen, m_nDataBufSize の型を int から size_t に変更しても sizeof(CMemory) は 8 しか増加しないので、64bitビルド時に 100万行でやっと 8MB の違いです。そのぐらいなら良いんじゃないかとも思えてきます。

C Run-Time の _HEAP_MAXREQ は 32bit でも INT_MAX より大きいので、 内部データを unsigned化 する作業はやったほうが良さそうです。

int 32bit版でも64bit版でも31bit利用可能。 uint32_t 32bit版でも64bit版でも32bit利用可能。

uint32_t にすれば少し制限が緩和されますね。ただし警告が増えそうです。

その前に CMemory::AllocBuffer の実装がなんかクサいのをなんとかしたいです。。。

独自の CMemory を使わずに std::vector<char> で良いんじゃないかと昔思ったりしましたが、CMemory は色々な箇所で使われているので書き換える手間に見合ったメリットが無さそうです。

berryzplus commented 3 years ago

冷静にコードを眺めると、1行に保持できる「データ量」の上限が2GBでした。

データ量=2GB(2ギガバイト) 文字数(1文字あたり2bytes)=1G文字

beru commented 3 years ago

そうですね。1行分の最大文字数は 30bit (1024 1024 1024) が正しいですね。訂正が面倒でしていませんでした。 この1行の制限自体は仕様で良いんじゃないかと思いますが、

まぁ言うは易し(Talk Is Cheap)で実現するのは大変そうです。。

berryzplus commented 3 years ago

概要

この件「64bit版で2GBより大きいサイズのテキストのコピペをする事が出来ない」について、 あるべき結論の認識が変わったので書いておきます。

結論

仕様です。 64bit版でも 2GB より大きいサイズのテキストを扱うことはできません。 扱えるテキストの最大サイズは、UTF16換算で 2G - 1 文字 までです。

結論の詳細

32bit版では、UTF16換算のテキストサイズが 2G - 1 文字 に収まる場合でも、2GBを超えるファイルは開けません。 64bit版では、UTF16換算のテキストサイズが 2G - 1 文字 に収まる場合に限り、2GBを超えるファイルを開くことができます。

bits 文字数上限 ファイルサイズ上限の目安(UTF16) ファイルサイズ上限の目安(UTF32)
32bit版 2,147,483,646 4,294,967,294 4,294,967,294
64bit版 2,147,483,646 4,294,967,294 8,589,934,588

TODO事項

beru commented 3 years ago

64bit版で読み込めるファイルサイズの上限が減ってしまうような変更は行わない方が良いと思いますよ。

berryzplus commented 3 years ago

64bit版で読み込めるファイルサイズの上限が減ってしまうような変更は行わない方が良いと思いますよ。

たぶん誤解だと思いますが、新たな制限を作る話ではなく、仕様的な限界を明示しよう、って話です。

状況まとめ GitHub移行以前 メモリ上限は2GB、扱える文字数の上限は1G文字、32bit版では2GBを超えるファイルは開かない。 CMemory変更後 メモリ上限は4GB、扱える文字数の上限は2G文字、32bit版では2GBを超えるファイルは開かない。

ファイルサイズを制限する意味はないですね。 2GB上限を超えた場合に使う変な名前の関数も撤廃したいっすね(闇

一度に編集できる文字数に上限を定める「べき」の論拠は、 Text Services Frameworkが2G文字を超えるテキストの編集に対応していないからです。 https://docs.microsoft.com/ja-jp/windows/win32/api/textstor/nf-textstor-itextstoreacp-gettext

拡張形式として、2G上限を突破する手段があってもよいとは思います。 上限を超える方法を用意するかどうかは別にして、上限は設けるべきだと思います。

beru commented 3 years ago

https://github.com/sakura-editor/sakura/issues/1575#issuecomment-835138576 に書かれた「仕様」というのは、このぐらいまでのサイズのデータなら各処理で問題なく扱うことが出来るサイズなのかもしれません。しかし実際には場所毎に扱う事が出来るサイズというのは異なるので、もっと大きいサイズのファイルも構成によっては読み込んで表示する事が出来ると思います。

自分が「仕様」を策定する事に否定的なのは、もともと仕様を細かく文書化して設計や実装が行われたソフトウェアではないのに、現状の実装上の制限から後付けで最大公約数的な「仕様」を謳う事です。適切に実装がされていれば解決出来るはずの問題を、問題の定義をすり替えて無かった事にしようとしているように見えます。

現状の実装の問題点とまっとうな対策案は berryzplusさん自身が書いたコメント https://github.com/sakura-editor/sakura/issues/1575#issuecomment-793831350 にまとめられていると思います。どうしてそこから後退してしまったのか分かりません。問題の解決を急いでいるのでしょうか?

berryzplus commented 3 years ago

#1575 (comment) に書かれた「仕様」というのは、このぐらいまでのサイズのデータなら各処理で問題なく扱うことが出来るサイズなのかもしれません。しかし実際には場所毎に扱う事が出来るサイズというのは異なるので、もっと大きいサイズのファイルも構成によっては読み込んで表示する事が出来ると思います。

具体的な値を示してあるために、分かりづらかったかも知れません。 記載しているファイルサイズは目安です。

ドキュメント全体の上限文字数を定めたら、 快適に編集できる環境を提供できるんじゃないか? と言う提案のつもりです。

現状は1.38GBを開けると言っても使用に耐えない重さです。 「開ける」なら、快適に編集できたほうがいいと思います。

現状の実装の問題点とまっとうな対策案は berryzplusさん自身が書いたコメント #1575 (comment) にまとめられていると思います。どうしてそこから後退してしまったのか分かりません。問題の解決を急いでいるのでしょうか?

ぼくも当初は、サイズ値を64bit化するのが「まっとう」だと思っていました。

しかし、CNativeWのサイズ値を64bit化する対応では、4GB超のメモリが必要なときに、メモリをスレッドヒープから確保することになってしまうので、パフォーマンスに激しい悪影響が出そうだ、ということに気付きました。

で、ドキュメントデータの確保先がヒープでなくても構わない手法として、以前から導入検討していたtsfのCOMインターフェースのシグニチャを確認したところ、tsfが64bit対応してないことに気付きました。

それはそれとして、元々の事象(=無応答になる)はバグとして対処するのが良いと思います。 編集上限文字に制限をかけたからと言って、無応答をなかったことにはできないですし。

berryzplus commented 3 years ago

しばらく考えてみました。

content-typetext/plain でも2GBを超えたらもうテキストじゃない気がします。

対応は、それを踏まえて行いたいです。


こないだ2chの書き込みでこんなやりとりを見ました。

具体的にはどのくらいのファイルサイズ?

10GBくらい

・・・。

個人的には、500MBを超えたらログファイルじゃないような気がします。 何故かというと「メモ帳(=notepad.exe)」で開ける上限が500MBだからです。 「ログファイルじゃない」というより、「ログファイルとして使い物にならない」ってことですが。

ログファイルは、運用環境のシステムイベントを記録しておき、トラブルの対策に役立てるためのものです。 運用環境にインストールするプログラムは、ほとんどの場合「システムに必要なもの」に限られます。 ログファイルを見るためのプログラムが「システムに必要」と言えるかは微妙だと思います。 運用保守に余計なプログラムを要さないことは、一般的なシステムの非機能要件だと考えるからです。

10GBを超えるようなログファイルは、おそらくデバッグトレースの垂れ流しを記録した場合とかにできると思います。

たぶん、システム屋がやるべきことは、 10GBを超えるような自称「ログファイル」を吐くクソシステムに、 「それはシステムじゃねぇよ」とNOを叩きつけることだと思うんです。

arigayas commented 3 years ago

Apacheを何も工夫せずにエラーログやアクセスログを全て保存する設定にして そこそこアクセスされるWebサービスを運営していれば数年放置していれば10GBクラスにはなりそうですが・・・。

たぶん、システム屋がやるべきことは、 10GBを超えるような自称「ログファイル」を吐くクソシステムに、 「それはシステムじゃねぇよ」とNOを叩きつけることだと思うんです。

上記のようなシステムはクソシステムだと思いますが 10GBクラスのファイルを難なく開くことが出来るようになったら、 もの凄いと思いますし、強いテキストエディタだと思います。

berryzplus commented 3 years ago

Visual studio 2022(次期バージョン)のプレビューが始まっています。 https://visualstudio.microsoft.com/ja/vs/preview/vs2022/

vs2022の最大の「売り」はIDEプロセスの64bit化らしいです。

従来頑なに 32bit 版プロセスで構成していたものを、 次回から突然64bit版プロセスに一本化するらしいです。

失敗が約束されてる雰囲気をビシビシ感じるわけですが、 初版リリースがまともに動かないのはいつものことなので、 ある意味「仕様通り」のリリース計画であるとも考えられます。


一応、このファイルを開こうとしてみました。

test.7z.zip

見せてもらおうか、マイクロソフトの次期IDEの性能とやらを。

image

・・・。

予想通りというかなんというか、開くことすらできませんでした。 このテストファイル、1.38GBしかないんですけどね。 ※text services frameworkの上限である「2GB」にすら達していませんが、無理でした。

というか、ダークモードにも対応してませんね・・・。

berryzplus commented 3 years ago

というか、ダークモードにも対応してませんね・・・。

👆これ誤解。