A more robust solution might be to add a lifetime directly to `ScipPtr`. So have `OwnedScip` and `ScipRef<'a>` instead of the `consumed` field.
mmghannam opened this issue · 8 comments
A more robust solution might be to add a lifetime directly to `ScipPtr`. So have `OwnedScip` and `ScipRef<'a>` instead of the `consumed` field.
Originally posted by @Andful in #149 (comment)
Oh, was not expecting the pull request to be merged without sparking any discussion.
I am a bit busy currently to implement this , but maybe, just to get an idea of the scope, I have a few questions:
- What is the purpose of
clone_for_plugin
? From my understanding it is used in callbacks to query model information, e.g. during branching. - Is it needed? I think, as of now, it suffers from the same problems as in #138 (By accessing the clone after the main model is dropped). I think it might be better just to remove it all together. If someone wants a shallow-copy(or a reference), the user can either choose to use a reference (
&Model
) or a reference-counting pointer (Rc<Model>
&Arc<Model>
). - Would it be fine to remove it (given that I fix the tests)? It would be an API breaking change :/, and some users might not love it.
- What is the purpose of
clone_for_plugin
? From my understanding it is used in callbacks to query model information, e.g. during branching.
Yes your understanding is correct.
- Is it needed? I think, as of now, it suffers from the same problems as in segfault (use after free) when accessing solution after model is dropped #138 (By accessing the clone after the main model is dropped). I think it might be better just to remove it all together. If someone wants a shallow-copy(or a reference), the user can either choose to use a reference (
&Model
) or a reference-counting pointer (Rc<Model>
&Arc<Model>
).- Would it be fine to remove it (given that I fix the tests)? It would be an API breaking change :/, and some users might not love it.
I don't mind removing it at all, as long as access to the SICP model is still allowed from plugins (callbacks).
Sorry for the late reply and thank you so much for your efforts!
@Andful what do you think about wrapping up ScipPtr
in an Arc
and passing it around every thing that has a reference to the model, and changing all ScipPtr
methods to use only immutable reference, since they are anyway can be protected from the Models methods. Then that should eliminate the use after free errors and would not need lifetimes? do you foresee any issues with this?
That seems like a much easier solution. Was contemplating that. I have to think about it a bit. We can defer freeing to be done by ScipPtr
, What is the function of vars
and conss
in e.g. Solution
?
I have started implementing this on the branch arc-scipptr
if you want to take a look.
What is the function of vars and conss in e.g. Solution?
I assume you mean in the Model states not the solution, it's to avoid creating structs for variables and constraints every time the user queries them. But now I'm actually rethinking this I think the rust compiler could optimize that away, and would remove this internal state that needs to be kept up to date. Anyhow, that's a separate issue.
I cannot see the branch. But feel free to ping me if you make a pull request. I was asking about vars
and conss
because they are freed by Model
. If we let scipptr
free the model and the variables on the C side, we just have to be a bit careful that vars
and conss
are not used after free or double freed.
Regarding Arc<ScipPtr>
, I have a small comment. ScipPtr
is not Send
. If there is no plan on making ScipPtr
Send
I would do Rc<ScipPtr>
, but if it is planned then Arc
is fine.
I cannot see the branch. But feel free to ping me if you make a pull request. I was asking about
vars
andconss
because they are freed byModel
. If we letscipptr
free the model and the variables on the C side, we just have to be a bit careful thatvars
andconss
are not used after free or double freed.
Sorry I forgot to push my changes :) I opened a draft PR with it #155.
Since the free method will only be called once after the last thing that has a reference in the model is freed, then use-after-free shouldn't happen. Also, because only the drop method in ScipPtr is the one responsible for freeing variables and constraints then we should be ok if we use Arc since it will only be called once.
Regarding
Arc<ScipPtr>
, I have a small comment.ScipPtr
is notSend
. If there is no plan on makingScipPtr
Send
I would doRc<ScipPtr>
, but if it is planned thenArc
is fine.
I think I want it to be Send in the future, I just need to think what invariants need to hold for this to be safe.