|
@@ -2652,6 +2652,11 @@ channel_process_cells(channel_t *chan)
|
|
|
/*
|
|
|
* Process cells until we're done or find one we have no current handler
|
|
|
* for.
|
|
|
+ *
|
|
|
+ * We must free the cells here after calling the handler, since custody
|
|
|
+ * of the buffer was given to the channel layer when they were queued;
|
|
|
+ * see comments on memory management in channel_queue_cell() and in
|
|
|
+ * channel_queue_var_cell() below.
|
|
|
*/
|
|
|
while (NULL != (q = TOR_SIMPLEQ_FIRST(&chan->incoming_queue))) {
|
|
|
tor_assert(q);
|
|
@@ -2669,6 +2674,7 @@ channel_process_cells(channel_t *chan)
|
|
|
q->u.fixed.cell, chan,
|
|
|
U64_PRINTF_ARG(chan->global_identifier));
|
|
|
chan->cell_handler(chan, q->u.fixed.cell);
|
|
|
+ tor_free(q->u.fixed.cell);
|
|
|
tor_free(q);
|
|
|
} else if (q->type == CELL_QUEUE_VAR &&
|
|
|
chan->var_cell_handler) {
|
|
@@ -2681,6 +2687,7 @@ channel_process_cells(channel_t *chan)
|
|
|
q->u.var.var_cell, chan,
|
|
|
U64_PRINTF_ARG(chan->global_identifier));
|
|
|
chan->var_cell_handler(chan, q->u.var.var_cell);
|
|
|
+ tor_free(q->u.var.var_cell);
|
|
|
tor_free(q);
|
|
|
} else {
|
|
|
/* Can't handle this one */
|
|
@@ -2701,6 +2708,7 @@ channel_queue_cell(channel_t *chan, cell_t *cell)
|
|
|
{
|
|
|
int need_to_queue = 0;
|
|
|
cell_queue_entry_t *q;
|
|
|
+ cell_t *cell_copy = NULL;
|
|
|
|
|
|
tor_assert(chan);
|
|
|
tor_assert(cell);
|
|
@@ -2728,8 +2736,19 @@ channel_queue_cell(channel_t *chan, cell_t *cell)
|
|
|
U64_PRINTF_ARG(chan->global_identifier));
|
|
|
chan->cell_handler(chan, cell);
|
|
|
} else {
|
|
|
- /* Otherwise queue it and then process the queue if possible. */
|
|
|
- q = cell_queue_entry_new_fixed(cell);
|
|
|
+ /*
|
|
|
+ * Otherwise queue it and then process the queue if possible.
|
|
|
+ *
|
|
|
+ * We queue a copy, not the original pointer - it might have been on the
|
|
|
+ * stack in connection_or_process_cells_from_inbuf() (or another caller
|
|
|
+ * if we ever have a subclass other than channel_tls_t), or be freed
|
|
|
+ * there after we return. This is the uncommon case; the non-copying
|
|
|
+ * fast path occurs in the if (!need_to_queue) case above when the
|
|
|
+ * upper layer has installed cell handlers.
|
|
|
+ */
|
|
|
+ cell_copy = tor_malloc_zero(sizeof(cell_t));
|
|
|
+ memcpy(cell_copy, cell, sizeof(cell_t));
|
|
|
+ q = cell_queue_entry_new_fixed(cell_copy);
|
|
|
log_debug(LD_CHANNEL,
|
|
|
"Queueing incoming cell_t %p for channel %p "
|
|
|
"(global ID " U64_FORMAT ")",
|
|
@@ -2755,6 +2774,7 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
|
|
|
{
|
|
|
int need_to_queue = 0;
|
|
|
cell_queue_entry_t *q;
|
|
|
+ var_cell_t *cell_copy = NULL;
|
|
|
|
|
|
tor_assert(chan);
|
|
|
tor_assert(var_cell);
|
|
@@ -2783,8 +2803,18 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
|
|
|
U64_PRINTF_ARG(chan->global_identifier));
|
|
|
chan->var_cell_handler(chan, var_cell);
|
|
|
} else {
|
|
|
- /* Otherwise queue it and then process the queue if possible. */
|
|
|
- q = cell_queue_entry_new_var(var_cell);
|
|
|
+ /*
|
|
|
+ * Otherwise queue it and then process the queue if possible.
|
|
|
+ *
|
|
|
+ * We queue a copy, not the original pointer - it might have been on the
|
|
|
+ * stack in connection_or_process_cells_from_inbuf() (or another caller
|
|
|
+ * if we ever have a subclass other than channel_tls_t), or be freed
|
|
|
+ * there after we return. This is the uncommon case; the non-copying
|
|
|
+ * fast path occurs in the if (!need_to_queue) case above when the
|
|
|
+ * upper layer has installed cell handlers.
|
|
|
+ */
|
|
|
+ cell_copy = var_cell_copy(var_cell);
|
|
|
+ q = cell_queue_entry_new_var(cell_copy);
|
|
|
log_debug(LD_CHANNEL,
|
|
|
"Queueing incoming var_cell_t %p for channel %p "
|
|
|
"(global ID " U64_FORMAT ")",
|