From: Timo Sirainen Date: Thu, 26 Mar 2026 09:45:24 +0000 (+0200) Subject: lib-master: Fix crash when reaching client_limit with restart_request_count>1 and... X-Git-Tag: 2.4.4~126 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=de906cffabb7a4a2dbee27d75ed7f40d22cf61fa;p=thirdparty%2Fdovecot%2Fcore.git lib-master: Fix crash when reaching client_limit with restart_request_count>1 and client_limit>1 Fixes: Panic: file master-service.c: line 1909 (master_service_listen): assertion failed: (service->master_status.available_count > 0) --- diff --git a/src/lib-master/master-service-private.h b/src/lib-master/master-service-private.h index b139990ecf..7385ab3534 100644 --- a/src/lib-master/master-service-private.h +++ b/src/lib-master/master-service-private.h @@ -48,7 +48,10 @@ struct master_service { unsigned int socket_count; struct io *io_status_write, *io_status_error; + /* Number of requests left before process is stopped. */ unsigned int restart_request_count_left; + /* Starts as service's client_limit, but never more than + restart_request_count_left. */ unsigned int total_available_count; unsigned int process_limit; unsigned int process_min_avail; diff --git a/src/lib-master/master-service.c b/src/lib-master/master-service.c index faf0167b63..73906922a7 100644 --- a/src/lib-master/master-service.c +++ b/src/lib-master/master-service.c @@ -1455,8 +1455,9 @@ static bool master_service_want_listener(struct master_service *service) /* more concurrent clients can still be added */ return TRUE; } - if (service->restart_request_count_left == 1) { - /* after handling this client, the whole process will stop. */ + if (service->restart_request_count_left == service->total_available_count) { + /* after handling the existing clients, + the whole process will stop. */ return FALSE; } if (service->avail_overflow_callback != NULL) { @@ -1484,7 +1485,7 @@ void master_service_client_connection_handled(struct master_service *service, if (!master_service_want_listener(service)) { i_assert(service->listeners != NULL); master_service_io_listeners_remove(service); - if (service->restart_request_count_left == 1 && + if (service->restart_request_count_left == service->total_available_count && service->avail_overflow_callback == NULL) { /* we're not going to accept any more connections after this. go ahead and close the connection early. don't @@ -1523,6 +1524,8 @@ void master_service_client_connection_destroyed(struct master_service *service) i_assert(service->restart_request_count_left > 0); if (service->restart_request_count_left == service->total_available_count) { + /* There may or may not be available clients, but we no longer + increse them. */ service->total_available_count--; service->restart_request_count_left--; } else { @@ -1805,6 +1808,12 @@ static bool master_service_full(struct master_service *service) /* This process can still create multiple concurrent clients if we just kill some of the existing ones. Do it immediately. */ + if (service->restart_request_count_left == service->total_available_count) { + /* restart_request_count is reached - killing existing + processes won't increase the number of available + clients anymore. */ + return TRUE; + } return !service->avail_overflow_callback(TRUE, &created); }