hiro99ma blog

何か技術的なこと

btc: libwally-core を使う (4)

2025/01/29

はじめに

C言語で libwally-core を使って P2TR のトランザクションを作っている。
まだコード整理中。

free のタイミング

valgrind でチェックしていてメモリリークがあることが分かった。
wally_cleanup() は うまいこと確保したメモリの対処をしてくれるわけではなかった。

なんでそんなことを思っていたかというと ccan/tal に配下のメモリをまとめて解放する機構があったからだ。
もちろんそうするためには誰が誰の配下かを教えないといけないのだが、libwally-core で確保したメモリは全体的に wally_init() 以降はトップメモリの配下になってるんじゃなかろうかと思っていたのだが違った。
もしそうだったら valgrind で検出できないはずだ。 コードを確認すると、libsecp256k1 のコンテキストを解放するだけだった。

解放し損ねていたのは 1箇所で、wally_witness_p2tr_from_sig() で確保していた struct wally_tx_witness_stack だ。
確保した後 wally_tx_set_input_witness() でトランザクションデータとして与えているので wally_tx_witness_stack_free() で解放するのは struct wally_tx の解放前後だろうと考えていた。
しかし実装を確認するとクローン してからそちらの方を struct wally_tx に与えている。
つまり wally_tx_set_input_witness() したら解放してよいということだ。
全部は見ていないが wally_tx_add_input/output() もそうなっていた。

これは全般的にそうしていると思っていて良いのかな? 使い方としてどこかに書かれていないと不安になるところだ。
解放しないといけないというところは同じなのだが、実装しているとタイミングを別にしたいこともしばしばあるので安全といえば安全なのかな。

とはいえ、一時的にでもメモリが倍必要になり、データをコピーする手間も発生するというのが気に掛かる。
動的なメモリを管理できるくらいのプラットフォームで動かすのだから、それくらいは手間にもならないのかもしれない。
ライブラリが内部で使うものはライブラリがメモリ管理するから、その外側で明示的にメモリを確保した場合は対処しなさい、というのはメモリ問題が起きにくいし、 安全性が求められるライブラリだと必須の対策なのかもしれない。

話を元に戻すと、それが嫌だったら直接 witness を struct wally_tx に代入すれば良いが注意がいる。
inputs_allocation_len のような _allocation_len をちゃんと面倒見ないと tx_free() ではメモリをクリアして解放しているのでおかしくなってくる。
1箇所でもそうしてしまったら add 系 や tx_free() などは使えないものと思った方が良いのかも。

ああ、API 数が多いのは構造体の中身を知らなくても値を設定できるようにするためか。。。

おわりに

今日はここまで。

< Top page