gpg-rs / gpgme

GPGme bindings for Rust
GNU Lesser General Public License v2.1
83 stars 13 forks source link

Clone Context #9

Open maennchen opened 7 years ago

maennchen commented 7 years ago

Hi @johnschug,

Thank you very much for this great lib!

I'm currently implementing an Elixir NIF (using rustler). To share the context to Elixir, I implemented a ResourceArc<ContextNifResource>.

To have immutability in elixir, I want to create a copy of the Context for every function that modifies it. (For example set_armor)

So that this works, I need the possibility to clone the Context.

I tried to do that myself using this code:

new_context = unsafe{Context::from_raw(Context::as_raw(old_context))}

I got those two errors though (not at the same time; randomly):

1:
Assertion failed: (!"lock ABI version"), function get_lock_object, file posix-lock.c, line 132.

2:
keybeam.smp(38723,0xb0599000) malloc: *** error for object 0x7fb36b4036c0: pointer being freed was not allocated
johnschug commented 7 years ago

Contexts cannot currently be cloned. This is a limitation of the underlying GPGme library. As a workaround you can create a new context manually and copy over the necessary attributes for whatever you are trying to do.

The errors you are receiving because of a use after free bug: Context::from_raw takes ownership of the context returned by as_raw, which does not release ownership.Context::from_raw and as_raw are mainly for code that interacts directly with the GPGme library.

maennchen commented 7 years ago

@johnschug Thanks for the clarification.

So you think the best way is to create a new context and copy over all values?

How would I approach this for the things in set_flag since there is no way to get all set flags?

Also for with_passphrase_provider, with_progress_handler and with_status_handler I see no getter functions.

If I wrote this clone function, would you like me to contribute that as the actual Clone implementation for the Context struct?

johnschug commented 7 years ago

To implement a general clone method you would have to keep track of those changes manually, since the underlying API doesn't provide a way to retrieve that information. For a specific operation you just have to copy over the relevant attributes, e.g. key_list_mode for find_keys. Instead of exposing the Context directly it might be easier to just expose higher level operations that are internally implemented using a context constructed for that operation. The operation can keep track of changes to the relevant attributes and construct an appropriate Context as necessary.

You can find examples of this approach as part of the official C++ Qt bindings: QGpgMESignJob