マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

もう脆弱性なんて怖くない(※ただしLaTeXの意味で)(2)

前回の続き)
「保護付」の完全展開

特別な措置とは、具体的には次のようなものである。

  • 完全展開する際に、「保護(protect)」されたトークンは展開されない。

このような展開のことを「保護付き完全展開(protected full expansion)」と呼ぶことにする。ここで、トークンが「保護」されているとは次のいずれかが成り立つことである。

  • 当該のトークンの前に \protect が置かれている。
  • 当該のトークンの意味が \DeclareRobustCommand で定義されたマクロである。((実は、\DeclareRobustCommand によるマクロ定義は内部で \protect を使っているのだが、少し仕組みがややこしいのでここでは別に扱う。))

「保護付き完全展開」が定義できれば、それを用いて「頑強」を規定することができる。(その否定が「脆弱」である。)

  • あるマクロが頑強であるとは、そのマクロ(に「正しい引数」を伴ったトークン列)を「保護付き完全展開」して得られるトークン列を実行したときに「正しい動作」になることである。
    ※ 完全展開可能の定義と同様に、ここでも何が「正しい」かが予め決められていることを前提としていることに注意。完全展開可能の場合と異なり、ここでは動作で「正しさ」を判断することにした。

例として、以下のマクロ定義を考える。

% 以下の3つのマクロで, 引数は10進表記の整数に限る
\def\expandableA#1{\romannumeral#1 }
\def\fragileA{{\count@=#1 \multiply\count@\tw@ \the\count@}}
\DeclareRobustCommand*\protectedA[1]{%
  {\count@=#1 \multiply\count@\tw@ \the\count@}}
\def\testA{\expandableA{21}/\fragileA{21}/\protectedA{21}}

上の例で、\expandableA{<整数>} は引数の整数をローマ数字で表した文字列を出力し、\fragileA{<整数>} は引数の整数の 2 倍の値を(10 進数字で)出力する、ということは容易に理解できる。なので、その各々を「正しい動作」と規定することにしよう。\protectedA の定義本体は \fragilaA と全く同一である(だから「正しい動作」も同じ)が、\DeclareRobustCommand で定義されたため、「生来的に保護付」なマクロになっている。最後の \testA については「xxi/42/42」が出力されるべきなのでこれを「正しい動作」と決めよう。さて、この \testA は頑強であるかないか。

まずは、\testA の「保護付完全展開」がどうなるかを考える。「生来的に保護付」な \protectedA が展開されないことを除いて通常の完全展開と同じなので以下のようになる。(ただし、展開時の \count@ の値を 123 とする。)

\testA
↓
\expandableA{21}/\fragileA{21}/\protectedA{21}
↓
xxi/{\count@ =21 \multiply \count@ \tw@ 123}/\protectedA {21}

さらに、この展開結果のトークン列を実行すると、「xxi/123/42」が出力される。ところが、これは \testA の「正しい動作」と食い違う。従って、\testA は頑強でなく脆弱である。

\testA が脆弱なのは、\fragileA が展開されてしまうからである。従って、\fragileA を「保護」することにする。つまり、次のようなマクロを考える。

\def\testB{\expandableA{21}/\protect\fragileA{21}/\protectedA{21}}

すると、\testB の「保護付完全展開」の結果は「xxi/\fragileA {21}/\protectedA {21}」であり、さらにこれを(展開限定でない場所で)実行すると「xxi/42/42」が出力される。ゆえに、\testB は頑強であることが判る。 ついでに、\expandableA\fragileA\protectedA 自体の頑強製を同様の手順で検査してみると、\fragileA は脆弱で、他の 2 つは頑強であることが判る。特に、「生来的に保護付」なマクロは、その定義本体の内容が何であっても(そもそも展開されないので)必ず頑強となる。だから、「生来的に保護付」なマクロを定義する命令は \DeclareRobustCommand と名づけられている。*1

(まだ解答に辿り着かないので次回に続く)

*1:ただし私の感覚では、「Robust」でなくて「Protected」とした方が適切だと思う。