Refactor channel_get_cell_queue_entry_size() to avoid an unreachable line for test coverage, and fix a nasty lurking memory bug in channel_flush_some_cells_from_outgoing_queue()

This commit is contained in:
Andrea Shepard 2013-12-13 05:55:12 -08:00
parent 52cfaa84b7
commit dabf4c33e2

View File

@ -1741,25 +1741,28 @@ cell_queue_entry_new_var(var_cell_t *var_cell)
static size_t static size_t
channel_get_cell_queue_entry_size(channel_t *chan, cell_queue_entry_t *q) channel_get_cell_queue_entry_size(channel_t *chan, cell_queue_entry_t *q)
{ {
size_t rv = 0;
tor_assert(chan); tor_assert(chan);
tor_assert(q); tor_assert(q);
switch (q->type) { switch (q->type) {
case CELL_QUEUE_FIXED: case CELL_QUEUE_FIXED:
return get_cell_network_size(chan->wide_circ_ids); rv = get_cell_network_size(chan->wide_circ_ids);
break; break;
case CELL_QUEUE_VAR: case CELL_QUEUE_VAR:
tor_assert(q->u.var.var_cell); tor_assert(q->u.var.var_cell);
return get_var_cell_header_size(chan->wide_circ_ids) + rv = get_var_cell_header_size(chan->wide_circ_ids) +
q->u.var.var_cell->payload_len; q->u.var.var_cell->payload_len;
break; break;
case CELL_QUEUE_PACKED: case CELL_QUEUE_PACKED:
return get_cell_network_size(chan->wide_circ_ids); rv = get_cell_network_size(chan->wide_circ_ids);
break; break;
default: default:
tor_assert(1); tor_assert(1);
return 0;
} }
return rv;
} }
/** /**
@ -2309,6 +2312,7 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
ssize_t flushed = 0; ssize_t flushed = 0;
cell_queue_entry_t *q = NULL; cell_queue_entry_t *q = NULL;
size_t cell_size; size_t cell_size;
int free_q = 0, handed_off = 0;
tor_assert(chan); tor_assert(chan);
tor_assert(chan->write_cell); tor_assert(chan->write_cell);
@ -2322,6 +2326,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
if (chan->state == CHANNEL_STATE_OPEN) { if (chan->state == CHANNEL_STATE_OPEN) {
while ((unlimited || num_cells > flushed) && while ((unlimited || num_cells > flushed) &&
NULL != (q = TOR_SIMPLEQ_FIRST(&chan->outgoing_queue))) { NULL != (q = TOR_SIMPLEQ_FIRST(&chan->outgoing_queue))) {
free_q = 0;
handed_off = 0;
if (1) { if (1) {
/* Figure out how big it is for statistical purposes */ /* Figure out how big it is for statistical purposes */
@ -2339,8 +2345,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
channel_timestamp_xmit(chan); channel_timestamp_xmit(chan);
++(chan->n_cells_xmitted); ++(chan->n_cells_xmitted);
chan->n_bytes_xmitted += cell_size; chan->n_bytes_xmitted += cell_size;
cell_queue_entry_free(q, 1); free_q = 1;
q = NULL; handed_off = 1;
} }
/* Else couldn't write it; leave it on the queue */ /* Else couldn't write it; leave it on the queue */
} else { } else {
@ -2351,8 +2357,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
"(global ID " U64_FORMAT ").", "(global ID " U64_FORMAT ").",
chan, U64_PRINTF_ARG(chan->global_identifier)); chan, U64_PRINTF_ARG(chan->global_identifier));
/* Throw it away */ /* Throw it away */
cell_queue_entry_free(q, 0); free_q = 1;
q = NULL; handed_off = 0;
} }
break; break;
case CELL_QUEUE_PACKED: case CELL_QUEUE_PACKED:
@ -2363,8 +2369,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
channel_timestamp_xmit(chan); channel_timestamp_xmit(chan);
++(chan->n_cells_xmitted); ++(chan->n_cells_xmitted);
chan->n_bytes_xmitted += cell_size; chan->n_bytes_xmitted += cell_size;
cell_queue_entry_free(q, 1); free_q = 1;
q = NULL; handed_off = 1;
} }
/* Else couldn't write it; leave it on the queue */ /* Else couldn't write it; leave it on the queue */
} else { } else {
@ -2375,8 +2381,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
"(global ID " U64_FORMAT ").", "(global ID " U64_FORMAT ").",
chan, U64_PRINTF_ARG(chan->global_identifier)); chan, U64_PRINTF_ARG(chan->global_identifier));
/* Throw it away */ /* Throw it away */
cell_queue_entry_free(q, 0); free_q = 1;
q = NULL; handed_off = 0;
} }
break; break;
case CELL_QUEUE_VAR: case CELL_QUEUE_VAR:
@ -2387,8 +2393,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
channel_timestamp_xmit(chan); channel_timestamp_xmit(chan);
++(chan->n_cells_xmitted); ++(chan->n_cells_xmitted);
chan->n_bytes_xmitted += cell_size; chan->n_bytes_xmitted += cell_size;
cell_queue_entry_free(q, 1); free_q = 1;
q = NULL; handed_off = 1;
} }
/* Else couldn't write it; leave it on the queue */ /* Else couldn't write it; leave it on the queue */
} else { } else {
@ -2399,8 +2405,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
"(global ID " U64_FORMAT ").", "(global ID " U64_FORMAT ").",
chan, U64_PRINTF_ARG(chan->global_identifier)); chan, U64_PRINTF_ARG(chan->global_identifier));
/* Throw it away */ /* Throw it away */
cell_queue_entry_free(q, 0); free_q = 1;
q = NULL; handed_off = 0;
} }
break; break;
default: default:
@ -2410,12 +2416,16 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
"(global ID " U64_FORMAT "; ignoring it." "(global ID " U64_FORMAT "; ignoring it."
" Someone should fix this.", " Someone should fix this.",
q->type, chan, U64_PRINTF_ARG(chan->global_identifier)); q->type, chan, U64_PRINTF_ARG(chan->global_identifier));
cell_queue_entry_free(q, 0); free_q = 1;
q = NULL; handed_off = 0;
} }
/* if q got NULLed out, we used it and should remove the queue entry */ /*
if (!q) { * if free_q is set, we used it and should remove the queue entry;
* we have to do the free down here so TOR_SIMPLEQ_REMOVE_HEAD isn't
* accessing freed memory
*/
if (free_q) {
TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next); TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next);
/* /*
* ...and we handed a cell off to the lower layer, so we should * ...and we handed a cell off to the lower layer, so we should
@ -2428,6 +2438,9 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
channel_assert_counter_consistency(); channel_assert_counter_consistency();
/* Update the channel's queue size too */ /* Update the channel's queue size too */
chan->bytes_in_queue -= cell_size; chan->bytes_in_queue -= cell_size;
/* Finally, free q */
cell_queue_entry_free(q, handed_off);
q = NULL;
} }
/* No cell removed from list, so we can't go on any further */ /* No cell removed from list, so we can't go on any further */
else break; else break;