Eliminate the possibility of nghttp2_stream.cycle overflow

This commit is contained in:
Tatsuhiro Tsujikawa 2016-02-18 23:56:29 +09:00
parent f0b5a8db8c
commit b7159f80b2
2 changed files with 33 additions and 13 deletions

View File

@ -30,14 +30,32 @@
#include "nghttp2_session.h" #include "nghttp2_session.h"
#include "nghttp2_helper.h" #include "nghttp2_helper.h"
/* Maximum distance between any two stream's cycle in the same
prirority queue. Imagine stream A's cycle is A, and stream B's
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
may get overflow. Because of how we calculate the next cycle
value, if B - A is less than or equals to
NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other
words, B is really greater than or equal to A. Otherwise, A is a
result of overflow, and it is actually A > B if we consider that
fact. */
#define NGHTTP2_MAX_CYCLE_DISTANCE (16384 * 256 + 255)
static int stream_less(const void *lhsx, const void *rhsx) { static int stream_less(const void *lhsx, const void *rhsx) {
const nghttp2_stream *lhs, *rhs; const nghttp2_stream *lhs, *rhs;
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry); lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry); rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
return lhs->cycle < rhs->cycle || if (lhs->cycle == rhs->cycle) {
(lhs->cycle == rhs->cycle && lhs->seq < rhs->seq); return lhs->seq < rhs->seq;
}
if (lhs->cycle < rhs->cycle) {
return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
}
return lhs->cycle - rhs->cycle > NGHTTP2_MAX_CYCLE_DISTANCE;
} }
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
@ -116,14 +134,14 @@ static int stream_subtree_active(nghttp2_stream *stream) {
/* /*
* Returns next cycle for |stream|. * Returns next cycle for |stream|.
*/ */
static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) { static void stream_next_cycle(nghttp2_stream *stream, uint32_t last_cycle) {
size_t penalty; uint32_t penalty;
penalty = penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
stream->last_writelen * NGHTTP2_MAX_WEIGHT + stream->pending_penalty; stream->pending_penalty;
stream->cycle = last_cycle + penalty / (uint32_t)stream->weight; stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight); stream->pending_penalty = penalty % (uint32_t)stream->weight;
} }
static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) { static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
@ -229,9 +247,9 @@ void nghttp2_stream_reschedule(nghttp2_stream *stream) {
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) { void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
nghttp2_stream *dep_stream; nghttp2_stream *dep_stream;
uint64_t last_cycle; uint32_t last_cycle;
int32_t old_weight; int32_t old_weight;
size_t wlen_penalty; uint32_t wlen_penalty;
if (stream->weight == weight) { if (stream->weight == weight) {
return; return;
@ -254,7 +272,7 @@ void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
wlen_penalty = stream->last_writelen * NGHTTP2_MAX_WEIGHT; wlen_penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
/* Compute old stream->pending_penalty we used to calculate /* Compute old stream->pending_penalty we used to calculate
stream->cycle */ stream->cycle */
@ -270,7 +288,9 @@ void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
place */ place */
stream_next_cycle(stream, last_cycle); stream_next_cycle(stream, last_cycle);
if (stream->cycle < dep_stream->descendant_last_cycle) { if (stream->cycle < dep_stream->descendant_last_cycle &&
(dep_stream->descendant_last_cycle - stream->cycle) <=
NGHTTP2_MAX_CYCLE_DISTANCE) {
stream->cycle = dep_stream->descendant_last_cycle; stream->cycle = dep_stream->descendant_last_cycle;
} }

View File

@ -147,9 +147,9 @@ struct nghttp2_stream {
/* Received body so far */ /* Received body so far */
int64_t recv_content_length; int64_t recv_content_length;
/* Base last_cycle for direct descendent streams. */ /* Base last_cycle for direct descendent streams. */
uint64_t descendant_last_cycle; uint32_t descendant_last_cycle;
/* Next scheduled time to sent item */ /* Next scheduled time to sent item */
uint64_t cycle; uint32_t cycle;
/* Next seq used for direct descendant streams */ /* Next seq used for direct descendant streams */
uint64_t descendant_next_seq; uint64_t descendant_next_seq;
/* Secondary key for prioritization to break a tie for cycle. This /* Secondary key for prioritization to break a tie for cycle. This