mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Fix more memory leaks. Also, when closing a book (to open a new one, not year end), free objects.
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@20042 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
3bd95ca483
commit
55865d2e1b
@ -266,6 +266,10 @@ GList *gnc_account_list_name_violations (QofBook *book, const gchar *separator)
|
|||||||
else
|
else
|
||||||
g_free ( acct_name );
|
g_free ( acct_name );
|
||||||
}
|
}
|
||||||
|
if (accounts != NULL)
|
||||||
|
{
|
||||||
|
g_list_free(accounts);
|
||||||
|
}
|
||||||
|
|
||||||
return invalid_list;
|
return invalid_list;
|
||||||
}
|
}
|
||||||
@ -1230,13 +1234,26 @@ xaccAccountCommitEdit (Account *acc)
|
|||||||
PINFO ("freeing splits for account %p (%s)",
|
PINFO ("freeing splits for account %p (%s)",
|
||||||
acc, priv->accountName ? priv->accountName : "(null)");
|
acc, priv->accountName ? priv->accountName : "(null)");
|
||||||
|
|
||||||
slist = g_list_copy(priv->splits);
|
book = qof_instance_get_book(acc);
|
||||||
for (lp = slist; lp; lp = lp->next)
|
|
||||||
|
/* If book is shutting down, just clear the split list. The splits
|
||||||
|
themselves will be destroyed by the transaction code */
|
||||||
|
if (!qof_book_shutting_down(book))
|
||||||
{
|
{
|
||||||
Split *s = lp->data;
|
slist = g_list_copy(priv->splits);
|
||||||
xaccSplitDestroy (s);
|
for (lp = slist; lp; lp = lp->next)
|
||||||
|
{
|
||||||
|
Split *s = lp->data;
|
||||||
|
xaccSplitDestroy (s);
|
||||||
|
}
|
||||||
|
g_list_free(slist);
|
||||||
}
|
}
|
||||||
g_list_free(slist);
|
else
|
||||||
|
{
|
||||||
|
g_list_free(priv->splits);
|
||||||
|
priv->splits = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* It turns out there's a case where this assertion does not hold:
|
/* It turns out there's a case where this assertion does not hold:
|
||||||
When the user tries to delete an Imbalance account, while also
|
When the user tries to delete an Imbalance account, while also
|
||||||
deleting all the splits in it. The splits will just get
|
deleting all the splits in it. The splits will just get
|
||||||
@ -1245,18 +1262,17 @@ xaccAccountCommitEdit (Account *acc)
|
|||||||
g_assert(priv->splits == NULL || qof_book_shutting_down(acc->inst.book));
|
g_assert(priv->splits == NULL || qof_book_shutting_down(acc->inst.book));
|
||||||
*/
|
*/
|
||||||
|
|
||||||
book = qof_instance_get_book(acc);
|
|
||||||
if (!qof_book_shutting_down(book))
|
if (!qof_book_shutting_down(book))
|
||||||
{
|
{
|
||||||
col = qof_book_get_collection(book, GNC_ID_TRANS);
|
col = qof_book_get_collection(book, GNC_ID_TRANS);
|
||||||
qof_collection_foreach(col, destroy_pending_splits_for_account, acc);
|
qof_collection_foreach(col, destroy_pending_splits_for_account, acc);
|
||||||
}
|
|
||||||
|
|
||||||
/* the lots should be empty by now */
|
/* the lots should be empty by now */
|
||||||
for (lp = priv->lots; lp; lp = lp->next)
|
for (lp = priv->lots; lp; lp = lp->next)
|
||||||
{
|
{
|
||||||
GNCLot *lot = lp->data;
|
GNCLot *lot = lp->data;
|
||||||
gnc_lot_destroy (lot);
|
gnc_lot_destroy (lot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_list_free(priv->lots);
|
g_list_free(priv->lots);
|
||||||
priv->lots = NULL;
|
priv->lots = NULL;
|
||||||
@ -4807,6 +4823,16 @@ xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
|
|||||||
|
|
||||||
/* ================================================================ */
|
/* ================================================================ */
|
||||||
/* QofObject function implementation and registration */
|
/* QofObject function implementation and registration */
|
||||||
|
|
||||||
|
static void
|
||||||
|
gnc_account_book_end(QofBook* book)
|
||||||
|
{
|
||||||
|
Account *root_account = gnc_book_get_root_account(book);
|
||||||
|
|
||||||
|
xaccAccountBeginEdit(root_account);
|
||||||
|
xaccAccountDestroy(root_account);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
/* MSVC compiler doesn't have C99 "designated initializers"
|
/* MSVC compiler doesn't have C99 "designated initializers"
|
||||||
* so we wrap them in a macro that is empty on MSVC. */
|
* so we wrap them in a macro that is empty on MSVC. */
|
||||||
@ -4821,7 +4847,7 @@ static QofObject account_object_def =
|
|||||||
DI(.type_label = ) "Account",
|
DI(.type_label = ) "Account",
|
||||||
DI(.create = ) (gpointer)xaccMallocAccount,
|
DI(.create = ) (gpointer)xaccMallocAccount,
|
||||||
DI(.book_begin = ) NULL,
|
DI(.book_begin = ) NULL,
|
||||||
DI(.book_end = ) NULL,
|
DI(.book_end = ) gnc_account_book_end,
|
||||||
DI(.is_dirty = ) qof_collection_is_dirty,
|
DI(.is_dirty = ) qof_collection_is_dirty,
|
||||||
DI(.mark_clean = ) qof_collection_mark_clean,
|
DI(.mark_clean = ) qof_collection_mark_clean,
|
||||||
DI(.foreach = ) qof_collection_foreach,
|
DI(.foreach = ) qof_collection_foreach,
|
||||||
|
@ -541,9 +541,9 @@ recurrenceListIsSemiMonthly(GList *recurrences)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
recurrenceListIsWeeklyMultiple(GList *recurrences)
|
recurrenceListIsWeeklyMultiple(const GList *recurrences)
|
||||||
{
|
{
|
||||||
GList *r_iter;
|
const GList *r_iter;
|
||||||
|
|
||||||
for (r_iter = recurrences; r_iter != NULL; r_iter = r_iter->next)
|
for (r_iter = recurrences; r_iter != NULL; r_iter = r_iter->next)
|
||||||
{
|
{
|
||||||
|
@ -161,7 +161,7 @@ gchar *recurrenceListToString(const GList *rlist);
|
|||||||
/** @return True if the recurrence list is a common "semi-monthly" recurrence. **/
|
/** @return True if the recurrence list is a common "semi-monthly" recurrence. **/
|
||||||
gboolean recurrenceListIsSemiMonthly(GList *recurrences);
|
gboolean recurrenceListIsSemiMonthly(GList *recurrences);
|
||||||
/** @return True if the recurrence list is a common "weekly" recurrence. **/
|
/** @return True if the recurrence list is a common "weekly" recurrence. **/
|
||||||
gboolean recurrenceListIsWeeklyMultiple(GList *recurrences);
|
gboolean recurrenceListIsWeeklyMultiple(const GList *recurrences);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pretty-print an intentionally-short summary of the period of a (GList of)
|
* Pretty-print an intentionally-short summary of the period of a (GList of)
|
||||||
|
@ -125,7 +125,7 @@ sxtg_book_begin (QofBook *book)
|
|||||||
static void
|
static void
|
||||||
sxtg_book_end (QofBook *book)
|
sxtg_book_end (QofBook *book)
|
||||||
{
|
{
|
||||||
gnc_book_set_template_root (book, NULL);
|
// gnc_book_set_template_root (book, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -483,11 +483,15 @@ xaccSchedXactionFree( SchedXaction *sx )
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* xaccAccountDestroy removes the account from
|
* xaccAccountDestroy removes the account from
|
||||||
* its group for us AFAICT
|
* its group for us AFAICT. If shutting down,
|
||||||
|
* the account is being deleted separately.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
xaccAccountBeginEdit(sx->template_acct);
|
if (!qof_book_shutting_down(qof_instance_get_book(sx)))
|
||||||
xaccAccountDestroy(sx->template_acct);
|
{
|
||||||
|
xaccAccountBeginEdit(sx->template_acct);
|
||||||
|
xaccAccountDestroy(sx->template_acct);
|
||||||
|
}
|
||||||
|
|
||||||
for ( l = sx->deferredList; l; l = l->next )
|
for ( l = sx->deferredList; l; l = l->next )
|
||||||
{
|
{
|
||||||
@ -1248,6 +1252,9 @@ gnc_sx_remove_defer_instance( SchedXaction *sx, void *deferStateData )
|
|||||||
* temporal-state-data instance list. The list should not be modified by the
|
* temporal-state-data instance list. The list should not be modified by the
|
||||||
* caller; use the gnc_sx_{add,remove}_defer_instance() functions to modifiy
|
* caller; use the gnc_sx_{add,remove}_defer_instance() functions to modifiy
|
||||||
* the list.
|
* the list.
|
||||||
|
*
|
||||||
|
* @param sx Scheduled transaction
|
||||||
|
* @return Defer list which must not be modified by the caller
|
||||||
**/
|
**/
|
||||||
GList*
|
GList*
|
||||||
gnc_sx_get_defer_instances( SchedXaction *sx )
|
gnc_sx_get_defer_instances( SchedXaction *sx )
|
||||||
@ -1255,6 +1262,29 @@ gnc_sx_get_defer_instances( SchedXaction *sx )
|
|||||||
return sx->deferredList;
|
return sx->deferredList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy_sx_on_book_close(QofInstance *ent, gpointer data)
|
||||||
|
{
|
||||||
|
SchedXaction* sx = GNC_SCHEDXACTION(ent);
|
||||||
|
|
||||||
|
gnc_sx_begin_edit(sx);
|
||||||
|
xaccSchedXactionDestroy(sx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys all SXes in the book because the book is being destroyed.
|
||||||
|
*
|
||||||
|
* @param book Book being destroyed
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
gnc_sx_book_end(QofBook* book)
|
||||||
|
{
|
||||||
|
QofCollection *col;
|
||||||
|
|
||||||
|
col = qof_book_get_collection(book, GNC_ID_SCHEDXACTION);
|
||||||
|
qof_collection_foreach(col, destroy_sx_on_book_close, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
/* MSVC compiler doesn't have C99 "designated initializers"
|
/* MSVC compiler doesn't have C99 "designated initializers"
|
||||||
* so we wrap them in a macro that is empty on MSVC. */
|
* so we wrap them in a macro that is empty on MSVC. */
|
||||||
@ -1269,7 +1299,7 @@ static QofObject SXDesc =
|
|||||||
DI(.type_label = ) "Scheduled Transaction",
|
DI(.type_label = ) "Scheduled Transaction",
|
||||||
DI(.create = ) (gpointer)xaccSchedXactionMalloc,
|
DI(.create = ) (gpointer)xaccSchedXactionMalloc,
|
||||||
DI(.book_begin = ) NULL,
|
DI(.book_begin = ) NULL,
|
||||||
DI(.book_end = ) NULL,
|
DI(.book_end = ) gnc_sx_book_end,
|
||||||
DI(.is_dirty = ) qof_collection_is_dirty,
|
DI(.is_dirty = ) qof_collection_is_dirty,
|
||||||
DI(.mark_clean = ) qof_collection_mark_clean,
|
DI(.mark_clean = ) qof_collection_mark_clean,
|
||||||
DI(.foreach = ) qof_collection_foreach,
|
DI(.foreach = ) qof_collection_foreach,
|
||||||
|
@ -1182,14 +1182,26 @@ do_destroy (Transaction *trans)
|
|||||||
|
|
||||||
qof_event_gen (&trans->inst, QOF_EVENT_DESTROY, NULL);
|
qof_event_gen (&trans->inst, QOF_EVENT_DESTROY, NULL);
|
||||||
|
|
||||||
/* We only own the splits that still think they belong to us. */
|
/* We only own the splits that still think they belong to us. This is done
|
||||||
trans->splits = g_list_copy(trans->splits);
|
in 2 steps. In the first, the splits are marked as being destroyed, but they
|
||||||
|
are not destroyed yet. In the second, the destruction is committed which will
|
||||||
|
do the actual destruction. If both steps are done for a split before they are
|
||||||
|
done for the next split, then a split will still be on the split list after it
|
||||||
|
has been freed. This can cause other parts of the code (e.g. in xaccSplitDestroy())
|
||||||
|
to reference the split after it has been freed. */
|
||||||
for (node = trans->splits; node; node = node->next)
|
for (node = trans->splits; node; node = node->next)
|
||||||
{
|
{
|
||||||
Split *s = node->data;
|
Split *s = node->data;
|
||||||
if (s->parent == trans)
|
if (s->parent == trans)
|
||||||
{
|
{
|
||||||
xaccSplitDestroy(s);
|
xaccSplitDestroy(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (node = trans->splits; node; node = node->next)
|
||||||
|
{
|
||||||
|
Split *s = node->data;
|
||||||
|
if (s->parent == trans)
|
||||||
|
{
|
||||||
xaccSplitCommitEdit(s);
|
xaccSplitCommitEdit(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2296,6 +2308,27 @@ xaccTransFindSplitByAccount(const Transaction *trans, const Account *acc)
|
|||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
/* QofObject function implementation */
|
/* QofObject function implementation */
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy_tx_on_book_close(QofInstance *ent, gpointer data)
|
||||||
|
{
|
||||||
|
Transaction* tx = GNC_TRANSACTION(ent);
|
||||||
|
|
||||||
|
xaccTransDestroy(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handles book end - frees all transactions from the book
|
||||||
|
*
|
||||||
|
* @param book Book being closed
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
gnc_transaction_book_end(QofBook* book)
|
||||||
|
{
|
||||||
|
QofCollection *col;
|
||||||
|
|
||||||
|
col = qof_book_get_collection(book, GNC_ID_TRANS);
|
||||||
|
qof_collection_foreach(col, destroy_tx_on_book_close, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
/* MSVC compiler doesn't have C99 "designated initializers"
|
/* MSVC compiler doesn't have C99 "designated initializers"
|
||||||
* so we wrap them in a macro that is empty on MSVC. */
|
* so we wrap them in a macro that is empty on MSVC. */
|
||||||
@ -2312,7 +2345,7 @@ static QofObject trans_object_def =
|
|||||||
DI(.type_label = ) "Transaction",
|
DI(.type_label = ) "Transaction",
|
||||||
DI(.create = ) (gpointer)xaccMallocTransaction,
|
DI(.create = ) (gpointer)xaccMallocTransaction,
|
||||||
DI(.book_begin = ) NULL,
|
DI(.book_begin = ) NULL,
|
||||||
DI(.book_end = ) NULL,
|
DI(.book_end = ) gnc_transaction_book_end,
|
||||||
DI(.is_dirty = ) qof_collection_is_dirty,
|
DI(.is_dirty = ) qof_collection_is_dirty,
|
||||||
DI(.mark_clean = ) qof_collection_mark_clean,
|
DI(.mark_clean = ) qof_collection_mark_clean,
|
||||||
DI(.foreach = ) qof_collection_foreach,
|
DI(.foreach = ) qof_collection_foreach,
|
||||||
|
@ -134,11 +134,14 @@ gchar * gnc_build_book_path (const gchar *filename);
|
|||||||
{
|
{
|
||||||
SCM key_scm = SCM_CAR (path_scm);
|
SCM key_scm = SCM_CAR (path_scm);
|
||||||
char *key;
|
char *key;
|
||||||
|
gchar* gkey;
|
||||||
|
|
||||||
if (!scm_is_string (key_scm))
|
if (!scm_is_string (key_scm))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
key = g_strdup (scm_to_locale_string (key_scm));
|
key = scm_to_locale_string (key_scm);
|
||||||
|
gkey = g_strdup (key);
|
||||||
|
gnc_free_scm_locale_string(key);
|
||||||
|
|
||||||
path = g_list_prepend (path, key);
|
path = g_list_prepend (path, key);
|
||||||
|
|
||||||
|
@ -614,6 +614,23 @@ gnc_lot_get_latest_split (GNCLot *lot)
|
|||||||
|
|
||||||
/* ============================================================= */
|
/* ============================================================= */
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy_lot_on_book_close(QofInstance *ent, gpointer data)
|
||||||
|
{
|
||||||
|
GNCLot* lot = GNC_LOT(ent);
|
||||||
|
|
||||||
|
gnc_lot_destroy(lot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gnc_lot_book_end(QofBook* book)
|
||||||
|
{
|
||||||
|
QofCollection *col;
|
||||||
|
|
||||||
|
col = qof_book_get_collection(book, GNC_ID_LOT);
|
||||||
|
qof_collection_foreach(col, destroy_lot_on_book_close, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
/* MSVC compiler doesn't have C99 "designated initializers"
|
/* MSVC compiler doesn't have C99 "designated initializers"
|
||||||
* so we wrap them in a macro that is empty on MSVC. */
|
* so we wrap them in a macro that is empty on MSVC. */
|
||||||
@ -628,7 +645,7 @@ static QofObject gncLotDesc =
|
|||||||
DI(.type_label = ) "Lot",
|
DI(.type_label = ) "Lot",
|
||||||
DI(.create = ) (gpointer)gnc_lot_new,
|
DI(.create = ) (gpointer)gnc_lot_new,
|
||||||
DI(.book_begin = ) NULL,
|
DI(.book_begin = ) NULL,
|
||||||
DI(.book_end = ) NULL,
|
DI(.book_end = ) gnc_lot_book_end,
|
||||||
DI(.is_dirty = ) qof_collection_is_dirty,
|
DI(.is_dirty = ) qof_collection_is_dirty,
|
||||||
DI(.mark_clean = ) qof_collection_mark_clean,
|
DI(.mark_clean = ) qof_collection_mark_clean,
|
||||||
DI(.foreach = ) qof_collection_foreach,
|
DI(.foreach = ) qof_collection_foreach,
|
||||||
|
Loading…
Reference in New Issue
Block a user