Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add: C APIの#[repr(Rust)]なものへのアクセスをすべて安全にする #849

Merged
merged 9 commits into from
Oct 8, 2024

Conversation

qryxip
Copy link
Member

@qryxip qryxip commented Oct 5, 2024

内容

C APIにおいて、Rust APIのオブジェクトそのものの代わりにトークンのような1-bit長の構造体ユーザーに渡すようにすることで、次のことを実現する。

  1. "delete"時に対象オブジェクトに対するアクセスがあった場合、アクセスが終わるまで待つ
  2. 次のユーザー操作に対するセーフティネットを張り、パニックするようにする
    1. "delete"後に他の通常のメソッド関数の利用を試みる
    2. "delete"後に"delete"を試みる
    3. そもそもオブジェクトとして変なダングリングポインタが渡される

ドキュメントとしてのsafety requirementsもあわせて緩和する。

このPRは #836 の解決 ではなく、ドキュメントにも手を加えていない。というのもVoicevoxVoiceModelFileには次のゲッターメソッドがあり、これらをカバーするのは現状のAPIの形だと不可能だからである

  • voicevox_voice_model_file_id
  • voicevox_voice_model_file_get_metas_json

関連 Issue

Resolves #836.

その他

@qryxip qryxip requested a review from Hiroshiba October 5, 2024 19:15
C APIにおいて次の状況に対してセーフティネットを張り、パニックするように
する。

1. オブジェクトが他スレッドでアクセスされている最中に"delete"を試みる
2. "delete"後に他の通常のメソッド関数の利用を試みる
3. "delete"後に"delete"を試みる

このPRは VOICEVOX#836 の解決**ではなく**、ドキュメントにも手を加えていない。とい
うのも`VoicevoxVoiceModelFile`には次のゲッターメソッドがあり、これらをカ
バーするのは現状のAPIの形だと不可能だからである。

* `voicevox_voice_model_file_id`
* `voicevox_voice_model_file_get_metas_json`
@qryxip qryxip force-pushed the add-safety-net-c-api-delete-fuctions branch from 5a56580 to 223a77b Compare October 5, 2024 19:25
@qryxip
Copy link
Member Author

qryxip commented Oct 5, 2024

元々やりたかったこととしては #832 みたいな設計をC APIでもやることでした。しかしそのためにはVoicevoxVoiceModelFileに生えている二つのゲッターメソッドが邪魔であることが今回わかりました。(このPRはこのPRでマージするとして、その後)どうにかするための対応としては次のように考えています。

  1. 二つのゲッターメソッドをゲッターではなくする

    voicevox_voice_model_file_iduint8_t (*output)[16]のような引数に吐き出すようにし、voicevox_voice_model_file_get_metas_jsonの方はcreate_metas_jsonに改名してvoicevox_json_freeが必要なようにする。

  2. 単なるゲッターではなくbracket patternにする

    関数オブジェクトをどう表現するかがすごい面倒そう…

  3. char*自体の代わりにVoicevoxStringRefみたいなオブジェクトを返すようにし、VoicevoxStringRefは"delete"を必要とする

    VoicevoxStringRef *metas = voicevox_voice_model_file_get_metas_json(model);
    
    char *metas_cstr = voicevox_string_ref_get_data(metas);
    do_something(metas_cstr);
    
    // `char*`を使い終えたことをVOICEVOX CORE C APIに伝える
    voicevox_string_ref_delete(metas);

    bracket patternほどではないけど使うのが面倒そう… あとVoicevoxStringRefもまた同じように管理するの?という気もしてくる。

  4. [追記] voicevox_voice_model_file_delete〃_closeの二種類を作る

    Closable__exit__のようなクローズ処理に対応する"close"と、本当のデストラクトに対応する"delete"の二種類を作る。"close"の方は他言語バインディング作成専用という感じで。

  5. 諦める

    このPRで対応を打ち切り、「Synthesizer::load_voice_model中にVoiceModelをデストラクトしたらどうなるのか」の問題は各バインディング製作者に任せる。

個人的には1.か4.なのですが、VoicevoxCoreSharpを作っている @yamachu さんにも意見を伺いたいなーと。

Comment on lines 129 to 150
/// プロセスの終わりまでデストラクトされない、ユーザーにオブジェクトとして貸し出す`u32`相当の値。
///
/// インスタンスは次のような形。
///
/// ```
/// #[derive(Clone, Copy, Debug, From, Into)]
/// #[repr(Rust)]
/// pub struct VoicevoxSynthesizer {
/// id: u32,
/// }
/// ```
///
/// `Body`そのものではなくこのトレイトのインスタンスをユーザーに渡すようにし、次のユーザー操作に対するセーフティネットを実現する。
///
/// 1. オブジェクトが他スレッドでアクセスされている最中に"delete"を試みる
/// 2. "delete"後に他の通常のメソッド関数の利用を試みる
/// 3. "delete"後に"delete"を試みる
///
/// ただし次のゲッター関数に関しては機能しない。
///
/// - `voicevox_voice_model_file_id`
/// - `voicevox_voice_model_file_get_metas_json`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doc commentだけ書いてみました。
Discordの会話: https://discord.com/channels/879570910208733277/893889888208977960/1292402538745954346

@yamachu
Copy link
Member

yamachu commented Oct 6, 2024

今回の変更ですが、言語バインディングライブラリを作る者として扱いやすいC APIになるなと感じました、ありがとうございます。

#849 (comment)
こちらの VoicevoxVoiceModelFile の扱いですが、私も 1 or 4 、良さそう具合で言えば 1 > 4 かなと考えています。
正直な所、自分の不勉強で申し訳ないのですが 2 がどんな感じになるのかがイメージできてないからという理由もあります。
3 は扱いが面倒だなという一言に尽きるかな…と…

1 は他の API との一貫性が取れているように感じるので、良いのかなとは思いました。

@Hiroshiba
Copy link
Member

自分もちゃんとわかってない気もしますが、1が良さそうに思いました!
っていうかまあ、これでstring周りの処理が全部共通になるって感じですかね?
確か単純にポイントが得られるパターンと、deleteが必要なパターンがあった記憶。

qryxip added a commit to qryxip/voicevox_core that referenced this pull request Oct 6, 2024
`VoicevoxVoiceModelFile`の次のゲッター関数を、ゲッター関数ではなくする。

- `voicevox_voice_model_file_id`
    `uint8_t (*output_voice_model_id)[16]`に吐き出すようにする。
- `voicevox_voice_model_file_get_metas_json`
    `voicevox_voice_model_file_create_metas_json`に改名。

ねらいとしては VOICEVOX#832 のような設計をC APIでも行うことで、サードパーティの
バインディング製作者の労力を減らすため。上記のゲッター関数がゲッターでは
なくなれば、オブジェクトへのアクセスを完全に管理できる。

VOICEVOX#849 (comment)
qryxip added a commit that referenced this pull request Oct 6, 2024
`VoicevoxVoiceModelFile`の次のゲッター関数を、ゲッター関数ではなくする。

- `voicevox_voice_model_file_id`
    `uint8_t (*output_voice_model_id)[16]`に吐き出すようにする。
- `voicevox_voice_model_file_get_metas_json`
    `voicevox_voice_model_file_create_metas_json`に改名。

ねらいとしては #832 のような設計をC APIでも行うことで、サードパーティの
バインディング製作者の労力を減らすため。上記のゲッター関数がゲッターでは
なくなれば、オブジェクトへのアクセスを完全に管理できる。

#849 (comment)
@qryxip
Copy link
Member Author

qryxip commented Oct 6, 2024

464d6f7 (#849): CApiObject::BodyRustApiObjectに改名しました。


#850 をマージできたので、#836 をやらないとですね…

@qryxip qryxip marked this pull request as draft October 6, 2024 18:38
@qryxip
Copy link
Member Author

qryxip commented Oct 7, 2024

  • 3e6ddf1 (#849): CApiObjectに"ID"を持たせなくても、ポインタのアドレスで代用できることに気付いたのでそうしてしまいました。永続するboxcar::Vec<impl CApiObject>によるメモリリークが一要素につき4-byteから1-byteになります。
  • ad753de (#849): "delete"時にオブジェクトへの他のアクセスを待つようにしました。

あとはドキュメントを更新すれば #836 をresolveできるはず。

@qryxip qryxip changed the title add: C APIの"delete"にセーフティネットを張る add: C APIの"delete"を安全なAPIにする Oct 7, 2024
@qryxip qryxip force-pushed the add-safety-net-c-api-delete-fuctions branch from 09d4990 to 274c2ea Compare October 7, 2024 20:45
@qryxip qryxip marked this pull request as ready for review October 7, 2024 20:45
@qryxip
Copy link
Member Author

qryxip commented Oct 7, 2024

  • 61cc6df (#849) このPRのdraftを外せるよう、ドキュメントを更新。
  • e6abd77 (#849): この仕組みならそもそもユーザーから渡されるVoicevoxSynthesizer*とかの有効性を信用しなくてもよいのでは?と思い、API全般においてVoicevoxSynthesizerのポインタはポインタのままで扱うように。これによりユーザーに要求するsafety requirementsが緩和された。

@qryxip qryxip changed the title add: C APIの"delete"を安全なAPIにする add: C APIの#[repr(Rust)]なものへのアクセスをすべて安全にする Oct 7, 2024
@qryxip qryxip force-pushed the add-safety-net-c-api-delete-fuctions branch 2 times, most recently from 54d967f to 242e8ed Compare October 8, 2024 02:16
@qryxip qryxip force-pushed the add-safety-net-c-api-delete-fuctions branch from 242e8ed to e6abd77 Compare October 8, 2024 02:23
Copy link
Member

@Hiroshiba Hiroshiba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

一応確認なのですが、レビュー始めちゃっても大丈夫でしょうか 👀

@qryxip
Copy link
Member Author

qryxip commented Oct 8, 2024

大丈夫です!

Copy link
Member

@Hiroshiba Hiroshiba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!!!

1点だけ、ドキュメントに関して細かいコメントをしただけになってしまいました!

クラッシュという表現もいい感じな気がしました。もしかしたら最近のプログラマーには通じないのかもだけど。
異常終了が丸いかも。でもまあ何でもいい気がしました!!

@qryxip qryxip merged commit f2e6b60 into VOICEVOX:main Oct 8, 2024
35 checks passed
@qryxip qryxip deleted the add-safety-net-c-api-delete-fuctions branch October 8, 2024 16:38

let this = {
let mut heads = Self::lock_heads();
heads.push(Default::default());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that the validate function below checks if the pointer points inside heads, but this line can cause heads to reallocate, which means that creating a new object might invalidate existing pointers.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh no thank you! You are obviously right.

I'll use boxcar.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(probably) fixed in #862.

qryxip added a commit to qryxip/voicevox_core that referenced this pull request Oct 24, 2024
@qryxip qryxip mentioned this pull request Oct 24, 2024
qryxip added a commit that referenced this pull request Oct 25, 2024
Fix up #849.

The main purpose is fixing the following bug using `boxcar`.

#849 (comment)

Refs: #849
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

C APIの"delete"を安全なAPIにする
4 participants