-
Notifications
You must be signed in to change notification settings - Fork 802
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
Price guardian #1716
base: stable
Are you sure you want to change the base?
Price guardian #1716
Conversation
1650891
to
70ecf15
Compare
(if price (gnc-price-unref price)) | ||
(set! pricing-txn trans) | ||
(set! price trans-price) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bugs me. Does (gnc:price-ref price)
put price
or *price
(in C's meaning, Guile having no way to express it) on the guardian's list? If it's *price
then no problem; otherwise this will leak the original *price
and if trans-price
will get an extra unref.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, the reports shouldn't generally call gnc-price-ref/unref, and shuould leave it to the guardians. I don't know whether it calls price
or *price
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They don't generally, only the two portfolio reports do. Nothing in Scheme except test-engine-extras.scm writes to price objects, so one option would be to copy the few things that reports need from prices (currency, commodity, time, and value) and not swig any of the price API.
Do you understand the problem with (set! price trans-price)
if the guardian is using the addresses of price
and trans-price
instead of the addresses that they point to (e.g. *price
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you understand the problem with
(set! price trans-price)
if the guardian is using the addresses ofprice
andtrans-price
instead of the addresses that they point to (e.g.*price
)?
Not quite.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two GncPrice pointers, p1
and p2
. price
is initialized to p1
and trans-price
to p2
. price-guardian
is called on price
and trans-price
when each is initialized, then (set! price trans-price)
happens and both price
and trans-price
equal p2
.
If (price-guardian price)
causes the guardian to keep track of p1
(what I called the '*price' scenario) then after the set!
call it's garbage-collected and returned and unreffed by reclaim-prices
. Later when both price
and trans-price
go out of scope (maybe at the end of the report render)p2
is garbage collected and can be unreffed by reclaim-prices
. All good.
But if (price-guardian price)
keeps a reference to price
(the 'price' scenario) then it's not guarding p1
. It doesn't return anything until price
or trans-price
go out of scope, and when they do it returns p2
for each one, so p1
leaks and p2
gets unreffed twice. Not good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see slightly and don't know the answer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then you need to find out. If it's the latter case then the set!
has to go, it's a potential use-after-free crasher.
Alternative: Remove all of the price refs and unrefs, no guardians. I don't think any of these calculations will be interrupted by a status bar update, and even if they can the user would have to somehow queue a price-delete to run during an idle for a price to become invalid while the report is loading. Pretty darn unlikely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternative: Remove all of the price refs and unrefs, no guardians. I don't think any of these calculations will be interrupted by a status bar update, and even if they can the user would have to somehow queue a price-delete to run during an idle for a price to become invalid while the report is loading. Pretty darn unlikely.
So, #1403 resurrected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, probably safer than this. But copying it into a scheme record would be safer still.
increases refcount for price, and adds a gc hook to the price SCM object. when the SCM object is gc, it's appropriately unreffed.
70ecf15
to
4e3ddca
Compare
I had another idea to move this guardian to engine.i and disallow gnc_price_ref/unref from being swigged. |
@christopherlam did you try using swig %refobject ? |
Good find... unfortunately I have no idea how this works. |
It's for "legacy C++", meaning before C++11. Modern C++ uses std::shared_ptr instead of hand-rolling ref counting. It also appears to require Having reread again the Guile Memory Management docs I'm pretty sure that guile's GC only knows about guile objects (the 'price' model). So guardians are a fine way to handle lifetime but the guarded variable can't be mutated: No |
It's nicer because it hides the guardians from the report code, but it still has the reference problem.
No, #1403 wanted to remove the memory management from gnc-pricedb.c, a terrible idea. I'm just suggesting to remove it from the two portfolio reports. Copying the price info into Scheme would reduce the risk still further; doing so in wrapped C code that refs the gnc_price, makes the copy, then unrefs the gnc_price would be safest. |
Rewrite for #1403
Adds mechanism for guarding SCM objects referring to price.
gnc:price-ref
will guard the price. As long as the SCM object is alive, the price ref will be increased; when gc runs, the guardian will appropriately unref prices.If a report which accesses price is run, and gc hasn't triggered yet, then the price ref would not be decremented yet. Hence the call to
scm_gc()
after running a report.