https://zenn.dev/satoru_takeuchi/articles/e35681658e5bd7
gcc v12.1において、C++の正規表現ライブラリstd::regexに、正規表現のバリデーションを改善するパッチ(以下"改善パッチ"と表記)が取り込まれました。改善パッチによって、これまではバリデーションにひっかからなかった不正な正規表現文字列が"正しく"不正なものと認識されて例外が発生するようになりました。
これだけ聞けばいいことだけのように思えるかもしれませんが、実はそうでもなかったりします。経験豊富なかたであれば見た瞬間ゾッとしたかもしれません。本記事では、この一見問題なさそうな改善パッチによって発生しうる問題、および、その具体的例について紹介するとともに、この手のパッチを当てるかどうかは難しい判断になるという知見を共有します。
[\\w-a]
)」というstd:regexからすると不正な正規表現文字列を与えているコードがあるstd::regexは不正な正規表現文字列をユーザが与えた場合、regex_errorという例外が発生します。ところが従来は「"["と"]"の間に"\w"のような文字クラスを指定する(例: [\\w-a]
)」というstd:regexからすると不正な文字列を与えても例外は発生しませんでした。前節において紹介したパッチを当てるとこの問題は解決します。以下、このパッチのコミットメッセージからの引用です。
std::regex currently allows invalid bracket ranges such as [\\w-a] which
are only allowed by ECMAScript when in web browser compatibility mode.
It should be an error, because the start of the range is a character
class, not a single character. The current implementation of
_Compiler::_M_expression_term does not provide a way to reject this,
because we only remember a previous character, not whether we just
processed a character class (or collating symbol etc.)
ここからはgccに限らずあらゆるプログラムで起こりうるバグ修正可否の判断について、これまで述べてきたgccの改善パッチを題材として書きます。
改善パッチには何の疑問もないように見えますが、実はそうではありません。前節において述べた不正な正規表現文字列を与えた上でたまたま動いてしまっていたプログラムを改善パッチを含んだgccでビルドしたら、たとえプログラム自身はコードを一切変更していなくても、問題のコードを実行したときに例外が発生するようになってしまうのです。例外処理をサボっていたような場合はプログラムのクラッシュなどの問題が発生します。「それ、悪いのは呼び出し側では?」といわれるとその通りなのですが、とにかく、これまで(たまたま)動いていたプログラムが動かなくなるのです。
ここからが難しい判断を迫られるところです。gccは非常に多くのプログラムから使われており、かつ、誰が使っているのかの全体像を把握するのは困難なので、改善パッチをあえて当てずに、バグをバグのまま残して、もともと動いていたプログラムが動くようにし続けるという選択をすることがあります[1]。gcc以外にもLinuxなど非常に修正時の影響度が高いソフトウェアではこのような選択を迫られることがよくあります。大変そうですね。
なお筆者はgcc開発者たちが改善パッチを適用した判断について何か否定的な思いを持っているわけではありません。なぜなら彼らがどういう情報を持った上でどういう理由で改善パッチの適用に至ったということがわからないので、何も知らない外野の立場で「こうしておけばよかった」などというのは無責任だと思うからです。この記事の目的は、あくまで「このような場合には修正しない場合もある」という一般的な選択肢をみなさんに知ってもらうことです。
最近Cephは重要な脆弱性を修正するためv17.2.2という新しいバージョンをリリースしました。v17.2.2はv17.2.1に脆弱性をふさぐための最小限の修正だけ入れたものだったのですが、v17.2.2へのアップデート直後から脆弱性の修正とは全然関係ないところで非常に重要なdaemonがクラッシュし続けてしまい、Cephクラスタ全体が機能しなくなるという問題が発生しました。
ここで勘のいいかたは気づいたかもしれませんが、その重要なdaemonはまさに改善パッチによって例外が発生するようになる不正な正規表現文字列を使っており、さらにCeph v17.2.1は改善パッチを当てていないgccでビルドした一方でv17.2.2は改善パッチを含むgcc[2]でビルドしたという偶然が重なったのです。この問題を修正するために、数日後にはさらにv17.2.3がリリースされました。