Ihoronir
Web

セキュリティ・キャンプ全国大会2023に参加しました

この記事の公開日:
この記事の最終編集日:

まえがき

セキュリティ・キャンプは 独立行政法人情報処理推進機構 (IPA)一般社団法人セキュリティ・キャンプ協議会 が毎年夏に開催している学生向けのイベントです。 参加者は 4 泊 5 日の間、 クロス・ウェーブ府中 という施設で朝から晩までサイバーセキュリティに関する講義や開発に取り組みます。 受講料・交通費・宿泊費・食費が全て無料であるにも関わらず、 一流の講師・チューターの方々から多くのことを学べるすごいイベントです。

この度、 8/7 から 8/11 にかけて開催されたセキュリティ・キャンプ全国大会 2023 に、 L3 (C コンパイラゼミ)の受講生として参加させていただきました。 この記事ではキャンプで体験したことや考えたことを記述しようと思います。

自己紹介

セキュリティ・キャンプの Discord に書いた自己紹介文を転載します。

はじめまして! L3 ( C コンパイラゼミ)受講生の〇〇(本名)です!
現在は大学の 3 回生で、情報工学の基礎をいろいろ勉強してます。
大規模なソフトウェアを作った経験がないので、これから C コンパイラという複雑で大規模なものを作り上げるのがとても楽しみです。
プログラミング以外では、登山や自転車旅など、冒険っぽいことをするのが趣味です。
コンピュータの世界でも、 0 と 1 の論理から GUI まで、幅広く冒険し尽くすのが目標です。
とはいえ、今一番興味があるのは低レイヤなので、まずは低レイヤから詳しくなっていこうと思います!
よろしくお願いします!!

↑ なかなかうまく書けてるなぁ (自分で言うな)

参加決定まで

セキュリティ・キャンプでは様々なクラス・ゼミが用意されていて、 参加希望者はどのクラス・ゼミに参加したいかを決めて応募する必要があります。 いろいろと面白そうなクラス・ゼミがあったので、 どれに応募しようか迷ったのですが、 「C コンパイラゼミ」が特に面白そうだったので、 このゼミに応募することにしました。

ところで、 セキュリティ・キャンプに参加するためには応募課題を提出する必要があり、 この応募課題の出来によって参加できるかどうかが決まります。 応募課題は何ヶ月も前から公開されていたのですが、 僕がセキュリティ・キャンプの存在を認識したのは応募課題の締め切りの 1 週間前だったので、 その時点でだいぶ出遅れた感がありました。

「今から応募課題を始めても無理かもなぁ」と思ってクネクネしていたところ、 C コンパイラゼミの講師である hsjoihs さんから「ご興味ありましたら是非!!」とリプライを頂いたので、 期限までにできるだけのことをやって応募課題を提出することにしました。

数週間後、 選考通過者の発表があり、 C コンパイラゼミを受講できることが決定しました。 もう嬉しすぎてウッキウキでした。

応募課題でどのようなことを書いたかは、 後日別の記事でまとめようと思います。

C コンパイラゼミとは

その名の通り、 C コンパイラの蝉です。1

このゼミでは C 言語のソースコードを対応するアセンブリ言語のコードへと変換するプログラム、 すなわち「C コンパイラ」を自作します。 IPA のページ に講師の方々が書いた講義概要が載っているのですが、 ここで C コンパイラゼミの講義概要を読めば、 どんなゼミかが一発で分かると思います。 とてもうまくまとまっている文章なので、 ぜひ読んでみてください。

受講生は次の 2 つの資料を手がかりに、 C コンパイラを自作していくことになります。

「低レイヤを知りたい人のためのCコンパイラ作成入門」は C コンパイラの作り方がステップごとにまとめられたウェブページです。 このページの内容に沿って 1 ステップずつソースコードを書いていけば、 C コンパイラをインクリメンタルに開発することができます。 C コンパイラ開発に必要な知識が読みやすい文章でまとまっていて、 とても参考になりました。

「C 言語 ポインタ完全制覇」はなんとセキュリティ・キャンプの費用で買っていただき、 無料で家まで送られてきました。 この本を読んだことで、 自分がいかに C 言語のことを何も分かっていなかったかが分かりました。 また、 文章が演説みたいな感じになっていて頭に入りやすかったです。 オススメです。

事前学習

事前学習では、 「低レイヤを知りたい人のためのCコンパイラ作成入門」を参考に、 自分の C コンパイラを作り進めるということを行いました。 また、 週に 1 回 Discord で講師の方に直接質問したり、 画面共有しながらいろいろ教えてもらえる機会を設けていただきました。

この事前学習ですが、 キャンプ本番までにセルフコンパイルの手前ぐらいまでいけたらいいな〜と思っていたものの、 結局ぜんぜん作業が進まず、 ポインタ型の導入あたりまでしか進めることができませんでした。 特に、 事前学習期間の後半はほとんど進捗が生まれていなかったので、 毎週進捗を報告するときに軽く自己嫌悪に陥っていたのですが、 講師の方々から「次はこうすれば良いのでは」というようなアドバイスをもらったり、 画面共有でプログラムを見てもらいながら作業を進めたりできたので、 とても助かりました。

キャンプ本番

1 日目

1 日目は開講式や共通講義、 LT 発表会、 グループワークなどが中心でした。 LT 発表会ではいろいろな人のいろいろな発表を聞くことができたので面白かったです。

夜はゼミの時間があり、 ここで初めて C コンパイラゼミの人々

と集まりました。 2 ヶ月もの間インターネット上だけでやりとりしていた人が目の前に居るという感覚が新鮮でした。

hsjoihs さんが家から大量の本を持ってきていて、 その量に圧倒されました。

この日はゼミの時間が短かったのもあって、 C コンパイラの進捗はあまり生まれませんでした。

2 日目

2 日目はゼミの時間がたっぷりあったので、 進捗を生むことができました。

この時点で「AST の各ノードに型の情報を持たせる」という部分で詰まっていたのですが、 hsjoihs さんのアドバイスに従い、 型検査後の AST を StmtTypedExpr の 2 種類の構造体を用いて表現するという方針で実装を進めていきました。 この辺の実装は作業量が多かったので大変でしたが、 なんとかポインタ演算や sizeof 演算子を含む C のプログラムをコンパイルできるようになりました。

他には、 hsjoihs さんから提供してもらった大量のテストケースを「いま通っているもの」と「これから通るようにするもの」に分けて別々にテストできるようにしたり、 テストが通らない場合はコミットできないように git の precommit を設定したりしました。

夜は協賛企業の説明会があり、 いろいろな企業の説明を聞きました。 どの企業も自社のサービスのセキュリティを万全にするために様々な施策を行っているということが分かりました。 現代社会においてサイバーセキュリテイがいかに重要視されているかを認識することができました。

3 日目

3 日目の午前中はバスに乗って社会見学に行きました。 いろいろと面白いものを見ることができ、 楽しかったです。

午後からはゼミの時間で、 この日は主に配列に関する機能を実装しました。 これ以前では、 あらゆるロード・ストアを 64 bit のレジスタで行っていたのですが、 int 型の配列のように 32 bit の値が連続的にメモリに配置されているような状況などを考えると、 ロード・ストア時に値の型に応じて適切なサイズのレジスタを指定する必要があり、 そのあたりが引っかかったポイントでした。 また、 sizeof 演算子および & 演算子のオペランド以外の場所に配列が現れた場合にポインタとして解釈するという部分でも引っかかったのですが、 講師・チューターの方々に教えてもらいながら実装を進めることができました。

4 日目

4 日目はグローバル変数と文字列リテラルを実装しました。

このあたりは godbolt.org で実際の C コンパイラの出力を見ながら実装していった感じでした。 グローバル変数のアドレスを計算するときに実際の C コンパイラの出力と同じ方法ではうまくいかなかった(アセンブラに渡すオプションの関係?)のですが、 lea 命令を使った方法を教えてもらい、 その方法で実装することができました。

他には、 行コメントやブロックコメント、 ローカル変数の初期化式、 += 演算子などを実装しました。 また、 git add -p コマンドで特定の diff だけを staging できるということを教えてもらい、 目からウロコでした。

この日は 2 回目の LT 発表会があり、 僕も「スマホで Misskey サーバを立てよう!」というテーマで発表をしました。 LT 発表は初めてだったというのもあって(言い訳)、 あまりうまく発表できませんでしたが、 良い経験にはなったと思います。 発表資料は ここ から見られます。 他の人の発表もいろいろ聞けたので楽しかったです。

4 日目の夜はグループワークがあり、 翌日の発表資料をまとめる必要があったのですが、 それが時間内に終わりませんでした。 しかし、 心優しい人々が夜中に発表資料を仕上げてくれたので、 ありがたいことに事なきを得ました。

一方で僕は夜中に何をしていたのかと言うと、 自作 C コンパイラで円周率を計算するプログラムをコンパイルしていました。 ネットから拾ってきたソースコードを少しいじったら無事に円周率が計算できたので、 やった〜〜と部屋で叫んだら窓ガラスが割れました。2 そのせいでエアコンが効かず暑かったです。

5 日目

5 日目はグループワークの発表と、 各クラス・ゼミの成果発表がありました。 どの発表もとても興味深かったです。 全体的に、 みんな発表がうまいな〜ということと、 みんなハイレベルなことをしてるな〜ということを思いました。 どの発表でも話者が対象のことを深く理解しているということが感じられ、 聴き応えがありました。 人々の多様な発表の数々を聞いて、 自分の興味の対象も広がりました。

成果発表の後は閉講式があり、 そこで「家に帰るまでがセキュリティ・キャンプ」というありがたいお言葉を頂戴したので、 僕のセキュリティ・キャンプはあと 2 日続くことが決定しました。

閉講式の後は、 東京駅まで行って C コンパイラゼミの人々と食事をしました。 牛タンがおいしかったです。

その後は徒歩で下北沢まで向かいつつ、 皇居・国会議事堂・東大駒場キャンパスなどを見物しました。

この日は宿泊先のネカフェで後置 ++ 演算子を実装しました。

6 日目

7 日目

感想

美しい設計とかではなく、 豊富なテストこそが正義

今まで「テストを書く」ということをあまりしてこなかったのですが、 今回の C コンパイラゼミの受講を通して、 テストの偉大さを実感しました。 そして、 「美しい設計」よりも「豊富なテスト」の方が、 より確実にプログラムの品質を担保してくれるのではないかという考えに至りました。

プログラムの品質を高める為にこれまで自分が常に意識していたのは、 プログラムをいかにうまく疎結合な複数のまとまりに分割し、 そのまとまりの間のインタフェースをいかに完璧に仕上げるかというということでした。 しかし、 この考え方ではどのようにプログラムを分割するのが「美しい」かや、 まとまりの間のインタフェースはどのようにするのが最適かといったことに気をとられ、 開発が遅々として進まないという問題がありました。

また、 このような考え方はトップダウンな開発とは相性が良いものの、 今回の C コンパイラ開発のようなインクリメンタルな開発においては、 何かを実装する度にプログラムの構造に変更が生じ、 コードを書き換えるための作業量が増大するという欠点を抱えていました。 最初から完璧な設計が見通せていればこのようなことはないのですが、 完璧な設計というものはこれから作るプログラムの全てを熟知した上でないと見出すことができないものです。 したがって、 コンパイラを初めて作るという人間がいきなりコンパイラの完璧な設計を見出すことは不可能です。 にも関わらず、 事前学習期間の僕は完璧な設計を追い求めてしまっていました。 これが、 事前学習期間の後半で僕がほとんど進捗を生み出せなくなっていた原因の一つなのではないかと考えます。

キャンプ期間中は「どのように実装するのがお行儀が良いか」といったことで悩む時間が惜しかったので、 コードの綺麗さなどは全く考えずに場当たり的にコードを書き換えたり書き足したりして、 コンパイラの機能を拡張していきました。 これにより、 普段の僕の感覚からするとかなり混迷を極めたソースコードが錬成され、 正直なところ現在の自分のコンパイラの全容は自分でも掴みきれていない感じになってしまっているのですが、 hsjoihs さんに提供してもらった大量のテストケース(の一部)が正しく通せているので、 僕のコンパイラは「なんか知らんけど正しく動作しているっぽいなぁ」という感じになっています。 しかしながら、 きれいな実装に対するこだわりを捨てたことで、 キャンプ期間中はかつてなく進捗を出すことができました。

これはけっこう画期的なことな気がしていて、 大量のテストケースを用意すれば「なんか複雑で全容が掴めないもの」が正しく動作しているかを検証できるというわけで、 とにかくテストケースの量こそが正義であり、 それさえクリアできていれば、 少ない作業量で場当たり的に拡張が繰り返された「お行儀の悪いコード」であっても、 プログラムの品質をある程度保証でき、 進捗もバンバン生まれるということが分かります。

以上の事柄を雑にまとめると、 僕のような初心者が C コンパイラをインクリメンタルに少ない作業量で自作しようとする場合、 次のステップを繰り返ば良いのではないかと思いました。

  1. これから実装する機能のテストケースを追加する。 多ければ多いほど良い
  2. 設計の美しさとかは一切考えなくて良いので、 場当たり的にコードを書き足す・書き換える (初心者が「良い設計」を思いつくことなどできないため)
  3. テストが通るようになったことを確認する

このようなステップを繰り返してある程度機能が固まってきたところで初めて、 「良い設計」が見えてくるのではないかと予想しています。 (僕はまだその段階に到達していないのでなんとも言えませんが...) そして、 「良い設計」が見えてきた時点で初めて大規模なリファクタリングを行うようにすれば、 初心者でも少ない作業量で良い感じの C コンパイラをインクリメンタルに開発することができるのではないかと思いました。

というか、 コンパイラ開発は 2 週目以降で初めて「最高の実装」に到達できるものであって、 1 週目の実装は泥臭くやるしかないのかもな〜と思いました。 これはコンパイラに限らずどのような大規模なソフトウェアの開発においても言えることかもしれません。

以上は全部個人(初心者)の感想です。 なお、 マサカリは大歓迎です。

後悔した点

当初は、 事前学習期間にガッツリ実装を進めて、 キャンプ期間中はより高度なこと(セルフコンパイルなど)に取り組もうと思っていました。 しかしそれが叶わなかったので、 講師・チューターの方々には退屈な思いをさせてしまったような気もしています。 貴重な機会を完全には活かしきれなかった感じがあり、 この点では後悔が残りました。

周りのレベルが高い

セキュリティ・キャンプは、 講師・チューターの方々のレベルが高いのはもちろん、 受講生もレベルが高い人が集まっていてすごかったです。 僕は暇さえあればダラダラしてしまうのですが、 キャンプで出会った人々はキャンプ期間中はもちろんキャンプ期間外でも常に手を動かし続けていて、 次元が違うなと思いました。 今回のキャンプでそのような人々から大いに刺激を受けたので、 今後はなるべく時間を無駄にせずに手を動かしていきたいと思います。 特に今、 自分の C コンパイラでやりたい作業がたくさんあるので、 時間がある夏休み中の間にそれらを進めていこうと思います。

名刺交換バトルは命がけ

セキュリティ・キャンプでは、 会場内を歩いているときに誰かと目が合うと、 その瞬間に名刺交換バトルが始まります。 このバトルに負けると会場から追い出されるという仕組みになっているので、3 毎回とても緊張しました。 なんとか最終日まで生き残ることができたので、 良かったです。

ご飯がおいしい

キャンプの食事は毎回とても豪華で、 おいしかったです。 これを目当てに毎年参加している人もいるのでは!?と思いました。

首都圏は栄えている

下記のような理由から、 地元の京阪神エリアと比べて栄えていると思いました。

しかし僕はアンチ東京一極集中なので、 少し複雑な気分になりました。 それはそれとして首都圏の街は栄えていて、 探検するのが楽しかったです。 今後も機会があれば首都圏のいろいろな街を探検したいと思いました。

あとがき

今回のセキュリティ・キャンプを通して体験したことや考えたことで、 ここに書ききれなかったことは山のようにあるのですが、 言葉にして文章にまとめるための気力を使い果たしてしまったので、 これぐらいしか書けませんでした。 とにかく、 いろいろなことを吸収できたので、 とても良かったです。

最後に C コンパイラゼミの hsjoihs さん、 n.takana さん、 uint256_t さん、 カッシーさんをはじめ、 セキュリティ・キャンプで出会った方々、 セキュリティ・キャンプの開催を支えてくださった方々にお礼を申し上げます。 本当にありがとうございました。 今回経験したことを活かして、 今後も頑張っていこうと思います。

おまけ

御徒町(?)でオラフを見ました (恐怖)

脚注

1

激ウマギャグです

2

嘘です

3

嘘です