起源 (Provenance) と呼ばれるポインタまわりの概念について。
「起源」の概念はポインタまわりの整数演算についての UB を検出可能にする。起源を利用した API を使用しておけば、Miri などの検証ツールとうまく連携できるようになる。なお、エラー検出以外の殆どの状況では、起源は無視されパフォーマンスに影響しない。
起源を使わない場合、ポインタは物理的にはアドレスを表現するただの整数である。同様に、ポインタを演算対象とする演算も物理的にはただの整数演算である。しかし、これだけが制限だとすると、どんな意味のない演算でも可能であり、その結果として生成されるポインタが UB を起こしうるかどうかも自動検出できない。
起源が有効な環境では、ポインタは参照先のアドレスに加えて起源を持つ。この起源は一緒に確保されて一緒に利用されるべきメモリの範囲である。この範囲を越えてポインタのアドレスを編集すると、Miri などの検出ツールは UB と判定する。
最初の起源は変数やヒープの確保によって生じる。そして、それらの変数やヒープを指すポインタや参照から新たなポインタや参照が派生されると、それらに元の起源の全部または一部を引き継いだ起源が紐づけられる。
上記は「厳密な起源」と呼ばれる仕組である。一方、「公開された起源」と呼ばれる仕組も存在する。なお、整数とポインタ間のキャストは公開された起源の別表現であり、実質それらは同じである。推奨されるのは厳密な起源で、公開された起源は仕様も不確かである。
公開された起源では、起源をグローバルなリストで管理しており、起源が必要になると以前に作られた起源からそれっぽい対象を選ぶ。Rust の外部やレガシーシステムとのやりとりではこれが必要になる状況が想定されている。
よく使うものを抜粋 (他は『API』セクションを参照)。
pointer::wrapping_offset
pointer::wrapping_add
pointer::wrapping_sub
pointer::addr
pointer::with_addr
pointer::map_addr
with_addr とアドレス計算の複合版
pointer::expose_provenance
with_exposed_provenance