2017-05-11

constexpr ifの落とし穴

会社の同僚から、以下のようなコードが動かない、ネット上をググると解決策らしきものが見つかるがそれもいまいち納得できない、という相談を受けた。

template < typename T >
void f()
{
    if constexpr ( std::is_same<T, int>{} )
    {
        // Tがintのときのみ発動してほしい
        // 実際は常に発動する
        static_assert( false ) ;
    }
}

C++17にはconstexpr ifが追加された。これは条件付きコンパイルではない。条件付き実体化抑制だ。

constexpr ifは以下のように使う。

struct S
{
    int value() { return 42 ; }
} ;

template < typename T >
int to_int(T t)
{
    int value{} ;
    if constexpr ( std::is_same<T, S >{} )
    {
        value = t.value() ;
    }
    else if constexpr ( std::is_integral<T>{} )
    {
        value = static_cast<int>(t) ;
    }

    return value ;
}

int main()
{
    f(42) ;
    S s ;
    f( s ) ;
}

to_intは引数からint型の値を取り出すための関数だ。クラスSの場合、int型を取り出すためにメンバー関数valueを呼び出す特別な処理をする。

これをみると、constexpr ifは条件付きコンパイルのように思える。つまり、if文によって選択されるブランチのみをコンパイルする機能だ。しかし、それは間違いだ。

constexpr ifは選択されないブランチのテンプレートの実体化を抑制する機能だ。

テンプレートは、まず宣言を解釈され、その後、具体的なテンプレート実引数を与えられて実体化する。

template < typename T >
void f( T t )
{
    t.func() ;
} 

int main() { }

この例では、Tにint型を渡すとエラーとなる。なぜならばint型はメンバー関数funcを持っていないからだ。

しかし、この例はコンパイルエラーにならない。なぜならば、テンプレートfのテンプレート実引数にint型は渡されていないからだ。

テンプレートは、具体的な型をテンプレート実引数として渡され実体化して、初めてコードが正しいかどうか検証される。

というのは間違いで、テンプレートは宣言の時点でもコードが正しいかどうかを検証される。

template < typename T >
void f(T t)
{
    // エラー、名前gは宣言されていない
    g( 0 ) ;
}

template < typename T > void g( T ) { }


int main() { }

この例はエラーになる。なぜならば名前gは事前に宣言されていないからだ。C++は名前を使う際には、事前に明示的な宣言を求める言語だ。

しかし、以下のような例はエラーにならない。


template < typename T >
void f()
{
    // エラーではない
    T::g() ;
}

これはなぜかと言うと、名前T::gはテンプレート仮引数Tに依存しているからだ。テンプレート仮引数Tに依存している名前は、Tの具体的な型が与えられるまで、コードの合法性が検証できない。そのため、そのようなコードの検証はテンプレートの実体化まで遅延される。

まとめると、テンプレート仮引数に依存しないコードはテンプレートの宣言時に検証され、依存するコードはテンプレートの実体化時に検証されるということだ。

これを踏まえて、以下のコードが動かない理由を考えてみよう。


template < typename T >
void f(T t)
{
    if constexpr ( false )
    {
        // エラー、名前gは宣言されていない
        g() ; 
    }
}

名前gはテンプレート仮引数に依存していないため、テンプレートの宣言時に検証される。その結果、エラーとなる。

ここまでくれば、冒頭のコードが意図通りに動かない理由もわかるはずだ。

template < typename T >
void f()
{
    if constexpr ( std::is_same<T, int>{} )
    {
        // Tがintのときのみ発動してほしい
        // 実際は常に発動する
        static_assert( false ) ;
    }
}

static_assert(false)はテンプレート仮引数Tに依存していないため、テンプレートの宣言時に検証され、エラーとなる。

ではどうすればいいのか。たんにstatic_assertの中にconstexpr ifと同じ式をいれてやればよい。

template < typename T >
void f()
{
    static_assert( std::is_same<T, int>{} ) ;

    if constexpr ( std::is_same<T, int>{} )
    {
        // ...
    }
}

しかしこれは同じ式が重複してよろしくない。式を変えたいときは二箇所を同時に変更しなければならない。

式の重複を防ぐには、変数を使ってやればよい。

constexpr bool cond = expr ;
static_assert( cond ) ;
if constexpr ( cond ) { }

しかし、if文というのはネストさせたいものだ。

if constexpr ( E1 )
    if constexpr ( E2 )
        if constexpr ( E3 )
        { }
        else if constexpr ( E4 )
        {
            // static_assertしたい。
        }

このような複雑なネストしたif文に相当する式を書くのは面倒なので、constexpr ifの中に入れて、そのブランチが実体化されるときのみstatic_assertが働くようにしたい。

そのためにはどうすればいいかというと、static_assertのオペランドの式を依存式にすればよい。そうすればテンプレートの実体化まで評価を遅延させることができる。constexpr ifに囲まれていてテンプレートが実体化しないのであればstatic_assert(false)も発動しない。

using < typename ... >
constexpr bool false_v = false ;

template < typename T >
void f( T t )
{
    if constexpr ( std::is_same<T, int>{} )
    {
        static_assert( false_v<T> ) ;
    }
}

false_vというのは任意の型を取って常にfalseを返すテンプレートconstexpr変数だ。このテンプレートにテンプレート引数を与えてやれば依存させることができる。結果として、この関数fはTがint型のときのみstatic_assertを発動させる。

現在書いているC++17の参考書には、このような落とし穴も含めたC++17の新機能の解説を書いている。なるべく早く書き上げたい。そして、最近、C++の規格を学びすぎたために、こういうC++の初心者が陥りがちな落とし穴が何なのか自分ではわからなくなってしまっている。C++の落とし穴を教えてほしい。

2017-05-10

Rustのパッケージマネージャーでパッケージ名nulを作ったら全Windowsユーザーのパッケージマネージャーが壊れた話

How I Broke Rust's Package Manager for All Windows Users - sasheldon.com

非Windowsユーザーが何気なくRustでnulという名前のパッケージを作って公開した。すると、全Windowsユーザーのパッケージマネージャーが壊れた。

理由は、nulという名前はWindowsでは予約語だからだ。Win32サブシステム経由で、どのディレクトリであれ、nulというファイル名を使おうとすると、それはGNU/Linuxでいう/dev/nullと同じような扱いになる。nulに拡張子がついていても同じだ。

RustはWindowsサポートも重視しているので、これに対処してWindowsの予約語を禁止する変更がなされた。

Reserve windows crate names. by withoutboats · Pull Request #695 · rust-lang/crates.io

これはWindowsがクソだが、他のOSでもファイルシステムには様々な技術的な柵がある。例えばMac OSのファイルシステムはUnicode正規化が特殊でクソだし、POSIXの多くのコマンドは-をSTDINやSTDOUTとして特別扱いする。また、bashは/dev/tcp/host/portというファイル名でhost:portに対するTCP接続を行う。

マイクロソフトのWindowsに付属しているアンチマルウェアソフトウェアが最高にクソな件

マイクロソフトのWindowsに付属しているマイクロソフトが提供しているアンチマルウェアソフトウェアに脆弱性が発覚した。

1252 - MsMpEng: Remotely Exploitable Type Confusion in Windows 8, 8.1, 10, Windows Server, SCEP, Microsoft Security Essentials, and more. - project-zero - Monorail

脆弱性の発覚はよくあることだ。脆弱性というのは、大抵はバッファーのサイズチェック漏れなどの些細な間違いが原因となる。

今回のMSのアンチマルウェアの脆弱性も、根本的な原因としてはそのようなチェック漏れなのだが、起こるべくして起こったクソすぎる実装のせいで、そのような些細な間違いが実用的な脆弱性に発展してしまっている。そのようなチェック漏れが存在するだけでは実用的な脆弱性に発展しない。そのチェック漏れを悪用できるようなコード実行ができる状況が存在することで、実用的な脆弱性に発展する。

MSのアンチマルウェアソフトウェアには、NScriptというJavaScript風のインタープリターが入っている。これによってあるJavaScriptコードが既知の悪意あるソフトウェアのパターンに一致するかどうかを調べている。JavaScriptはいくらでも同等内容になるように変形可能なので、実際に実行しなければパターンに一致するかどうかわからない。したがってこのように実際に実行して挙動がパターンに一致するかどうか調べる仕組みが必要になる。

問題は、このインタープリターは極めて強い権限で実行され、サンドボックス化もされていない。これはセキュリティソフトウェアとして問題外の実装だ。任意の悪意ある可能性があるコードの挙動を実際に実行して調べるのに、不必要な権限の放棄や適切なサンドボックス化を行っていないのはありえない。

かつ、MSのアンチマルウェアソフトウェアはファイルシステムの変更を監視していて、ファイルシステムのどこに書き込まれようと、JavaScriptっぽいコードは全部、このNScriptインタープリターで実行して、パターン検出を行おうとする。これは任意のブラウザーなどのソフトウェアのキャッシュなどにも対応できるための実装だ。しかし、これによって、ファイルシステムにさえかきこめれば、どのような方法であっても脆弱性をつくコード実行が可能になる。

結果として、マイクロソフトのアンチマルウェアの脆弱性を悪用するには、悪意あるJavaScriptコードをメールで送る、Webブラウザーで閲覧させるなどの何らかの方法で、ファイルシステム上に書き出させればよい。ユーザーがメールを実際に閲覧するとかソフトウェアを実行するといった操作は必要がない。

あるJavaScriptコードが悪意あるものであるかどうかを実際に実行して調べるセキュリティ対策のソフトウェアが存在するせいで強い権限による任意のコード実行につながるというのは、極めて皮肉だ。

私が平生から主張しているように、アンチマルウェアソフトウェアというのは詐欺だ。使ってはならない。アンチマルウェアソフトウェアはセキュリティではない。世の中のすべてのアンチマルウェアソフトウェアは実装がクソだ。アンチマルウェアソフトウェアを使った人間

「追加のソフトウェアは追加のリスク」という古き良きシステム管理者の格言はなぜ失われてしまったのか。

超会議2017でマストドンブースの運営スタッフをした

私は江添亮、ドワンゴ社員だ。超会議2017で運営スタッフをした。このブログ記事は個人的なものだ。株式会社ドワンゴの見解ではない。こう書かなければならないのは悲しいことだ。結局、国語教育で存在しない作者の意図を答えさられた人が多いようだ。ちなみに、この文章はマストドンとfactorioがやりたくて仕方がない合間を縫って後ろ髪を引かれながら書いた。もし将来、この文章を使って「作者の意図を答えよ」という問題が出題されたときには、「作者はマストドンとfactorioの中毒者であるが我慢しながらこれを書いた」と答えるのが正解だ。

超会議2017リハーサル

概要 | ニコニコ超会議2017 公式サイト

超会議2017での私の割当は、神エクセル方眼紙で公開された。自由な表計算ソフトウェアであるLibre Officeでみてみると、私はゲームエリアにアサインされていた。

やった。事前に提出した希望通りだ。ああ、入社して苦節3年、ようやく希望通りのアサインが行われた。ハッカソンやら馬車やら焼きそばやらと、私は常に変わった場所に割り当てられていた。それがようやく、ゲームエリアのアナログゲームブースでボードゲームのインストをするスタッフになったのだ。今度の超会議では好きなボドゲのインストができる。

そして、ドワンゴがマストドンのインスタンス、friends.nicoが公開された。そして全てが変わってしまった。

マストドンは面白い。なるほど、マストドンは技術的にはクソだ。しかし面白い。しかも自由だ。マストドンには未来がある。Twitterの時代は終わった。これからはマストドンが圧倒的に流行する。既存の不自由なSNSは滅びる。

そして、超会議開催の直前の土日に、マストドンブースの設営が決定された。これは行くしかない。強引に根回しをしてブースのリアサインをする。ああ、せっかく希望通りのボードゲームのインストスタッフになれたのに。いやしかしこれもマストドンのためだ。

超会議前日、リハーサルのために幕張メッセに行き、マストドンブースを確認する。いかにも急造したらしきブースがぽつねんとある。大きめのディスプレイがあり、friends.nicoのLTLをニコニコ動画風の右から左に流れるコメント形式で流している。

私は引き戸になっているブースの下を改めた。ここがマストドンブースであるならば、当然あるはずだ。人権が、インターネット回線が。あるはずだ。果たしてEthernetポートはあった。ある。人権がある。当日はライブマストドンができるぞ。

マストドンブースの確認と、ユーザー記者の控室などにマストドン体験端末の設置などの雑用をする。あとは超会議のリハーサルの体験だ。

超人スポーツのジャンピング竹馬が面白かった。アマゾンで中国製が2万で売られているので、即座に購入した。届くのが楽しみだ。ただし、これはだいぶ危険なので、プロテクターとヘルメットを用意した上で、受け身の練習もしなければならないと思っている。

そして、マストドン会議に参加した。

本の虫: マストドン会議で技術と自由を語る

マストドン会議ではマストドンの実装とプロトコルの設計がいかにクソか、そして自由の素晴らしさを語った。

マストドンは自由だ。自由は素晴らしい。

TwitterはTwitter社が独占している。そのため、Twitterがお前のアカウントをBANすると言ったならば、お前のアカウントはBANされる。お前の相撲取り画像は肌色成分が多いのでエロ画像だと言われたならば、それはエロ画像だ。Twitterに逆らうことはできない。

マストドンでは誰もがインスタンス(サーバー)を立てられる。あるマストドンの運営が「お前の相撲取り画像は・・・」などと馬鹿なこと言い出したら、そんなインスタンスは使わなければよい。どのインスタンスも機に食わなければ、自分でインスタンスを立てればよい。自由を保証するには拒否できる力が必要だ。

これは政治家や政党にとっても都合がいいだろう。ご存知の通り、アメリカ大統領選挙ではTwitterやFacebookが恣意的な検閲を行い、トランプとヒラリーのどちらかに有利な検閲を行った。マストドンではこういう恐れがなくなる。政党や候補者自らインスタンスを立てればよいのだから。

近々マストドン会議2が行われるらしく、ドワンゴからも2人ほど発表するそうだ。なんとか次も発表枠で潜り込めないか交渉している。

超会議

超会議では、私はひたすらマストドンブースに張り付いてマストドンの宣伝を行った。

マストドンブースは超演奏してみたブースの向かい側で、始終うるさかった。なかでも特に多くかかった音楽は、けものフレンズの主題歌と、逃げるは恥だが役に立つの主題歌だった。

超会議では様々な人間がマストドンブースを訪れた。特に印象深かった人間が何人かいる。

マストドンブースにほぼ張り付いていた人間がいた。マストドンの中毒性を考えればコレは当然のことだ。

マストドンをしていて、しかもプログラミングのできる中学生や高校生がやってきた。私は自由なコンピューターの必要性を説いた。プログラミングをするには自由なコンピューターが最も便利だ。不自由なコンピューターではろくなコードが書けない。第一、不自由なOSはその動作を確認できないし、改造もできない。

ある中学生は、プログラミングに興味があるが、いまは不自由なコンピューターであるスマフォしか持っていないといった。私はぜひとも自由なコンピューターを買い、その上の自由なOSをインスールして、プログラミングを本格的に学べと教えた。その子はママに相談すると言って帰っていった。

お母さん、息子の将来のためにはプログラミングができるべきだ。そのためには自由なコンピューターを使うべきだ。

ある高校生はRaspberry PiにDebianを入れて使っているという。ああ、私が高校生の頃にRaspberry Piがあればなんと良かったことだろうか。今の子どもたちは恵まれすぎている。そんな恵まれた環境で育った子どもたちが社会に出る頃には、我々のような老人プログラマーは皆、戦力外通告を受けることだろう。未来は明るい。

マストドンブースに来た政治家達

重ねて書くが、これは私の個人的なブログであって私が雇用されている会社の見解ではないし、書かれている以上の「作者の心情」とか「作者の意図」を見出してはならない。

さて、超会議ではマストドンブースに二人の政治家が来た。政治家であるという理由だけでわざわざ書くというのは、これから私が主張する内容と矛盾する。しかし彼らは政治家であるために例外的な対応を求めたので、例外的に書いてもいいだろう。

東京都知事の小池百合子

急に、マストドンブースにスーツが近寄ってきて、「都知事の小池百合子がまもなくやってくる」と私に告げた。私は事前に連絡を受けていない。上司に連絡を取ると、「把握している。小池百合子のスケジュールは警備上の理由で秘密である」と告げられた。

やがて、怒涛のように小池百合子とその取り巻き御一行様がやってきた。まるで北朝鮮の総書記の視察を受けているかのようだ。小池百合子の周りをスーツが厳しく取り囲んでいる。その中心に光るように目立つ小池百合子。一触即発のアトモスフィア。スーツのうちの何人かは物理的なペンと物理的な紙のメモ帳を手にして激しく首を縦に振りながら何やら一心不乱に書き込んでいる。上司が小池百合子にマストドンの説明をする。そして、小池百合子が去っていった。まるで嵐がやんで晴れ渡ったかのような安堵感が広がる。

これは文化に対する理解と尊敬がない。超会議は誰であれ身一つでそのへんをフラフラと歩いて楽しむべきだ。実際、有名人が何人もそれと気づかれずにフラフラと周りを歩いているのを私は何度も目撃している。小池百合子の査察を受けている間、そのホールは厳しい警戒態勢になり、乗合馬車なども待機を余儀なくされた。都知事ともなると身辺警護が厳しいのはわかる。それはわかる。しかし、文化への尊重も必要だ。

民進党の枝野幸男

超会議2日目の開始直後、急に、マストドンブースにスーツが2,3人ほど近寄ってきて、「これから・・・のユキオが来る」と私に告げた。はて、一体何のユキオだろう。周りが騒がしくて聞き取れない。重ねて聞くが、やはり「・・・のユキオ」としか聞き取れない。名前よりもその役職のほうが重要だ。私はその名前を知らない可能性のほうが高いのだから。

スーツが去ろうとするので慌てて呼び止めて再度聞くと、今度は、「エダのユキオです。政治家の」と答えた。エダのユキオ・・・、なるほど、助詞の「の」ではなく、民進党の枝野幸男(えだのゆきお)か。

もし枝野幸男本人が何も根回しをせず無名の一般人としてやってきたのならば、私も通常通りマストドンの説明と、マストドンのソフトウェア実装が自由であることの価値を説いただろう。しかし、そのような特別対応を求めるのであれば、やはり私としても上司に連絡をする。

上司からの返事がないまま、スーツが再びやってきた。「今から15分後に枝野幸男が来る」ということを私に告げた。

スーツ曰く、「枝野幸男はマストドンにアカウントを作ることを所望している。いまブースに設置してるコンピューターで枝野幸男のマストドンのアカウントを作ることは可能か?」

可能か? 技術的にはイエス。セキュリティ的にはノー。もちろん答えはノーだ。

自分のアカウント登録は自分の所有するコンピューターで行うべきだ。なにしろ、メールアドレスへのアクセスが必要なのだから。

程なくして枝野幸男本人がマストドンブースにやってきた。物々しい目立つ護衛や取り巻きはいない。上司も間に合う。上司が枝野幸男にマストドンの説明をする。

枝野幸男は文化を理解していた。枝野幸男のマストドンのアカウントの名前は本名ではない。かつ、本業には言及しない。それでいい。自分の管理していないインスタンス経由でマストドンに参加するのであれば、無名の一般人として参加すべきだ。そしてどうでもいいバカなことをつぶやくべきだ。そして、他人も本人の意志を尊重し、わざわざ本業についての質問をぶつけるような無粋なことをするべきではない。民進党の政治家、枝野幸男として意識の高い発言をするのであれば、自分でサーバーを建てるべきだ。なぜならば、自分の管理するサーバーは一番信頼できるからだ。

このブログを書いている今も、枝野幸男はわかる人にだけわかる本名ではない名前で、政治家としてではなく一個人として、マストドンで雑談をしている。このまま続けたいだけ続けて、やめたいときにやめるべきだ。

マストドンの保証する自由は、政党や政治家にも利点がある。なぜならば、自らサーバーを立てて情報を発信することで、マスメディアによる脚色のない一次情報を自ら発信できるからだ。

マストドンでは誰でもインスタンス(サーバー)を建てることができる。どのインスタンスを経由してマストドンに参加しているかを意識する必要はない。TwitterやFacebookのように、サーバーを独占され、唯々諾々と決定に従うしかない不平等で不自由な時代は終わった。これからはマストドンの時代だ。

2017-05-05

5月7日に江添ボドゲ会をやるかも

江添ボドゲ会5月7日 - connpass

5月7日に木場にある江添の自宅でボドゲ会を開くかもしれない。connpassで4人集まれば開く。詳細は上記connpassリンクを参照のこと。