From 98682c7a8792e7e79e487fea5024d25cee5aa310 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Wed, 15 Mar 2023 01:36:13 +0900 Subject: fix(nuldoc):
 contained unnecessary whitespaces inside it

---
 .../phperkaigi-2023-unused-token-quiz-3/index.html | 40 +++++++---------------
 1 file changed, 13 insertions(+), 27 deletions(-)

(limited to 'public/posts/2023-01-10')

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 3100b8e..81d673f 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
@@ -82,8 +82,7 @@
               注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
             

-
-              <?php
+            
<?php
     try {
     f(g() / __LINE__);
     } catch (Throwable $e) {
@@ -194,8 +193,7 @@
 
     function g() {
     return __LINE__;
-      }
-            
+ }

"Catchline" と名付けた作品。実行するとトークン#base64_decode('SGVsbG8sIFdvcmxkIQ==')が得られる。 @@ -239,8 +237,7 @@ このうち 1つ目のケースは、finally節の中でエラーを投げると PHP 処理系が勝手に$previousを設定してくれる。

-
-                <?php
+              
<?php
 
       try {
       try {
@@ -253,8 +250,7 @@
       // => Error 2
       echo $e->getPrevious()->getMessage() . PHP_EOL;
       // => Error 1
-        }
-              
+ }

この知識を元に、トークンの出力部を解析してみる。 @@ -267,8 +263,7 @@ 出力部をコメントや改行を追加して再掲する:

-
-                <?php
+              
<?php
       try {
       f(g() / __LINE__);
       } catch (Throwable $e) {
@@ -276,8 +271,7 @@
       printf('%c', $e->getLine() + 23);
       }
       echo "\n";
-        }
-              
+ }

出力をおこなうcatch節を見てみると、Throwable::getPrevious()を呼び出してエラーチェインを辿り、Throwable::getLine()でエラーが発生した行数を取得している。その行数に23なるマジックナンバーを足し、フォーマット指定子%cで出力している。 @@ -287,9 +281,7 @@ フォーマット指定子%cは、整数を ASCII コードと見做して印字する。トークン#base64_decode('SGVsbG8sIFdvcmxkIQ==')bであれば、ASCII コード98なので、75 行目で発生したエラー、

-
-                      1, 20 => 0 / 0,
-              
+
      1, 20 => 0 / 0,

によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。 @@ -306,8 +298,7 @@ f()の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意):

-
-                function f(int $i) {
+              
function f(int $i) {
       if ($i < 0) f();
       try {
       match ($i) {
@@ -326,24 +317,19 @@
       } finally {
       f($i - 1);
       }
-        }
-              
+ }

前述のように、finally節でエラーを投げると PHP 処理系が$previousを設定する。ここでは、エラーを繋げるためにf()を再帰呼び出ししている。最初にf()を呼び出している箇所を確認すると、

-
-                <?php
+              
<?php
       try {
-        f(g() / __LINE__); // 3 行目
-              
+ f(g() / __LINE__); // 3 行目
-
-                function g() {
+              
function g() {
       return __LINE__; // 111 行目
-        }
-              
+ }

f()には111 / 337が渡されることがわかる。そこから 1 ずつ減らして再帰呼び出ししていき、0 より小さくなったらf()を引数なしで呼び出す。引数の数が足りないと呼び出しに失敗するので、再帰はここで止まる。 -- cgit v1.2.3-70-g09d2