Fix potential infinite loop in business lot scrubbing

This commit is contained in:
Geert Janssens
2015-02-21 14:27:29 +01:00
parent 01170e664c
commit 8136d7ba3f

View File

@@ -82,31 +82,33 @@ scrub_other_link (GNCLot *from_lot, Split *ll_from_split,
GNCLot *to_lot, Split *ll_to_split) GNCLot *to_lot, Split *ll_to_split)
{ {
Split *real_from_split; // This refers to the split in the payment lot representing the payment itself Split *real_from_split; // This refers to the split in the payment lot representing the payment itself
gnc_numeric from_val, real_from_val, to_val;
gboolean modified = FALSE; gboolean modified = FALSE;
gnc_numeric real_from_val;
gnc_numeric from_val = xaccSplitGetValue (ll_from_split);
gnc_numeric to_val = xaccSplitGetValue (ll_to_split);
Transaction *ll_txn = xaccSplitGetParent (ll_to_split); Transaction *ll_txn = xaccSplitGetParent (ll_to_split);
// Per iteration we can only scrub at most max (val-doc-split, val-pay-split) // Per iteration we can only scrub at most min (val-doc-split, val-pay-split)
// So split the bigger one in two if needed and continue with the equal valued splits only // So set the ceiling for finding a potential offsetting split in the lot
// The remainder is added to the lot link transaction and the lot to keep everything balanced if (gnc_numeric_compare (gnc_numeric_abs (from_val), gnc_numeric_abs (to_val)) >= 0)
// and will be processed in a future iteration from_val = gnc_numeric_neg (to_val);
modified = reduce_biggest_split (ll_from_split, ll_to_split);
// Next we have to find the original payment split so we can // Next we have to find the original payment split so we can
// add (part of) it to the document lot // add (part of) it to the document lot
real_from_split = gncOwnerFindOffsettingSplit (from_lot, xaccSplitGetValue (ll_from_split)); real_from_split = gncOwnerFindOffsettingSplit (from_lot, from_val);
if (!real_from_split) if (!real_from_split)
return modified; // No usable split in the payment lot return FALSE; // No usable split in the payment lot
// Here again per iteration we can only scrub at most max (val-other-pay-split, val-pay-split) // We now have found 3 splits involved in the scrub action:
// So split the bigger one in two if needed and continue with the equal valued splits only // 2 lot link splits which we want to reduce
// 1 other split to move into the original lot instead of the lot link split
// As said only value of the split can be offset.
// So split the bigger ones in two if needed and continue with equal valued splits only
// The remainder is added to the lot link transaction and the lot to keep everything balanced // The remainder is added to the lot link transaction and the lot to keep everything balanced
// and will be processed in a future iteration // and will be processed in a future iteration
modified = reduce_biggest_split (real_from_split, ll_from_split);
// Once more check for max (val-doc-split, val-pay-split), and reduce if necessary.
// It may have changed while looking for the real payment split
modified = reduce_biggest_split (ll_from_split, ll_to_split); modified = reduce_biggest_split (ll_from_split, ll_to_split);
modified |= reduce_biggest_split (real_from_split, ll_from_split);
modified |= reduce_biggest_split (ll_from_split, ll_to_split);
// At this point ll_to_split and real_from_split should have the same value // At this point ll_to_split and real_from_split should have the same value
// If not, flag a warning and skip to the next iteration // If not, flag a warning and skip to the next iteration
@@ -116,8 +118,11 @@ scrub_other_link (GNCLot *from_lot, Split *ll_from_split,
if (!gnc_numeric_equal (real_from_val, to_val)) if (!gnc_numeric_equal (real_from_val, to_val))
{ {
// This is unexpected - write a warning message and skip this split // This is unexpected - write a warning message and skip this split
PWARN("real_from_val and to_val differ. " PWARN("real_from_val (%s) and to_val (%s) differ. "
"This is unexpected! Skip scrubbing of real_from_split %p against ll_to_split %p.", real_from_split, ll_to_split); "This is unexpected! Skip scrubbing of real_from_split %p against ll_to_split %p.",
gnc_numeric_to_string (real_from_val), // gnc_numeric_denom (real_from_val),
gnc_numeric_to_string (to_val), // gnc_numeric_denom (to_val),
real_from_split, ll_to_split);
return modified; return modified;
} }