Преглед изворни кода

http2: fix memory leak when retry.

Nick Peng пре 2 недеља
родитељ
комит
20a59e69e9
3 измењених фајлова са 43 додато и 18 уклоњено
  1. 6 6
      src/dns_client/client_http2.c
  2. 1 7
      src/dns_server/server_http2.c
  3. 36 5
      src/http_parse/http2.c

+ 6 - 6
src/dns_client/client_http2.c

@@ -125,12 +125,12 @@ static void _dns_client_release_stream_on_error(struct dns_server_info *server_i
 /* Helper function to flush pending HTTP/2 writes */
 static void _dns_client_flush_http2_writes(struct http2_ctx *http2_ctx)
 {
-	struct http2_poll_item poll_items[1];
-	int poll_count = 0;
 	int loop = 0;
 
 	while (http2_ctx_want_write(http2_ctx) && loop++ < 10) {
-		http2_ctx_poll(http2_ctx, poll_items, 1, &poll_count);
+		if (http2_ctx_poll(http2_ctx, NULL, 0, NULL) < 0) {
+			break;
+		}
 	}
 }
 
@@ -307,11 +307,11 @@ int _dns_client_send_http2(struct dns_server_info *server_info, struct dns_query
 	pthread_mutex_unlock(&server_info->lock);
 
 	/* Flush data immediately */
-	struct http2_poll_item poll_items[1];
-	int poll_count = 0;
 	int loop = 0;
 	while (http2_ctx_want_write(http2_ctx) && loop++ < 10) {
-		http2_ctx_poll(http2_ctx, poll_items, 1, &poll_count);
+		if (http2_ctx_poll(http2_ctx, NULL, 0, NULL) < 0) {
+			break;
+		}
 	}
 
 	/* Check if there's pending write data, if so add EPOLLOUT event */

+ 1 - 7
src/dns_server/server_http2.c

@@ -236,17 +236,11 @@ int _dns_server_process_http2(struct dns_server_conn_tls_client *tls_client, str
 
 	/* Handle EPOLLOUT - flush pending writes */
 	if (event->events & EPOLLOUT) {
-		struct http2_poll_item poll_items[1];
-		int poll_count = 0;
 		int loop = 0;
 		while (http2_ctx_want_write(ctx) && loop++ < 10) {
-			ret = http2_ctx_poll(ctx, poll_items, 1, &poll_count);
-			if (ret < 0) {
+			if (http2_ctx_poll(ctx, NULL, 0, NULL) < 0) {
 				break;
 			}
-			if (poll_count > 0 && poll_items[0].stream) {
-				http2_stream_put(poll_items[0].stream);
-			}
 		}
 	}
 

+ 36 - 5
src/http_parse/http2.c

@@ -1548,9 +1548,17 @@ static int _http2_ctx_poll(struct http2_ctx *ctx, struct http2_poll_item *items,
 						   int check_writable)
 {
 	pthread_mutex_lock(&ctx->mutex);
+	if (ret_count) {
+		*ret_count = 0;
+	}
 
 	int ret = _http2_ctx_io_process(ctx);
 
+	if (items == NULL || max_items <= 0) {
+		pthread_mutex_unlock(&ctx->mutex);
+		return ret;
+	}
+
 	/* Note: We continue even if http2_process_frames returns error (like EOF),
 	   because we might have received data that made streams readable.
 	   We will return the error at the end if no streams are ready. */
@@ -1560,14 +1568,29 @@ static int _http2_ctx_poll(struct http2_ctx *ctx, struct http2_poll_item *items,
 	_http2_ctx_check_new_streams(ctx, items, max_items, &count);
 	_http2_ctx_collect_ready_streams(ctx, items, max_items, &count, check_writable);
 
-	*ret_count = count;
-	pthread_mutex_unlock(&ctx->mutex);
+	if (ret_count) {
+		*ret_count = count;
+	}
 
-	/* If we have an error, return it even if there are ready items */
+	/* If we have an error, return it even if there ready items.
+	   BUT we must release references collected in items before returning. */
 	if (ret < 0 && ret != HTTP2_ERR_EAGAIN) {
+		int i;
+		for (i = 0; i < count; i++) {
+			if (items[i].stream) {
+				http2_stream_put(items[i].stream);
+				items[i].stream = NULL;
+			}
+		}
+		if (ret_count) {
+			*ret_count = 0;
+		}
+		pthread_mutex_unlock(&ctx->mutex);
 		return ret;
 	}
 
+	pthread_mutex_unlock(&ctx->mutex);
+
 	if (count > 0) {
 		return 0;
 	}
@@ -1581,7 +1604,11 @@ static int _http2_ctx_poll(struct http2_ctx *ctx, struct http2_poll_item *items,
 
 int http2_ctx_poll(struct http2_ctx *ctx, struct http2_poll_item *items, int max_items, int *ret_count)
 {
-	if (!ctx || !items || !ret_count || max_items <= 0) {
+	if (!ctx) {
+		return -1;
+	}
+
+	if (items != NULL && (max_items <= 0 || !ret_count)) {
 		return -1;
 	}
 	return _http2_ctx_poll(ctx, items, max_items, ret_count, 1);
@@ -1589,7 +1616,11 @@ int http2_ctx_poll(struct http2_ctx *ctx, struct http2_poll_item *items, int max
 
 int http2_ctx_poll_readable(struct http2_ctx *ctx, struct http2_poll_item *items, int max_items, int *ret_count)
 {
-	if (!ctx || !items || !ret_count || max_items <= 0) {
+	if (!ctx) {
+		return -1;
+	}
+
+	if (items != NULL && (max_items <= 0 || !ret_count)) {
 		return -1;
 	}
 	return _http2_ctx_poll(ctx, items, max_items, ret_count, 0);