週次オープンソース:ゲストカーネルのない Linux サンドボックスと、ゼロから書いたバーコードライブラリ
コミット数で見ると、今週も重い週だった。3,000 コミットを少し超えた。新しいプロジェクトが二つ始まった。 nixvm は Linux カーネルを起動せずに本物の Linux ユーザランドを 動かすサンドボックス、anydcode はゼロから書いたバーコード ライブラリだ。これまでの大きなエンジン三つも動き続けた。z3rs は一週間かけて本物の Z3 と自分を突き合わせ、graphitesql は 最初の 0.1 リリースをタグ付けし、kataan は Temporal API を 丸ごと実装した。
nixvm:Linux カーネルなしで Linux システムコールを
nixvm は「ハードウェア
ではなく Linux システムコールを直接エミュレートすることで、本物の
Linux ユーザランドを動かすポータブルな VM 風サンドボックス」だ。
gVisor 型のやり方を取り、ゲストカーネルが存在しない。素の
Alpine ユーザランドは、ホスト CPU 上かソフトウェアインタプリタ上で
動く。ゲストのプロセスが syscall や svc を実行すると、制御は
トラップして nixvm 自身の Rust 製カーネルに移る。ファイル、メモリ、
プロセス、スレッド、シグナル、ネットワークは、すべてこのカーネルが
ユーザ空間で扱う。狙いは npm install、pip install、信頼できない
ビルドスクリプトといった危うい作業を隔離して動かすことで、
ハードウェア仮想化はあってもなくてもよい。
リポジトリは金曜に作られ、日曜までに 188 コミットに達した。 おおよそ次の順で組み上がった:
- CPU インタプリタ。 aarch64 インタプリタは「hello world」
から始まり、本物の busybox が動くところまで ISA を広げた。NEON、
スカラ/ベクタの浮動小数点、LSE アトミック、CRC32、AES/SHA 命令。
続いて x86-64 インタプリタが、SSE/SSE2、x87 のサブセット、
CPUID/RDRAND、LOCKアトミックとともに加わった。 - ローダ。 静的 ELF、次に static-PIE、そして 動的リンク。
本物の
ld-muslが素の Alpine のバイナリを起動する。 - カーネル。 スケジューラ付きの fork/exec/wait4(これで
パイプラインが動く)、本物の futex を持つアドレス空間共有の
スレッド、vCPU ホストスレッドの SMP プール、
poll/epoll/eventfd/timerfd、シグナル、ファイルバックと
コピーオンライトのメモリ、そして仮想ネットワークスタック。
AF_UNIX、TCP/UDP ループバック、netlink のスタブ、最後に
ホストへの外向き通信 が入り、
apk update && apk addが本物の インターネット越しに動く。 - ファイルシステム。 tmpfs、コピーオンライトのオーバーレイ、
fstool による読み取り専用 squashfs のルート、合成した
/dev・/proc・/sys、ホストのディレクトリを通す「穴」。穴は、ゲストの シンボリックリンクがマウントルートの外へ出られないよう固めてある。 - ハードウェアバックエンド。 macOS の Hypervisor.framework
(EL0 で実行し、
svcでトラップ)と、x86-64 ゲスト向けの KVM。KVM ではフルの Alpine ユーザランドが起動する。 インタプリタは引き続きフォールバックとして残る。
インタプリタもカーネルもポータブルな Rust なので、全体は WebAssembly にもコンパイルできる。GitHub Pages 上の Vue + xterm の ページが、どちらのアーキテクチャでも Alpine をブラウザ内で起動する。 ルートファイルシステムはメモリ上の squashfs から読み込む。rootfs の tarball はプロセス内で compcol を使って展開しており、ここでもまた 同じ no-C スタックだ。Node.js は共有ライブラリのグラフ全体を 読み込むが、イベントループがまだ futex/epoll でビジースピンする ことがコミットに記録されている。
anydcode:50 以上のバーコード方式、往復で厳密
anydcode(クレート名
anyd)は「1D と 2D のバーコードを復号・符号化する、ゼロから
書いた Rust ライブラリ」だ。設計目標は ロスレスな往復。復号した
シンボルはペイロード と 符号化時のすべての決定(セグメント分割、
バージョン、EC レベル、マスク)を保持し、そのまま符号化し直すと
元のシンボルがバイト単位で再現される。検出は、軽いフレームごとの
パス(位置特定と分類)と重い復号パスに分かれていて、ライブ映像に
向く。
土曜に作られ、一気にカタログを進めて、週末には モデル化した すべての方式が実装済み になった:
- 2D マトリクス: QR、Micro QR、rMQR、Data Matrix、Aztec と Aztec Runes、MaxiCode、Han Xin、DotCode、Grid Matrix、そして Apple App Clip Code。
- スタック型: PDF417、MicroPDF417、Code 16K、Code 49、 Codablock F、GS1 DataBar のスタック型各種。
- リニアと郵便: Code 128 / GS1-128、アドオン付き EAN/UPC、 Code 39/93/11、ITF と 2-of-5、Codabar、MSI、Telepen、 Pharmacode、DataBar、POSTNET/PLANET/IMb、RM4SCC/KIX、 Australia Post、日本郵便、Mailmark、DX フィルムエッジ。
続いて実際の写真に取り組んだ。QR のサンプラには、適応的な
二値化、曲面向けの thin-plate-spline による歪み補正(曲がってぼけた
ボトルの写真がいまは回帰テスト用のフィクスチャになっている)、
タイミングパターンを基準にしたモジュール単位のサンプリングが
入った。EAN/UPC は、実際のカメラ画像向けにエッジ幅による復号へ
移った。wasm-bindgen を使わずに作った WASM デモは、51 方式すべてを
生成し、画像を復号し、Web Worker でターゲットを追跡しながら
ライブカメラからスキャンする。v0.1.1 として出荷された。
z3rs:Z3 と自分を突き合わせる
先週の Pure-Rust 版 Z3 移植である
z3rs は、今週最多の
426 コミットだった。その大半は本物との差を埋める作業だ。週の
始めに PARITY.md v2 と、Z3 自身の回帰テストコーパスに対する
差分ハーネス が入った。その後の作業のほとんどは、このハーネスと
差分ファジングが見つけたものへの対応だ:
- 文字列とシーケンス(QF_S) には約 100 コミット。単語方程式を
反駁する Nielsen 変換、
str.containsの正規表現による反駁、Z3 のseq_rewriterの replace 規則の移植、そしてprefixof・str.at・str.indexof・連結の分割を結びつける小さな公理が多数。 - 量化子: 整数の ∀x∃y に対する完全な Presburger 量化子消去 (Cooper)、線形実数の入れ子 QE、幅の狭いビットベクタの有限領域 展開。
- 算術、配列、データ型: QF_LIA の dark-shadow ウィットネス、
本物のモデルを伴う非線形整数ウィットネス、配列の外延性と
(_ map f)の等式、列挙型の鳩の巣による反駁、再帰的 CHC の 両方向の判定。 - 健全性。 約 45 コミットが、不健全な答えや誤った答えを直す。
データ型の非巡回性、
0^0の畳み込み、unknown ゲートをすり抜ける FP マーカー、CHC エンジンの誤った unsat。差分スイープでしか 見つからない種類のバグだ。
出力形式は z3 と一致するようになり(ビットベクタの数値表記、
モデルの体裁、unsat コア、get-objectives の MaxSAT ペナルティ)、
v0.0.6 から v0.0.8 まで三つのリリースが出た。
graphitesql:v0.1.0 と C ABI
Pure-Rust の SQLite である
graphitesql は
341 コミットで v0.1.0 をタグ付けした。いちばん変わったのは
カバー範囲の広さだ:
graphitesql-capi:libsqlite3 互換の C ABI を持つ兄弟 クレート。sqlite3_create_function、ウィンドウ関数、update・ commit・rollback の各フック、sqlite3_error_offsetを含む。 既存の C の呼び出し側がこれにリンクできる。- sqlite3_session の changeset:生成、反転、連結、そして カスタムの競合ハンドラ付きの適用。
- FTS5:外部コンテンツテーブル、メンテナンスコマンド、 プレフィクスインデックス、トゥームストーンセグメントによる インクリメンタルな削除・更新。
- 並行性。 複数接続の WAL リーダ向けに共有の wal-index、 トランザクションの最初の読み取りで取る読み取りロック。
- プランナと VDBE。 相関サブクエリ、集約を伴う結合、 インデックスによるソートの省略が、バイトコードエンジン上で 動くようになった。
- 厳密さの修正も長く続いた。テキスト値はバイト列として保持される
ようになり、UTF-8 でないテキストも SQLite と同じように往復する。
シェルには
.mode、.import、.showと、SQLite 風のエラー キャレットが加わった。
kataan:Temporal と汎用 JIT 層
argus ブラウザ用の JavaScript エンジンである
kataan は、test262 を
一件ずつ潰す段階から先へ進んだ。今週 Temporal の骨組みを作り、
そのまま全体を実装した。七つの plain 型、タイムゾーンデータ付きの
ZonedDateTime、ISO 以外の暦と暦を意識した算術、Duration の
丸め。その一連の作業の終わりに、built-ins/Temporal の失敗 0
を報告するコミットがある。Intl は Pure-Rust の ICU 相当である
intlrs の CLDR データに
付け替えられ、Temporal は DateTimeFormat で書式化できるように
なった。
ほかの作業:ShadowRealm の分離、Iterator.zip、import 属性と JSON
モジュール、仮想時計上の Atomics wait/waitAsync、タイマー付きの
イベントループ、node 風の Buffer・path・process。JIT では
NaN-boxing の汎用層に、制御フロー、プロパティと要素のインライン
高速パス、JIT→JIT の直接呼び出しが入った。
今週その他
- oxideav-av1 は エンコーダになった。適合レベルのキーフレームエンコーダに続き、 1/4 画素の動き、矩形パーティション、切り替え可能な補間フィルタ、 二参照の複合予測を備えた P フレームのインター符号化が入った。 自前で符号化したストリームが適合コーパスに加わった(39 → 50)。
- puregit は ロードマップを完了した。HTTP 越しのプロトコル v2、shallow clone と partial clone、到達可能性ビットマップ、ssh-agent 認証、SSH と OpenPGP によるコミット署名とその検証、libgit2 風の C ABI。
- puremp には、一般 数体篩、SEA による点の数え上げ、ECPP による素数証明、類群を伴う 代数体が加わった。
- latticefoundry に RISC-V RV64IM ターゲットが加わった。C フロントエンドの lf-cc は いまや GNU gzip(出力はバイト単位で同一)、bzip2、make、bash を コンパイルする。
- purecrypto は 性能改善に取り組んだ。ML-KEM・ML-DSA・SLH-DSA が共有する 4-way AVX2 の Keccak カーネル、AES-GCM のステッチ実装、P-256 と edwards25519 の comb テーブル。
- libwallet は Rust への移植を続けた。稼働中の Spot リレー越しのデバイス間 鍵生成、RemoteKey のシェア、旧来の TSS 署名。
- oxideav-ifc は ジオメトリのフェーズ 3(ブーリアン演算による切り抜き、 スイープソリッド、CSG)を進め、意味データ層に取りかかった。 プロパティセット、材料、単位、ジオリファレンス。
- teamclaude には、 モデルごとのルーティングと、アカウント切り替え時に サンダリングハードを避けるストーム制御が加わった。
来週
nixvm は Alpine の起動から、実際の作業負荷を動かす段階へ進む。 まずは Node のイベントループからだ。anydcode は実際のカメラ入力での 復号をさらに進める。z3rs は差分スイープを続け、graphitesql は 0.1 の 上に積み上げていく。