diff options
Diffstat (limited to 'public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3')
| -rw-r--r-- | public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html | 148 |
1 files changed, 74 insertions, 74 deletions
diff --git a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html index 6896530..a7f86b3 100644 --- a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html +++ b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html @@ -83,23 +83,23 @@ </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - try { - f(g() / __LINE__); - } catch (Throwable $e) { - while ($e = $e->getPrevious()) printf('%c', $e->getLine() + 23); - echo "\n"; - } - function f(int $i) { - if ($i < 0) f(); - try { +try { + f(g() / __LINE__); +} catch (Throwable $e) { + while ($e = $e->getPrevious()) printf('%c', $e->getLine() + 23); + echo "\n"; +} +function f(int $i) { + if ($i < 0) f(); + try { match ($i) { - 0 => 0 / 0, + 0 => 0 / 0, - 15, 36 => 0 / 0, - 14 => 0 / 0, - 37 => 0 / 0, + 15, 36 => 0 / 0, + 14 => 0 / 0, + 37 => 0 / 0, @@ -110,16 +110,16 @@ - 6 => 0 / 0, + 6 => 0 / 0, - 5 => 0 / 0, + 5 => 0 / 0, - 22 => 0 / 0, + 22 => 0 / 0, - 34, 35 => 0 / 0, + 34, 35 => 0 / 0, @@ -128,10 +128,10 @@ - 25 => 0 / 0, - 17, 21 => 0 / 0, + 25 => 0 / 0, + 17, 21 => 0 / 0, - 24, 32 => 0 / 0, + 24, 32 => 0 / 0, @@ -139,12 +139,12 @@ - 33 => 0 / 0, + 33 => 0 / 0, - 16 => 0 / 0, + 16 => 0 / 0, - 18 => 0 / 0, + 18 => 0 / 0, @@ -153,37 +153,37 @@ - 7 => 0 / 0, + 7 => 0 / 0, - 2 => 0 / 0, - 1, 20 => 0 / 0, - 10, 28 => 0 / 0, - 8, 12, 26 => 0 / 0, - 4, 9, 13 => 0 / 0, + 2 => 0 / 0, + 1, 20 => 0 / 0, + 10, 28 => 0 / 0, + 8, 12, 26 => 0 / 0, + 4, 9, 13 => 0 / 0, - 31 => 0 / 0, + 31 => 0 / 0, - 29 => 0 / 0, + 29 => 0 / 0, - 11 => 0 / 0, + 11 => 0 / 0, - 3, 19, 23 => 0 / 0, + 3, 19, 23 => 0 / 0, - 27 => 0 / 0, + 27 => 0 / 0, - 30 => 0 / 0, + 30 => 0 / 0, }; - } finally { + } finally { f($i - 1); - } - } + } +} @@ -191,9 +191,9 @@ - function g() { - return __LINE__; - }</code></pre> +function g() { + return __LINE__; +}</code></pre> <p> "Catchline" と名付けた作品。実行するとトークン<code>#base64_decode('SGVsbG8sIFdvcmxkIQ==')</code>が得られる。 @@ -239,18 +239,18 @@ <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - try { - try { - throw new Exception("Error 1"); - } finally { - throw new Exception("Error 2"); - } - } catch (Exception $e) { - echo $e->getMessage() . PHP_EOL; - // => Error 2 - echo $e->getPrevious()->getMessage() . PHP_EOL; - // => Error 1 - }</code></pre> +try { + try { + throw new Exception("Error 1"); + } finally { + throw new Exception("Error 2"); + } +} catch (Exception $e) { + echo $e->getMessage() . PHP_EOL; + // => Error 2 + echo $e->getPrevious()->getMessage() . PHP_EOL; + // => Error 1 +}</code></pre> <p> この知識を元に、トークンの出力部を解析してみる。 @@ -264,14 +264,14 @@ </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - try { - f(g() / __LINE__); - } catch (Throwable $e) { - while ($e = $e->getPrevious()) { - printf('%c', $e->getLine() + 23); - } - echo "\n"; - }</code></pre> +try { + f(g() / __LINE__); +} catch (Throwable $e) { + while ($e = $e->getPrevious()) { + printf('%c', $e->getLine() + 23); + } + echo "\n"; +}</code></pre> <p> 出力をおこなう<code>catch</code>節を見てみると、<code>Throwable::getPrevious()</code>を呼び出してエラーチェインを辿り、<code>Throwable::getLine()</code>でエラーが発生した行数を取得している。その行数に<code>23</code>なるマジックナンバーを足し、フォーマット指定子<code>%c</code>で出力している。 @@ -281,7 +281,7 @@ フォーマット指定子<code>%c</code>は、整数を ASCII コード<span></span>と見做して印字する。トークン<code>#base64_decode('SGVsbG8sIFdvcmxkIQ==')</code>の<code>b</code>であれば、ASCII コード<code>98</code>なので、75 行目で発生したエラー、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code> 1, 20 => 0 / 0,</code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>1, 20 => 0 / 0,</code></pre> <p> によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。 @@ -299,9 +299,9 @@ </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code>function f(int $i) { - if ($i < 0) f(); - try { - match ($i) { + if ($i < 0) f(); + try { + match ($i) { 0 => 0 / 0, // 12 行目 @@ -313,23 +313,23 @@ // (略) 30 => 0 / 0, // 97 行目 - }; - } finally { - f($i - 1); - } - }</code></pre> + }; + } finally { + f($i - 1); + } +}</code></pre> <p> 前述のように、<code>finally</code>節でエラーを投げると PHP 処理系が<code>$previous</code>を設定する。ここでは、エラーを繋げるために<code>f()</code>を再帰呼び出ししている。最初に<code>f()</code>を呼び出している箇所を確認すると、 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - try { - f(g() / __LINE__); // 3 行目</code></pre> +try { + f(g() / __LINE__); // 3 行目</code></pre> <pre class="highlight" language="php" linenumbering="unnumbered"><code>function g() { - return __LINE__; // 111 行目 - }</code></pre> + return __LINE__; // 111 行目 +}</code></pre> <p> <code>f()</code>には<code>111 / 3</code>で<code>37</code>が渡されることがわかる。そこから 1 ずつ減らして再帰呼び出ししていき、0 より小さくなったら<code>f()</code>を引数なしで呼び出す。引数の数が足りないと呼び出しに失敗するので、再帰はここで止まる。 |
