dlang
ポエム
D言語Day 23

safe functionは未定義動作を許さないといったな、あれは嘘だ (タイトルは釣りです)

遅くなりましたすいません, これはD言語アドベントカレンダーの23日目の記事です.
この記事はほんとにチラシの裏であり得られるものなどなにひとつないのでポエムのつもりでごらんください.

D言語の言語仕様にはsafe functionというものがあります.

2018年12月27日時点の https://dlang.org/spec/function.html#function-safety の記述において, safe function の定義は

Safe functions are functions that are statically checked to exhibit no possibility of undefined behavior.
Undefined behavior is often used as a vector for malicious attacks.

となっています. ひらたくいうとsafe functionは未定義動作を踏まないことを保証してくれるそうです.

safe functionを定義するためには @safe という属性を関数に付与してやる必要があります.

以下のコードは @safe ではコンパイルできません.

void func() @safe
{
    const x = 1;
    auto y = &x; // cannot take address of local `x` in `@safe` function.
}

safe function 内で許可されない操作は https://dlang.org/spec/function.html#safe-functions に一覧があります.
上の例だと No taking the address of a local variable or function parameters に抵触しているためコンパイルエラーとなります.

さて, このリストをみると未初期化変数の扱いに関する記述がないことに気がつきます.
実際に @safe 内で未初期化変数を使うコードを書いてみると, コンパイル・実行ともに可能でランダムな値が取得できます.

int func() @safe
{
    int x = void;
    return x;
}

この挙動にすでにきづいた人がいて, チケットをすでにあげていました. https://issues.dlang.org/show_bug.cgi?id=18016
そしてどうやら議論の中で
「ポインタの未初期化変数は未定義動作として扱う(つまりsafe function内で記述することを許容しない)けど, 値の未初期化変数は implementation defined と定義して未定義動作から外すわ. 仕様もそういう感じに変更しとく」
などと, implementation defined なる概念になりました. (なので別にsafe functionは未定義動作を許容するようになったわけではないのです)

個人的にはこれを未定義動作ではないというのはちょっと無理があるかなとは思いますが, いろいろ考えてみても特に不便もないので別にいいかなという感想です.

まあこのコードがコンパイルエラーになるだけC言語よりはるかにマシでしょ, D言語使おう.

void func() @safe
{
    int* x = void;
}