summaryrefslogtreecommitdiff
path: root/main/cdr.c
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2016-10-18 16:30:17 -0500
committerMark Michelson <mmichelson@digium.com>2016-10-18 17:14:43 -0500
commitf14ef51ead823103d55923ca8003c4a533c4191e (patch)
tree163c18b915fab283ace449b3460931bfd7123fc4 /main/cdr.c
parent193a94a60fbee4d1920a806da883321a6dd6e056 (diff)
CDR: Alter destruction pattern for CDR chains.
CDRs form chains. When the root of the chain is destroyed, it then unreferences the next CDR in the chain. That CDR is destroyed, and it then unreferences the next CDR in the chain. This repeats until the end of the chain is reached. While this typically does not cause any sort of problems, it is possible in strange scenarios for the CDR chain to grow way longer than expected. In such a scenario, the destruction pattern can result in a stack overflow. This patch fixes the problem by switching from a recursive pattern to an iterative pattern for destruction. When the root CDR is destroyed, it is responsible for iterating over the rest of the CDRs and unreferencing each one. Other CDRs in the chain, since they are not the root, will simply destroy themselves and be done. This causes the stack depth not to increase. ASTERISK-26421 #close Reported by Andrew Nagy Change-Id: I3ca90c2b8051f3b7ead2e0e43f60d2c18fb204b8
Diffstat (limited to 'main/cdr.c')
-rw-r--r--main/cdr.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/main/cdr.c b/main/cdr.c
index e2f9b764c..baa17b967 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -698,6 +698,7 @@ struct cdr_object {
);
struct cdr_object *next; /*!< The next CDR object in the chain */
struct cdr_object *last; /*!< The last CDR object in the chain */
+ int is_root; /*!< True if this is the first CDR in the chain */
};
/*!
@@ -853,7 +854,22 @@ static void cdr_object_dtor(void *obj)
}
ast_string_field_free_memory(cdr);
- ao2_cleanup(cdr->next);
+ /* CDR destruction used to work by calling ao2_cleanup(next) and
+ * allowing the chain to destroy itself neatly. Unfortunately, for
+ * really long chains, this can result in a stack overflow. So now
+ * when the root CDR is destroyed, it is responsible for unreffing
+ * all CDRs in the chain
+ */
+ if (cdr->is_root) {
+ struct cdr_object *curr = cdr->next;
+ struct cdr_object *next;
+
+ while (curr) {
+ next = curr->next;
+ ao2_cleanup(curr);
+ curr = next;
+ }
+ }
}
/*!
@@ -2100,6 +2116,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription
if (!cdr) {
return;
}
+ cdr->is_root = 1;
ao2_link(active_cdrs_by_channel, cdr);
}